diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 4d4188554..66f4d0089 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -143,6 +143,7 @@ namespace Logs { Corpses, XTargets, EvolveItem, + Visibility, MaxCategoryID /* Don't Remove this */ }; @@ -244,7 +245,8 @@ namespace Logs { "EqTime", "Corpses", "XTargets", - "EvolveItem" + "EvolveItem", + "Visibility" }; } diff --git a/common/eqemu_logsys_log_aliases.h b/common/eqemu_logsys_log_aliases.h index 638657f64..280908d3e 100644 --- a/common/eqemu_logsys_log_aliases.h +++ b/common/eqemu_logsys_log_aliases.h @@ -854,6 +854,16 @@ OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ } while (0) +#define LogVisibility(message, ...) do {\ + if (LogSys.IsLogEnabled(Logs::General, Logs::Visibility))\ + OutF(LogSys, Logs::General, Logs::Visibility, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + +#define LogVisibilityDetail(message, ...) do {\ + if (LogSys.IsLogEnabled(Logs::Detail, Logs::Visibility))\ + OutF(LogSys, Logs::Detail, Logs::Visibility, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ +} while (0) + #define Log(debug_level, log_category, message, ...) do {\ if (LogSys.IsLogEnabled(debug_level, log_category))\ LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ diff --git a/common/timer.h b/common/timer.h index 6678be952..599f7b2f2 100644 --- a/common/timer.h +++ b/common/timer.h @@ -86,6 +86,9 @@ struct BenchTimer void reset() { start_time = clock::now(); } // this is seconds double elapsed() { return std::chrono::duration (clock::now() - start_time).count(); } + std::chrono::milliseconds::rep elapsedMilliseconds() { return std::chrono::duration_cast(clock::now() - start_time).count(); } + std::chrono::microseconds::rep elapsedMicroseconds() { return std::chrono::duration_cast(clock::now() - start_time).count(); } + std::chrono::nanoseconds::rep elapsedNanoseconds() { return std::chrono::duration_cast(clock::now() - start_time).count(); } private: std::chrono::time_point start_time; }; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 38c3e299d..8ad5f2c02 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4956,6 +4956,20 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { CheckScanCloseMobsMovingTimer(); } + // see_close + if (moving) { + if (m_see_close_mobs_timer.GetRemainingTime() > 1000) { + m_see_close_mobs_timer.Disable(); + m_see_close_mobs_timer.Start(1000); + m_see_close_mobs_timer.Trigger(); + } + } + else if (m_see_close_mobs_timer.GetDuration() == 1000) { + m_see_close_mobs_timer.Disable(); + m_see_close_mobs_timer.Start(60000); + m_see_close_mobs_timer.Trigger(); + } + CheckSendBulkClientPositionUpdate(); int32 new_animation = ppu->animation; diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 2894fb354..0e2d5ff23 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -285,6 +285,10 @@ bool Client::Process() { entity_list.ScanCloseMobs(this); } + if (m_see_close_mobs_timer.Check()) { + entity_list.UpdateVisibility(this); + } + if (RuleB(Inventory, LazyLoadBank)) { // poll once a second to see if we are close to a banker and we haven't loaded the bank yet if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) { diff --git a/zone/entity.cpp b/zone/entity.cpp index f58d1ce7e..83b4f2556 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2869,6 +2869,7 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob) ); it->second->m_close_mobs.erase(entity_id); + it->second->m_can_see_mob.erase(entity_id); ++it; } @@ -2922,6 +2923,9 @@ void EntityList::RemoveAuraFromMobs(Mob *aura) // All of the above makes a tremendous impact on the bottom line of cpu cycle performance because we run an order of magnitude // less checks by focusing our hot path logic down to a very small subset of relevant entities instead of looping an entire // entity list (zone wide) + +BenchTimer g_scan_bench_timer; + void EntityList::ScanCloseMobs(Mob *scanning_mob) { if (!scanning_mob) { @@ -2932,6 +2936,8 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob) return; } + g_scan_bench_timer.reset(); + float scan_range = zone->GetMaxUpdateRange(); // Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved. @@ -2959,22 +2965,27 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob) } } - UpdateVisibility(scanning_mob); - LogAIScanClose( - "[{}] Scanning close list > list_size [{}] moving [{}]", + "[{}] Scanning close list > list_size [{}] moving [{}] elapsed [{}] us", scanning_mob->GetCleanName(), scanning_mob->m_close_mobs.size(), - scanning_mob->IsMoving() ? "true" : "false" + scanning_mob->IsMoving() ? "true" : "false", + g_scan_bench_timer.elapsedMicroseconds() ); } +BenchTimer g_vis_bench_timer; + void EntityList::UpdateVisibility(Mob *scanning_mob) { if (!scanning_mob || !scanning_mob->IsClient()) { return; } + ScanCloseMobs(scanning_mob); + + g_vis_bench_timer.reset(); + // Ensure sufficient capacity in the visibility map if (scanning_mob->m_can_see_mob.bucket_count() < scanning_mob->m_close_mobs.size()) { scanning_mob->m_can_see_mob.reserve(scanning_mob->m_close_mobs.size()); @@ -2991,7 +3002,7 @@ void EntityList::UpdateVisibility(Mob *scanning_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 (!scanning_last_known_visible && mob->IsClient()) { scanning_mob->SendAppearancePacket( AppearanceType::Invisibility, 0, @@ -3000,14 +3011,14 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) mob->CastToClient() ); it_scanning_visible->second = true; - scanning_mob->Shout(fmt::format("Setting scanning_mob visible to mob [{}]", mob->GetCleanName()).c_str()); + 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 (!mob_last_known_visible && scanning_mob->IsClient()) { mob->SendAppearancePacket( AppearanceType::Invisibility, 0, @@ -3016,7 +3027,7 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) scanning_mob->CastToClient() ); it_mob_visible->second = true; - mob->Shout(fmt::format("Setting mob visible to scanning_mob [{}]", scanning_mob->GetCleanName()).c_str()); + LogVisibilityDetail("Setting mob [{}] visible to scanning_mob [{}]", mob->GetCleanName(), scanning_mob->GetCleanName()); } } @@ -3032,7 +3043,7 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) 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 (!is_on_close_list && last_known_visible && mob->IsClient()) { scanning_mob->SendAppearancePacket( AppearanceType::Invisibility, 3001, @@ -3041,12 +3052,12 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) mob->CastToClient() ); it->second = false; - scanning_mob->Shout(fmt::format("Setting mob [{}] invisible to scanning_mob", mob->GetCleanName()).c_str()); + 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 (it_mob != mob->m_can_see_mob.end() && !scanning_mob->m_close_mobs.count(mob_id) && it_mob->second && scanning_mob->IsClient()) { mob->SendAppearancePacket( AppearanceType::Invisibility, 3001, @@ -3055,9 +3066,17 @@ void EntityList::UpdateVisibility(Mob *scanning_mob) scanning_mob->CastToClient() ); it_mob->second = false; - mob->Shout(fmt::format("Setting scanning_mob [{}] invisible to mob", scanning_mob->GetCleanName()).c_str()); + LogVisibilityDetail("Setting scanning_mob [{}] invisible to mob [{}]", scanning_mob->GetCleanName(), mob->GetCleanName()); } } + + LogVisibility( + "[{}] Visibility > list_size [{}] moving [{}] elapsed [{}] us", + scanning_mob->GetCleanName(), + scanning_mob->m_can_see_mob.size(), + scanning_mob->IsMoving() ? "true" : "false", + g_vis_bench_timer.elapsedMicroseconds() + ); } bool EntityList::RemoveMerc(uint16 delete_id) diff --git a/zone/mob.cpp b/zone/mob.cpp index dd62d9329..19306f51d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -129,6 +129,7 @@ Mob::Mob( position_update_melee_push_timer(500), hate_list_cleanup_timer(6000), m_scan_close_mobs_timer(6000), + m_see_close_mobs_timer(1000), m_mob_check_moving_timer(1000), bot_attack_flag_timer(10000) { diff --git a/zone/mob.h b/zone/mob.h index 1bdcac89b..a3afe5c6a 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -204,6 +204,7 @@ public: std::unordered_map m_close_mobs; 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; // Bot attack flag