Compare commits

...

15 Commits

Author SHA1 Message Date
Akkadius 78b0c86442 Don't send update to self while in group 2025-01-20 21:34:49 -06:00
Akkadius ce3d3153d8 Little bit of cleanup 2025-01-20 21:34:49 -06:00
Akkadius 92cc457067 Add rule Zone:EnableEntityClipping 2025-01-20 21:34:49 -06:00
Akkadius 9780623fea Update client.cpp 2025-01-20 21:34:49 -06:00
Akkadius d89bcf4f6c Update client.cpp 2025-01-20 21:34:49 -06:00
Akkadius 34b3a3fc88 Updates 2025-01-20 21:34:49 -06:00
Akkadius 8f54abec61 Update mob.cpp 2025-01-20 21:34:17 -06:00
Akkadius ed4d72c54b Broadcast to group 2025-01-20 21:34:17 -06:00
Akkadius 2d8ef8d286 Feature flag all logic 2025-01-20 21:34:16 -06:00
Akkadius 6424e6a3f3 Amazing 2025-01-20 21:34:00 -06:00
Akkadius 8606ccffc9 Beautiful 2025-01-20 21:34:00 -06:00
Akkadius 2bf02a5be5 Update entity.cpp 2025-01-20 21:33:38 -06:00
Akkadius abc507d173 More 2025-01-20 21:33:38 -06:00
Akkadius c18cba4faf More changes 2025-01-20 21:33:10 -06:00
Akkadius 010ba01ee7 Zone optimizations 2025-01-20 21:31:13 -06:00
19 changed files with 240 additions and 162 deletions
+3 -2
View File
@@ -457,10 +457,11 @@ enum ServerLockType : int {
Unlock Unlock
}; };
enum Invisibility : uint8 { enum Invisibility : uint16 {
Visible, Visible,
Invisible, Invisible,
Special = 255 Special = 255,
GMInvis = 3001
}; };
enum AugmentActions : int { enum AugmentActions : int {
+3 -1
View File
@@ -143,6 +143,7 @@ namespace Logs {
Corpses, Corpses,
XTargets, XTargets,
EvolveItem, EvolveItem,
Visibility,
MaxCategoryID /* Don't Remove this */ MaxCategoryID /* Don't Remove this */
}; };
@@ -244,7 +245,8 @@ namespace Logs {
"EqTime", "EqTime",
"Corpses", "Corpses",
"XTargets", "XTargets",
"EvolveItem" "EvolveItem",
"Visibility"
}; };
} }
+10
View File
@@ -854,6 +854,16 @@
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0) } 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 {\ #define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\ if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\ LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
+2
View File
@@ -373,6 +373,8 @@ RULE_BOOL(Zone, AllowCrossZoneSpellsOnBots, false, "Set to true to allow cross z
RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries") RULE_BOOL(Zone, AllowCrossZoneSpellsOnMercs, false, "Set to true to allow cross zone spells (cast/remove) to affect mercenaries")
RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets") RULE_BOOL(Zone, AllowCrossZoneSpellsOnPets, false, "Set to true to allow cross zone spells (cast/remove) to affect pets")
RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu") RULE_BOOL(Zone, ZoneShardQuestMenuOnly, false, "Set to true if you only want quests to show the zone shard menu")
RULE_BOOL(Zone, AkkadiusTempPerformanceFeatureFlag, true, "Enable or disable the Akkadius Temp Performance Feature Flag")
RULE_BOOL(Zone, EnableEntityClipping, true, "Enable or disable visual entity clipping server side")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Map) RULE_CATEGORY(Map)
+3
View File
@@ -86,6 +86,9 @@ struct BenchTimer
void reset() { start_time = clock::now(); } void reset() { start_time = clock::now(); }
// this is seconds // this is seconds
double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); } double elapsed() { return std::chrono::duration<double> (clock::now() - start_time).count(); }
std::chrono::milliseconds::rep elapsedMilliseconds() { return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start_time).count(); }
std::chrono::microseconds::rep elapsedMicroseconds() { return std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start_time).count(); }
std::chrono::nanoseconds::rep elapsedNanoseconds() { return std::chrono::duration_cast<std::chrono::nanoseconds>(clock::now() - start_time).count(); }
private: private:
std::chrono::time_point<std::chrono::high_resolution_clock> start_time; std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
}; };
+1 -1
View File
@@ -679,7 +679,7 @@ int ZoneStore::GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version) uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
{ {
const auto& z = GetZoneVersionWithFallback(zone_id, version); const auto& z = GetZoneVersionWithFallback(zone_id, version);
return z ? z->max_movement_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE; return z ? z->npc_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
} }
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version) int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
-33
View File
@@ -7390,39 +7390,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
return; return;
} }
/**
* @param close_mobs
* @param scanning_mob
*/
void EntityList::ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob)
{
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
close_mobs.clear();
for (auto& e : mob_list) {
auto mob = e.second;
if (!mob->IsClient()) {
continue;
}
if (mob->GetID() <= 0) {
continue;
}
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
if (distance <= scan_range) {
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
}
else if (mob->GetAggroRange() >= scan_range) {
close_mobs.insert(std::pair<uint16, Mob*>(mob->GetID(), mob));
}
}
LogAIScanCloseDetail("Close Client Mob List Size [{}] for mob [{}]", close_mobs.size(), scanning_mob->GetCleanName());
}
uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid) { uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets, Raid* raid) {
uint8 need_healed = 0; uint8 need_healed = 0;
+72 -17
View File
@@ -12939,17 +12939,10 @@ void Client::SendTopLevelInventory()
} }
} }
// On a normal basis we limit mob movement updates based on distance
// This ensures we send a periodic full zone update to a client that has started moving after 5 or so minutes
//
// For very large zones we will also force a full update based on distance
//
// We ignore a small distance around us so that we don't interrupt already pathing deltas as those npcs will appear
// to full stop when they are actually still pathing
void Client::CheckSendBulkClientPositionUpdate() void Client::CheckSendBulkClientPositionUpdate()
{ {
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition()); float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance(); bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetMaxNpcUpdateRange();
bool is_ready_to_update = ( bool is_ready_to_update = (
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
); );
@@ -12958,31 +12951,54 @@ void Client::CheckSendBulkClientPositionUpdate()
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName()); LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
auto &mob_movement_manager = MobMovementManager::Get(); auto &mob_movement_manager = MobMovementManager::Get();
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) { for (auto &e: entity_list.GetMobList()) {
Mob *entity = it.second; Mob *mob = e.second;
if (!entity->IsNPC()) { if (!mob->IsNPC()) {
continue; continue;
} }
int animation_speed = 0; int animation_speed = 0;
if (entity->IsMoving()) { if (mob->IsMoving()) {
if (entity->IsRunning()) { if (mob->IsRunning()) {
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed()); animation_speed = (mob->IsFeared() ? mob->GetFearSpeed() : mob->GetRunspeed());
} }
else { else {
animation_speed = entity->GetWalkspeed(); animation_speed = mob->GetWalkspeed();
} }
} }
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this); // if we have seen this mob before, and it hasn't moved, skip it
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
if (m_last_seen_mob_position.contains(mob->GetID())) {
if (m_last_seen_mob_position[mob->GetID()] == mob->GetPosition()) {
LogVisibilityDetail(
"Mob [{}] has already been sent to client [{}] at this position, skipping",
mob->GetCleanName(),
GetCleanName()
);
continue;
}
}
}
mob_movement_manager.SendCommandToClients(
mob,
0.0,
0.0,
0.0,
0.0,
animation_speed,
ClientRangeAny,
this
);
} }
m_last_position_before_bulk_update = GetPosition(); m_last_position_before_bulk_update = GetPosition();
} }
} }
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval); const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval); const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
@@ -13123,3 +13139,42 @@ void Client::SetAAEXPPercentage(uint8 percentage)
SendAlternateAdvancementStats(); SendAlternateAdvancementStats();
SendAlternateAdvancementTable(); SendAlternateAdvancementTable();
} }
void Client::BroadcastPositionUpdate()
{
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer;
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
spu->spawn_id = GetID();
spu->x_pos = FloatToEQ19(GetX());
spu->y_pos = FloatToEQ19(GetY());
spu->z_pos = FloatToEQ19(GetZ());
spu->heading = FloatToEQ12(GetHeading());
spu->delta_x = FloatToEQ13(0);
spu->delta_y = FloatToEQ13(0);
spu->delta_z = FloatToEQ13(0);
spu->delta_heading = FloatToEQ10(0);
spu->animation = 0;
entity_list.QueueCloseClients(this, &outapp, true, zone->GetMaxClientUpdateRange());
Group *g = GetGroup();
if (g) {
for (auto & m : g->members) {
if (m && m->IsClient() && m != this) {
m->CastToClient()->QueuePacket(&outapp);
}
}
}
}
void Client::SetVisibility(Mob* mob, bool visible) {
mob->SendAppearancePacket(
AppearanceType::Invisibility,
visible ? m_invisibility_state : Invisibility::GMInvis, // reset back to original visibility state when visible
false,
true,
this
);
}
+2
View File
@@ -1828,6 +1828,7 @@ public:
void DoEvolveTransferXP(const EQApplicationPacket* app); void DoEvolveTransferXP(const EQApplicationPacket* app);
void SendEvolveXPTransferWindow(); 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 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: protected:
friend class Mob; friend class Mob;
@@ -2087,6 +2088,7 @@ private:
Timer m_client_npc_aggro_scan_timer; Timer m_client_npc_aggro_scan_timer;
void CheckClientToNpcAggroTimer(); void CheckClientToNpcAggroTimer();
void ClientToNpcAggroProcess(); void ClientToNpcAggroProcess();
void BroadcastPositionUpdate();
// bulk position updates // bulk position updates
glm::vec4 m_last_position_before_bulk_update; glm::vec4 m_last_position_before_bulk_update;
+19
View File
@@ -971,6 +971,10 @@ void Client::CompleteConnect()
RecordStats(); RecordStats();
AutoGrantAAPoints(); AutoGrantAAPoints();
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
m_last_seen_mob_position.reserve(entity_list.GetMobList().size());
}
// enforce some rules.. // enforce some rules..
if (!CanEnterZone()) { if (!CanEnterZone()) {
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName()); LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
@@ -4956,6 +4960,21 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
CheckScanCloseMobsMovingTimer(); CheckScanCloseMobsMovingTimer();
} }
if (RuleB(Zone, EnableEntityClipping)) {
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(); CheckSendBulkClientPositionUpdate();
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;
+8
View File
@@ -122,8 +122,12 @@ bool Client::Process() {
/* I haven't naturally updated my position in 10 seconds, updating manually */ /* I haven't naturally updated my position in 10 seconds, updating manually */
if (!IsMoving() && m_position_update_timer.Check()) { if (!IsMoving() && m_position_update_timer.Check()) {
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
CastToClient()->BroadcastPositionUpdate();
} else {
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0); SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
} }
}
if (mana_timer.Check()) if (mana_timer.Check())
CheckManaEndUpdate(); CheckManaEndUpdate();
@@ -285,6 +289,10 @@ bool Client::Process() {
entity_list.ScanCloseMobs(this); entity_list.ScanCloseMobs(this);
} }
if (RuleB(Zone, EnableEntityClipping) && m_see_close_mobs_timer.Check() && RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
entity_list.UpdateVisibility(this);
}
if (RuleB(Inventory, LazyLoadBank)) { 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 // 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()) { if (!m_lazy_load_bank && lazy_load_bank_check_timer.Check()) {
+1 -1
View File
@@ -1122,7 +1122,7 @@ void EntityList::AESpell(
LogAoeCast( LogAoeCast(
"Close scan distance [{}] cast distance [{}]", "Close scan distance [{}] cast distance [{}]",
RuleI(Range, MobCloseScanDistance), zone->GetMaxNpcUpdateRange(),
distance distance
); );
+68 -19
View File
@@ -1717,15 +1717,6 @@ void EntityList::QueueClientsByXTarget(Mob *sender, const EQApplicationPacket *a
} }
} }
/**
* @param sender
* @param app
* @param ignore_sender
* @param distance
* @param skipped_mob
* @param is_ack_required
* @param filter
*/
void EntityList::QueueCloseClients( void EntityList::QueueCloseClients(
Mob *sender, Mob *sender,
const EQApplicationPacket *app, const EQApplicationPacket *app,
@@ -1742,7 +1733,7 @@ void EntityList::QueueCloseClients(
} }
if (distance <= 0) { if (distance <= 0) {
distance = 600; distance = zone->GetMaxClientUpdateRange();
} }
float distance_squared = distance * distance; float distance_squared = distance * distance;
@@ -2878,6 +2869,9 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
); );
it->second->m_close_mobs.erase(entity_id); it->second->m_close_mobs.erase(entity_id);
it->second->m_can_see_mob.erase(entity_id);
it->second->m_last_seen_mob_position.erase(entity_id);
++it; ++it;
} }
@@ -2931,6 +2925,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 // 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 // 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) // entity list (zone wide)
BenchTimer g_scan_bench_timer;
void EntityList::ScanCloseMobs(Mob *scanning_mob) void EntityList::ScanCloseMobs(Mob *scanning_mob)
{ {
if (!scanning_mob) { if (!scanning_mob) {
@@ -2941,7 +2938,9 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
return; return;
} }
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance); g_scan_bench_timer.reset();
float scan_range = std::max(zone->GetMaxNpcUpdateRange(), zone->GetMaxClientUpdateRange());
// Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved. // Reserve memory in m_close_mobs to avoid frequent re-allocations if not already reserved.
// Assuming mob_list.size() as an upper bound for reservation. // Assuming mob_list.size() as an upper bound for reservation.
@@ -2957,7 +2956,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
continue; continue;
} }
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition()); float distance = Distance(scanning_mob->GetPosition(), mob->GetPosition());
if (distance <= scan_range || mob->GetAggroRange() >= scan_range) { if (distance <= scan_range || mob->GetAggroRange() >= scan_range) {
// add mob to scanning_mob's close list and vice versa // add mob to scanning_mob's close list and vice versa
// check if the mob is already in the close mobs list before inserting // check if the mob is already in the close mobs list before inserting
@@ -2969,10 +2968,64 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
} }
LogAIScanClose( LogAIScanClose(
"[{}] Scanning close list > list_size [{}] moving [{}]", "[{}] Scanning close list > list_size [{}] moving [{}] elapsed [{}] us",
scanning_mob->GetCleanName(), scanning_mob->GetCleanName(),
scanning_mob->m_close_mobs.size(), 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;
#define STATE_HIDDEN (-1)
#define STATE_VISIBLE 1
void EntityList::UpdateVisibility(Mob *scanning_mob) {
if (!scanning_mob) {
return;
}
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());
}
// Iterate through all mobs in the zone
for (auto &e: mob_list) {
auto mob = e.second;
if (!mob || mob == scanning_mob) { continue; }
// 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;
if (scanning_mob->CalculateDistance(mob) <= mob->GetUpdateRange()) {
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;
}
}
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;
}
}
}
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()
); );
} }
@@ -5759,14 +5812,10 @@ void EntityList::ReloadMerchants() {
* then we return the full list * then we return the full list
* *
* See comments @EntityList::ScanCloseMobs for system explanation * See comments @EntityList::ScanCloseMobs for system explanation
*
* @param mob
* @param distance
* @return
*/ */
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance) std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
{ {
if (distance <= RuleI(Range, MobCloseScanDistance)) { if (distance <= zone->GetMaxNpcUpdateRange()) {
return mob->m_close_mobs; return mob->m_close_mobs;
} }
+2 -2
View File
@@ -570,6 +570,8 @@ public:
void RefreshClientXTargets(Client *c); void RefreshClientXTargets(Client *c);
void SendAlternateAdvancementStats(); void SendAlternateAdvancementStats();
void ScanCloseMobs(Mob *scanning_mob); void ScanCloseMobs(Mob *scanning_mob);
void UpdateVisibility(Mob *scanning_mob);
void UpdateKnownPositions(Mob *scanning_mob);
void GetTrapInfo(Client* c); void GetTrapInfo(Client* c);
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group); bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);
@@ -631,8 +633,6 @@ private:
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
void ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob);
void GetBotList(std::list<Bot*> &b_list); void GetBotList(std::list<Bot*> &b_list);
private: private:
std::list<Bot*> bot_list; std::list<Bot*> bot_list;
+9
View File
@@ -129,6 +129,7 @@ Mob::Mob(
position_update_melee_push_timer(500), position_update_melee_push_timer(500),
hate_list_cleanup_timer(6000), hate_list_cleanup_timer(6000),
m_scan_close_mobs_timer(6000), m_scan_close_mobs_timer(6000),
m_see_close_mobs_timer(1000),
m_mob_check_moving_timer(1000), m_mob_check_moving_timer(1000),
bot_attack_flag_timer(10000) bot_attack_flag_timer(10000)
{ {
@@ -4126,6 +4127,10 @@ void Mob::SendAppearancePacket(
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
auto* a = (SpawnAppearance_Struct*)outapp->pBuffer; auto* a = (SpawnAppearance_Struct*)outapp->pBuffer;
if (type == AppearanceType::Invisibility && value != Invisibility::GMInvis) {
m_invisibility_state = value;
}
a->spawn_id = GetID(); a->spawn_id = GetID();
a->type = type; a->type = type;
a->parameter = value; a->parameter = value;
@@ -8626,3 +8631,7 @@ void Mob::ClearDataBucketCache()
DataBucket::DeleteFromCache(id, t); DataBucket::DeleteFromCache(id, t);
} }
} }
float Mob::GetUpdateRange() {
return IsClient() ? zone->GetMaxClientUpdateRange() : zone->GetMaxNpcUpdateRange();
}
+6
View File
@@ -202,7 +202,10 @@ public:
void DisplayInfo(Mob *mob); void DisplayInfo(Mob *mob);
std::unordered_map<uint16, Mob *> m_close_mobs; std::unordered_map<uint16, Mob *> m_close_mobs;
std::unordered_map<int, int8> m_can_see_mob;
std::unordered_map<int, glm::vec4> m_last_seen_mob_position;
Timer m_scan_close_mobs_timer; Timer m_scan_close_mobs_timer;
Timer m_see_close_mobs_timer;
Timer m_mob_check_moving_timer; Timer m_mob_check_moving_timer;
// Bot attack flag // Bot attack flag
@@ -1490,6 +1493,7 @@ public:
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f); std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
void CheckScanCloseMobsMovingTimer(); void CheckScanCloseMobsMovingTimer();
float GetUpdateRange();
void ClearDataBucketCache(); void ClearDataBucketCache();
@@ -1907,6 +1911,8 @@ protected:
MobMovementManager *mMovementManager; MobMovementManager *mMovementManager;
bool m_invisibility_state = 0;
private: private:
Mob* target; Mob* target;
EQ::InventoryProfile m_inv; EQ::InventoryProfile m_inv;
+7 -1
View File
@@ -852,11 +852,14 @@ void MobMovementManager::SendCommandToClients(
} }
c->QueuePacket(&outapp, false); c->QueuePacket(&outapp, false);
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
}
} }
} }
else { else {
float short_range = RuleR(Pathing, ShortMovementUpdateRange); float short_range = RuleR(Pathing, ShortMovementUpdateRange);
float long_range = zone->GetNpcPositionUpdateDistance(); float long_range = zone->GetMaxNpcUpdateRange();
for (auto &c : _impl->Clients) { for (auto &c : _impl->Clients) {
if (single_client && c != single_client) { if (single_client && c != single_client) {
@@ -902,6 +905,9 @@ void MobMovementManager::SendCommandToClients(
} }
c->QueuePacket(&outapp, false); c->QueuePacket(&outapp, false);
if (RuleB(Zone, AkkadiusTempPerformanceFeatureFlag)) {
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
}
} }
} }
} }
+2 -62
View File
@@ -1091,7 +1091,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
mMovementManager = &MobMovementManager::Get(); mMovementManager = &MobMovementManager::Get();
SetNpcPositionUpdateDistance(0);
SetQuestHotReloadQueued(false); SetQuestHotReloadQueued(false);
} }
@@ -1380,7 +1379,8 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_version)
can_levitate = z->canlevitate != 0; can_levitate = z->canlevitate != 0;
can_castoutdoor = z->castoutdoor != 0; can_castoutdoor = z->castoutdoor != 0;
is_hotzone = z->hotzone != 0; is_hotzone = z->hotzone != 0;
max_movement_update_range = z->max_movement_update_range; m_npc_update_range = z->npc_update_range;
m_client_update_range = z->client_update_range;
default_ruleset = z->ruleset; default_ruleset = z->ruleset;
allow_mercs = true; allow_mercs = true;
m_graveyard_id = z->graveyard_id; m_graveyard_id = z->graveyard_id;
@@ -1538,10 +1538,6 @@ bool Zone::Process() {
if (adv_data && !did_adventure_actions) { if (adv_data && !did_adventure_actions) {
DoAdventureActions(); DoAdventureActions();
} }
if (GetNpcPositionUpdateDistance() == 0) {
CalculateNpcUpdateDistanceSpread();
}
} }
if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) { if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) {
@@ -2735,62 +2731,6 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
m_ucss_available = ucss_available; m_ucss_available = ucss_available;
} }
int Zone::GetNpcPositionUpdateDistance() const
{
return npc_position_update_distance;
}
void Zone::SetNpcPositionUpdateDistance(int in_npc_position_update_distance)
{
Zone::npc_position_update_distance = in_npc_position_update_distance;
}
void Zone::CalculateNpcUpdateDistanceSpread()
{
float max_x = 0;
float max_y = 0;
float min_x = 0;
float min_y = 0;
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
if (entity->GetX() <= min_x) {
min_x = entity->GetX();
}
if (entity->GetY() <= min_y) {
min_y = entity->GetY();
}
if (entity->GetX() >= max_x) {
max_x = entity->GetX();
}
if (entity->GetY() >= max_y) {
max_y = entity->GetY();
}
}
int x_spread = int(std::abs(max_x - min_x));
int y_spread = int(std::abs(max_y - min_y));
int combined_spread = int(std::abs((x_spread + y_spread) / 2));
int update_distance = EQ::ClampLower(int(combined_spread / 4), int(zone->GetMaxMovementUpdateRange()));
SetNpcPositionUpdateDistance(update_distance);
Log(Logs::General, Logs::Debug,
"NPC update spread distance set to [%i] combined_spread [%i]",
update_distance,
combined_spread
);
}
bool Zone::IsQuestHotReloadQueued() const bool Zone::IsQuestHotReloadQueued() const
{ {
return quest_hot_reload_queued; return quest_hot_reload_queued;
+4 -5
View File
@@ -156,9 +156,6 @@ public:
bool SaveZoneCFG(); bool SaveZoneCFG();
bool DoesAlternateCurrencyExist(uint32 currency_id); bool DoesAlternateCurrencyExist(uint32 currency_id);
int GetNpcPositionUpdateDistance() const;
void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
char *adv_data; char *adv_data;
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location); const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
@@ -417,7 +414,8 @@ public:
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message)); SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
}; };
double GetMaxMovementUpdateRange() const { return max_movement_update_range; } double GetMaxNpcUpdateRange() const { return m_npc_update_range; }
double GetMaxClientUpdateRange() const { return m_client_update_range; }
void SetIsHotzone(bool is_hotzone); void SetIsHotzone(bool is_hotzone);
@@ -469,7 +467,8 @@ private:
bool staticzone; bool staticzone;
bool zone_has_current_time; bool zone_has_current_time;
bool quest_hot_reload_queued; bool quest_hot_reload_queued;
double max_movement_update_range; double m_npc_update_range;
double m_client_update_range;
char *long_name; char *long_name;
char *map_name; char *map_name;
char *short_name; char *short_name;