mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-19 13:28:25 +00:00
[Performance] Client / NPC Position Update Optimizations (#4602)
* Zone optimizations * More changes * More * Update entity.cpp * Beautiful * Amazing * Feature flag all logic * Broadcast to group * Update mob.cpp * Updates * Update client.cpp * Update client.cpp * Add rule Zone:EnableEntityClipping * Little bit of cleanup * Don't send update to self while in group * Remove visibility work and feature flags * Cleanup * Logging * Improve CheckSendBulkNpcPositions * No need to cast * Field cleanup * Build initial list on zone-in
This commit is contained in:
+79
-23
@@ -157,7 +157,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
||||
endupkeep_timer(1000),
|
||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||
m_client_npc_aggro_scan_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||
m_client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
||||
m_client_bulk_npc_pos_update_timer(60 * 1000),
|
||||
tribute_timer(Tribute_duration),
|
||||
proximity_timer(ClientProximity_interval),
|
||||
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
|
||||
@@ -12939,50 +12939,77 @@ 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::CheckSendBulkNpcPositions()
|
||||
{
|
||||
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
|
||||
float update_range = RuleI(Range, MobCloseScanDistance);
|
||||
bool moved_far_enough_before_bulk_update = distance_moved >= update_range;
|
||||
bool is_ready_to_update = (
|
||||
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
m_client_bulk_npc_pos_update_timer.Check() || moved_far_enough_before_bulk_update
|
||||
);
|
||||
|
||||
if (IsMoving() && is_ready_to_update) {
|
||||
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
|
||||
|
||||
int updated_count = 0;
|
||||
int skipped_count = 0;
|
||||
if (is_ready_to_update) {
|
||||
auto &mob_movement_manager = MobMovementManager::Get();
|
||||
auto &mob_list = entity_list.GetMobList();
|
||||
|
||||
for (auto &it : mob_list) {
|
||||
Mob *entity = it.second;
|
||||
if (!entity->IsNPC()) {
|
||||
for (auto &e: entity_list.GetMobList()) {
|
||||
Mob *mob = e.second;
|
||||
if (!mob->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int animation_speed = 0;
|
||||
if (entity->IsMoving()) {
|
||||
if (entity->IsRunning()) {
|
||||
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
|
||||
if (mob->IsMoving()) {
|
||||
if (mob->IsRunning()) {
|
||||
animation_speed = (mob->IsFeared() ? mob->GetFearSpeed() : mob->GetRunspeed());
|
||||
}
|
||||
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 (m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (m_last_seen_mob_position[mob->GetID()] == mob->GetPosition()) {
|
||||
LogPositionUpdateDetail(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
GetCleanName()
|
||||
);
|
||||
skipped_count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mob_movement_manager.SendCommandToClients(
|
||||
mob,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
animation_speed,
|
||||
ClientRangeAny,
|
||||
this
|
||||
);
|
||||
|
||||
updated_count++;
|
||||
}
|
||||
|
||||
LogPositionUpdate(
|
||||
"[{}] Sent [{}] bulk updated NPC positions, skipped [{}] distance_moved [{}] update_range [{}]",
|
||||
GetCleanName(),
|
||||
updated_count,
|
||||
skipped_count,
|
||||
distance_moved,
|
||||
update_range
|
||||
);
|
||||
|
||||
m_last_position_before_bulk_update = GetPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint16 scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
|
||||
const uint16 scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
|
||||
|
||||
@@ -13123,3 +13150,32 @@ void Client::SetAAEXPPercentage(uint8 percentage)
|
||||
SendAlternateAdvancementStats();
|
||||
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->GetClientUpdateRange());
|
||||
|
||||
Group *g = GetGroup();
|
||||
if (g) {
|
||||
for (auto & m : g->members) {
|
||||
if (m && m->IsClient() && m != this) {
|
||||
m->CastToClient()->QueuePacket(&outapp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user