From 0348cb6b8eeca9cde2ff6b33cce5773e5db6cb9c Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Mon, 6 Feb 2023 17:23:29 -0600 Subject: [PATCH] [Fix] Fix NPC ghosting at safe coordinates (#2823) * [Fix] Fix NPC ghosting at safe coordinates * Tweak order * Handle another case --- zone/client.h | 1 + zone/client_packet.cpp | 17 +++++++++++++++++ zone/entity.cpp | 6 +++++- zone/npc.cpp | 11 +++++++++++ zone/npc.h | 2 ++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/zone/client.h b/zone/client.h index 66053dfaa..807069d9b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -2083,6 +2083,7 @@ private: bool m_bot_precombat; bool CanTradeFVNoDropItem(); + void SendMobPositions(); }; #endif diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c1539de21..e4ca1a55d 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -778,6 +778,12 @@ void Client::CompleteConnect() parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); + // the way that the client deals with positions during the initial spawn struct + // is subtly different from how it deals with getting a position update + // if a mob is slightly in the wall or slightly clipping a floor they will be + // sent to a succor point + SendMobPositions(); + SetLastPositionBeforeBulkUpdate(GetPosition()); /* This sub event is for if a player logs in for the first time since entering world. */ @@ -15730,3 +15736,14 @@ bool Client::CanTradeFVNoDropItem() return false; } + +void Client::SendMobPositions() +{ + auto p = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto *s = (PlayerPositionUpdateServer_Struct *) p->pBuffer; + for (auto &m: entity_list.GetMobList()) { + m.second->MakeSpawnUpdate(s); + QueuePacket(p, false); + } + safe_delete(p); +} diff --git a/zone/entity.cpp b/zone/entity.cpp index af1d4e880..c141d392f 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -718,6 +718,8 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue) } } + npc->SendPositionToClients(); + entity_list.ScanCloseMobs(npc->close_mobs, npc, true); npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr); @@ -844,8 +846,10 @@ void EntityList::CheckSpawnQueue() NPC *pnpc = it->second; pnpc->SendArmorAppearance(); pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false); - if (!pnpc->IsTargetable()) + if (!pnpc->IsTargetable()) { pnpc->SendTargetable(false); + } + pnpc->SendPositionToClients(); } safe_delete(outapp); iterator.RemoveCurrent(); diff --git a/zone/npc.cpp b/zone/npc.cpp index 50ef41376..153233979 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -3783,3 +3783,14 @@ int NPC::GetRolledItemCount(uint32 item_id) return rolled_count; } + +void NPC::SendPositionToClients() +{ + auto p = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto *s = (PlayerPositionUpdateServer_Struct *) p->pBuffer; + for (auto &c: entity_list.GetClientList()) { + MakeSpawnUpdate(s); + c.second->QueuePacket(p, false); + } + safe_delete(p); +} diff --git a/zone/npc.h b/zone/npc.h index fc3eb0f0a..418927d35 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -536,6 +536,8 @@ public: void RecalculateSkills(); void ReloadSpells(); + void SendPositionToClients(); + static LootDropEntries_Struct NewLootDropEntry(); protected: