From d46b8d6471f0dc7e3a6327f523643a111c0f84da Mon Sep 17 00:00:00 2001
From: Zach Fox <fox@highfidelity.io>
Date: Tue, 11 Dec 2018 14:52:11 -0800
Subject: [PATCH] Fix MS17811: Prevent frozen avatars in certain ignore cases

---
 .../src/avatars/AvatarMixerClientData.h           |  3 +++
 .../src/avatars/AvatarMixerSlave.cpp              | 15 +++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h
index afbc68378a..8a86af384a 100644
--- a/assignment-client/src/avatars/AvatarMixerClientData.h
+++ b/assignment-client/src/avatars/AvatarMixerClientData.h
@@ -110,6 +110,8 @@ public:
     void setBaseDisplayName(const QString& baseDisplayName) { _baseDisplayName = baseDisplayName; }
     bool getRequestsDomainListData() { return _requestsDomainListData; }
     void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; }
+    bool getPrevRequestsDomainListData() { return _prevRequestsDomainListData; }
+    void setPrevRequestsDomainListData(bool requesting) { _prevRequestsDomainListData = requesting; }
 
     const ConicalViewFrustums& getViewFrustums() const { return _currentViewFrustums; }
 
@@ -176,6 +178,7 @@ private:
     int _recentOtherAvatarsOutOfView { 0 };
     QString _baseDisplayName{}; // The santized key used in determinging unique sessionDisplayName, so that we can remove from dictionary.
     bool _requestsDomainListData { false };
+    bool _prevRequestsDomainListData{ false };
 
     AvatarTraits::TraitVersions _lastReceivedTraitVersions;
     TraitsCheckTimestamp _lastReceivedTraitsChange;
diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp
index a037f24345..5df7758a0c 100644
--- a/assignment-client/src/avatars/AvatarMixerSlave.cpp
+++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp
@@ -268,6 +268,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
     // When this is true, the AvatarMixer will send Avatar data to a client
     // about avatars they've ignored or that are out of view
     bool PALIsOpen = nodeData->getRequestsDomainListData();
+    bool PALWasOpen = nodeData->getPrevRequestsDomainListData();
 
     // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
     bool getsAnyIgnored = PALIsOpen && destinationNode->getCanKick();
@@ -392,6 +393,20 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
 
             sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
         }
+        
+        // If Avatar A's PAL WAS open but is no longer open, AND
+        // Avatar A should be ignoring Avatar B...
+        if (PALWasOpen && !PALIsOpen && shouldIgnore) {
+            // ...send a Kill Packet to Node A, instructing Node A to kill Avatar B,
+            // then have Node A cleanup the killed Node B.
+            auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
+            packet->write(avatarNode->getUUID().toRfc4122());
+            packet->writePrimitive(KillAvatarReason::AvatarIgnored);
+            nodeList->sendPacket(std::move(packet), *destinationNode);
+            nodeData->cleanupKilledNode(avatarNode->getUUID(), avatarNode->getLocalID());
+        }
+
+        nodeData->setPrevRequestsDomainListData(PALIsOpen);
     }
 
     // loop through our sorted avatars and allocate our bandwidth to them accordingly