diff --git a/zone/client.cpp b/zone/client.cpp index 8ae081fee..a1b89a064 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -13144,3 +13144,13 @@ void Client::BroadcastPositionUpdate() entity_list.QueueCloseClients(this, &outapp, true, zone->GetMaxUpdateRange()); } + +void Client::SetVisibility(Mob* mob, bool visible) { + mob->SendAppearancePacket( + AppearanceType::Invisibility, + visible ? m_invisibility_state : 3001, // reset back to original visibility state when visible + false, + true, + this + ); +} diff --git a/zone/client.h b/zone/client.h index b45651451..53840da54 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1828,6 +1828,7 @@ public: void DoEvolveTransferXP(const EQApplicationPacket* app); void SendEvolveXPTransferWindow(); void SendEvolveTransferResults(const EQ::ItemInstance &inst_from, const EQ::ItemInstance &inst_to, const EQ::ItemInstance &inst_from_new, const EQ::ItemInstance &inst_to_new, const uint32 compatibility, const uint32 max_transfer_level); + void SetVisibility(Mob* mob, bool visible); protected: friend class Mob; diff --git a/zone/entity.cpp b/zone/entity.cpp index 9db6343f6..0518d78a5 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -697,7 +697,6 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue) mob_list.emplace(std::pair(npc->GetID(), npc)); entity_list.ScanCloseMobs(npc); - entity_list.UpdateVisibility(npc); if (parse->HasQuestSub(npc->GetNPCTypeID(), EVENT_SPAWN)) { parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); @@ -2976,15 +2975,14 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob) } BenchTimer g_vis_bench_timer; +#define STATE_HIDDEN -1 +#define STATE_VISIBLE 1 -void EntityList::UpdateVisibility(Mob *scanning_mob) -{ +void EntityList::UpdateVisibility(Mob *scanning_mob) { if (!scanning_mob) { return; } - ScanCloseMobs(scanning_mob); - g_vis_bench_timer.reset(); // Ensure sufficient capacity in the visibility map @@ -2992,94 +2990,31 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) scanning_mob->m_can_see_mob.reserve(scanning_mob->m_close_mobs.size()); } - // Update visibility for all mobs in the close list of `scanning_mob` - for (auto &e : scanning_mob->m_close_mobs) { + // Iterate through all mobs in the zone + for (auto &e: mob_list) { auto mob = e.second; - if (!mob) continue; + if (!mob || mob == scanning_mob) { continue; } - int mob_id = mob->GetID(); + // Update scanning_mob's visibility of mob + auto it_scanning_visible = scanning_mob->m_can_see_mob.find(mob->GetID()); + int8_t scanning_visibility = (it_scanning_visible != scanning_mob->m_can_see_mob.end()) + ? it_scanning_visible->second : 0; - // Update visibility for `scanning_mob` to `mob` - auto [it_scanning_visible, inserted_scanning_visible] = scanning_mob->m_can_see_mob.try_emplace(mob_id, false); - bool scanning_last_known_visible = it_scanning_visible->second; - - if (!scanning_last_known_visible) { - if (mob->IsClient()) { - scanning_mob->SendAppearancePacket( - AppearanceType::Invisibility, - 0, - false, - true, - mob->CastToClient() - ); + if (scanning_mob->CalculateDistance(mob) <= zone->GetMaxUpdateRange()) { + if (scanning_visibility != STATE_VISIBLE) { // Become visible + if (scanning_mob->IsClient()) { + scanning_mob->CastToClient()->SetVisibility(mob, true); + } + scanning_mob->m_can_see_mob[mob->GetID()] = STATE_VISIBLE; } - - it_scanning_visible->second = true; - LogVisibilityDetail("Setting scanning_mob [{}] visible to mob [{}]", scanning_mob->GetCleanName(), mob->GetCleanName()); } - - // Now update the visibility for `mob` to `scanning_mob` - auto [it_mob_visible, inserted_mob_visible] = mob->m_can_see_mob.try_emplace(scanning_mob->GetID(), false); - bool mob_last_known_visible = it_mob_visible->second; - - if (!mob_last_known_visible) { - if (scanning_mob->IsClient()) { - mob->SendAppearancePacket( - AppearanceType::Invisibility, - 0, - false, - true, - scanning_mob->CastToClient() - ); + else { + if (scanning_visibility != STATE_HIDDEN) { // Become invisible + if (scanning_mob->IsClient()) { + scanning_mob->CastToClient()->SetVisibility(mob, false); + } + scanning_mob->m_can_see_mob[mob->GetID()] = STATE_HIDDEN; } - - it_mob_visible->second = true; - LogVisibilityDetail("Setting mob [{}] visible to scanning_mob [{}]", mob->GetCleanName(), scanning_mob->GetCleanName()); - } - } - - // Check all other mobs to make invisible if they are no longer close - for (auto &e : mob_list) { - auto mob = e.second; - if (!mob) continue; - - int mob_id = mob->GetID(); - bool is_on_close_list = mob->m_close_mobs.find(scanning_mob->GetID()) != mob->m_close_mobs.end(); - - // Update scanning_mob's view of mob visibility - auto [it, inserted] = scanning_mob->m_can_see_mob.try_emplace(mob_id, false); - bool last_known_visible = it->second; - - if (!is_on_close_list && last_known_visible) { - if (mob->IsClient()) { - scanning_mob->SendAppearancePacket( - AppearanceType::Invisibility, - 3001, - false, - true, - mob->CastToClient() - ); - } - - it->second = false; - LogVisibilityDetail("Setting mob [{}] invisible to scanning_mob [{}]", mob->GetCleanName(), scanning_mob->GetCleanName()); - } - - // Inverse: Update mob's view of scanning_mob visibility - auto it_mob = mob->m_can_see_mob.find(scanning_mob->GetID()); - if (it_mob != mob->m_can_see_mob.end() && !scanning_mob->m_close_mobs.count(mob_id) && it_mob->second) { - if (scanning_mob->IsClient()) { - mob->SendAppearancePacket( - AppearanceType::Invisibility, - 3001, - false, - true, - scanning_mob->CastToClient() - ); - } - - it_mob->second = false; - LogVisibilityDetail("Setting scanning_mob [{}] invisible to mob [{}]", scanning_mob->GetCleanName(), mob->GetCleanName()); } } diff --git a/zone/mob.cpp b/zone/mob.cpp index 19306f51d..b88b1c3e5 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4127,6 +4127,10 @@ void Mob::SendAppearancePacket( auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); auto* a = (SpawnAppearance_Struct*)outapp->pBuffer; + if (type == AppearanceType::Invisibility) { + m_invisibility_state = value; + } + a->spawn_id = GetID(); a->type = type; a->parameter = value; diff --git a/zone/mob.h b/zone/mob.h index a3afe5c6a..353307d8b 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -202,7 +202,7 @@ public: void DisplayInfo(Mob *mob); std::unordered_map m_close_mobs; - std::unordered_map m_can_see_mob; + std::unordered_map m_can_see_mob; Timer m_scan_close_mobs_timer; Timer m_see_close_mobs_timer; Timer m_mob_check_moving_timer; @@ -1909,6 +1909,8 @@ protected: MobMovementManager *mMovementManager; + bool m_invisibility_state = 0; + private: Mob* target; EQ::InventoryProfile m_inv;