diff --git a/common/ruletypes.h b/common/ruletypes.h index b0ca0acfa..529c7d239 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -564,6 +564,7 @@ RULE_INT(Range, SpellMessages, 75) RULE_INT(Range, SongMessages, 75) RULE_INT(Range, MobPositionUpdates, 600) RULE_INT(Range, ClientPositionUpdates, 300) +RULE_INT(Range, ClientForceSpawnUpdateRange, 1000) RULE_INT(Range, CriticalDamage, 80) RULE_INT(Range, ClientNPCScan, 300) RULE_CATEGORY_END() diff --git a/zone/client.h b/zone/client.h index 952c98333..ca43d6c91 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1489,7 +1489,9 @@ private: Timer hp_self_update_throttle_timer; /* This is to prevent excessive packet sending under trains/fast combat */ Timer hp_other_update_throttle_timer; /* This is to keep clients from DOSing the server with macros that change client targets constantly */ Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */ - glm::vec3 m_Proximity; + + glm::vec3 m_Proximity; + glm::vec4 last_major_update_position; void BulkSendInventoryItems(); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 3e08c1fba..a0961038e 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -243,15 +243,21 @@ bool Client::Process() { /* Build a close range list of NPC's */ if (npc_close_scan_timer.Check()) { - close_mobs.clear(); - auto &mob_list = entity_list.GetMobList(); - float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan)); - float client_update_range = (RuleI(Range, MobPositionUpdates) * RuleI(Range, MobPositionUpdates)); + /* Force spawn updates when traveled far */ + bool force_spawn_updates = false; + float client_update_range = (RuleI(Range, ClientForceSpawnUpdateRange) * RuleI(Range, ClientForceSpawnUpdateRange)); + if (DistanceSquared(last_major_update_position, m_Position) >= client_update_range) { + last_major_update_position = m_Position; + force_spawn_updates = true; + } + float scan_range = (RuleI(Range, ClientNPCScan) * RuleI(Range, ClientNPCScan)); + auto &mob_list = entity_list.GetMobList(); for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) { Mob* mob = itr->second; + float distance = DistanceSquared(m_Position, mob->GetPosition()); if (mob->IsNPC()) { if (distance <= scan_range) { @@ -261,6 +267,10 @@ bool Client::Process() { close_mobs.insert(std::pair(mob, distance)); } } + + if (force_spawn_updates && mob != this && distance <= client_update_range) + mob->SendPositionUpdateToClient(this); + } } diff --git a/zone/mob.cpp b/zone/mob.cpp index 924f26b69..342626078 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1455,6 +1455,20 @@ void Mob::SendPosition() { safe_delete(app); } +void Mob::SendPositionUpdateToClient(Client *client) { + auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + PlayerPositionUpdateServer_Struct* spawn_update = (PlayerPositionUpdateServer_Struct*)app->pBuffer; + + if(this->IsMoving()) + MakeSpawnUpdate(spawn_update); + else + MakeSpawnUpdateNoDelta(spawn_update); + + client->QueuePacket(app, false); + + safe_delete(app); +} + /* Position updates for mobs on the move */ void Mob::SendPositionUpdate(uint8 iSendToSelf) { auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); diff --git a/zone/mob.h b/zone/mob.h index bdc1e7c3a..16e73ba77 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -543,6 +543,7 @@ public: virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true); void SetDelta(const glm::vec4& delta); void SetTargetDestSteps(uint8 target_steps) { tar_ndx = target_steps; } + void SendPositionUpdateToClient(Client *client); void SendPositionUpdate(uint8 iSendToSelf = 0); void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu); void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu);