mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +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:
parent
1a27127c39
commit
25826c6686
@ -6289,7 +6289,20 @@ INSERT INTO `items_evolving_details` VALUES
|
||||
|
||||
)",
|
||||
.content_schema_update = true
|
||||
}
|
||||
},
|
||||
ManifestEntry{
|
||||
.version = 9291,
|
||||
.description = "2025_01_21_add_remove_zone_fields",
|
||||
.check = "SHOW COLUMNS FROM `zone` LIKE 'client_update_range'",
|
||||
.condition = "empty",
|
||||
.match = "",
|
||||
.sql = R"(
|
||||
ALTER TABLE zone DROP COLUMN IF EXISTS npc_update_range;
|
||||
ALTER TABLE zone DROP COLUMN IF EXISTS max_movement_update_range;
|
||||
ALTER TABLE `zone` ADD COLUMN `client_update_range` int(11) NOT NULL DEFAULT 600 AFTER `npc_max_aggro_dist`;
|
||||
)",
|
||||
.content_schema_update = true
|
||||
},
|
||||
// -- template; copy/paste this when you need to create a new entry
|
||||
// ManifestEntry{
|
||||
// .version = 9228,
|
||||
|
||||
@ -143,6 +143,7 @@ namespace Logs {
|
||||
Corpses,
|
||||
XTargets,
|
||||
EvolveItem,
|
||||
PositionUpdate,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@ -244,7 +245,8 @@ namespace Logs {
|
||||
"EqTime",
|
||||
"Corpses",
|
||||
"XTargets",
|
||||
"EvolveItem"
|
||||
"EvolveItem",
|
||||
"PositionUpdate"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -854,6 +854,16 @@
|
||||
OutF(LogSys, Logs::Detail, Logs::XTargets, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPositionUpdate(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::General, Logs::PositionUpdate))\
|
||||
OutF(LogSys, Logs::General, Logs::PositionUpdate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define LogPositionUpdateDetail(message, ...) do {\
|
||||
if (LogSys.IsLogEnabled(Logs::Detail, Logs::PositionUpdate))\
|
||||
OutF(LogSys, Logs::Detail, Logs::PositionUpdate, __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__);\
|
||||
|
||||
@ -111,7 +111,7 @@ public:
|
||||
int32_t fast_regen_mana;
|
||||
int32_t fast_regen_endurance;
|
||||
int32_t npc_max_aggro_dist;
|
||||
uint32_t max_movement_update_range;
|
||||
uint32_t client_update_range;
|
||||
int32_t underworld_teleport_index;
|
||||
int32_t lava_damage;
|
||||
int32_t min_lava_damage;
|
||||
@ -220,7 +220,7 @@ public:
|
||||
"fast_regen_mana",
|
||||
"fast_regen_endurance",
|
||||
"npc_max_aggro_dist",
|
||||
"max_movement_update_range",
|
||||
"client_update_range",
|
||||
"underworld_teleport_index",
|
||||
"lava_damage",
|
||||
"min_lava_damage",
|
||||
@ -325,7 +325,7 @@ public:
|
||||
"fast_regen_mana",
|
||||
"fast_regen_endurance",
|
||||
"npc_max_aggro_dist",
|
||||
"max_movement_update_range",
|
||||
"client_update_range",
|
||||
"underworld_teleport_index",
|
||||
"lava_damage",
|
||||
"min_lava_damage",
|
||||
@ -464,7 +464,7 @@ public:
|
||||
e.fast_regen_mana = 180;
|
||||
e.fast_regen_endurance = 180;
|
||||
e.npc_max_aggro_dist = 600;
|
||||
e.max_movement_update_range = 600;
|
||||
e.client_update_range = 600;
|
||||
e.underworld_teleport_index = 0;
|
||||
e.lava_damage = 50;
|
||||
e.min_lava_damage = 10;
|
||||
@ -599,7 +599,7 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
@ -730,7 +730,7 @@ public:
|
||||
v.push_back(columns[89] + " = " + std::to_string(e.fast_regen_mana));
|
||||
v.push_back(columns[90] + " = " + std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(columns[91] + " = " + std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.max_movement_update_range));
|
||||
v.push_back(columns[92] + " = " + std::to_string(e.client_update_range));
|
||||
v.push_back(columns[93] + " = " + std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(columns[94] + " = " + std::to_string(e.lava_damage));
|
||||
v.push_back(columns[95] + " = " + std::to_string(e.min_lava_damage));
|
||||
@ -850,7 +850,7 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
@ -978,7 +978,7 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
@ -1110,7 +1110,7 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
@ -1233,7 +1233,7 @@ public:
|
||||
e.fast_regen_mana = row[89] ? static_cast<int32_t>(atoi(row[89])) : 180;
|
||||
e.fast_regen_endurance = row[90] ? static_cast<int32_t>(atoi(row[90])) : 180;
|
||||
e.npc_max_aggro_dist = row[91] ? static_cast<int32_t>(atoi(row[91])) : 600;
|
||||
e.max_movement_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.client_update_range = row[92] ? static_cast<uint32_t>(strtoul(row[92], nullptr, 10)) : 600;
|
||||
e.underworld_teleport_index = row[93] ? static_cast<int32_t>(atoi(row[93])) : 0;
|
||||
e.lava_damage = row[94] ? static_cast<int32_t>(atoi(row[94])) : 50;
|
||||
e.min_lava_damage = row[95] ? static_cast<int32_t>(atoi(row[95])) : 10;
|
||||
@ -1406,7 +1406,7 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
@ -1527,7 +1527,7 @@ public:
|
||||
v.push_back(std::to_string(e.fast_regen_mana));
|
||||
v.push_back(std::to_string(e.fast_regen_endurance));
|
||||
v.push_back(std::to_string(e.npc_max_aggro_dist));
|
||||
v.push_back(std::to_string(e.max_movement_update_range));
|
||||
v.push_back(std::to_string(e.client_update_range));
|
||||
v.push_back(std::to_string(e.underworld_teleport_index));
|
||||
v.push_back(std::to_string(e.lava_damage));
|
||||
v.push_back(std::to_string(e.min_lava_damage));
|
||||
|
||||
@ -86,6 +86,9 @@ struct BenchTimer
|
||||
void reset() { start_time = clock::now(); }
|
||||
// this is seconds
|
||||
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:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
|
||||
};
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9290
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9291
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||
|
||||
#endif
|
||||
|
||||
@ -676,12 +676,6 @@ int ZoneStore::GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
||||
return z ? z->npc_max_aggro_dist : DEFAULT_ZONE_MAX_AGGRO_DISTANCE;
|
||||
}
|
||||
|
||||
uint32 ZoneStore::GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||
{
|
||||
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
||||
return z ? z->max_movement_update_range : DEFAULT_ZONE_MAX_MOVEMENT_UPDATE_RANGE;
|
||||
}
|
||||
|
||||
int8 ZoneStore::GetZoneMinimumExpansion(uint32 zone_id, int version)
|
||||
{
|
||||
const auto& z = GetZoneVersionWithFallback(zone_id, version);
|
||||
|
||||
@ -94,7 +94,6 @@ public:
|
||||
int GetZoneFastRegenMana(uint32 zone_id, int version = 0);
|
||||
int GetZoneFastRegenEndurance(uint32 zone_id, int version = 0);
|
||||
int GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version = 0);
|
||||
uint32 GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version = 0);
|
||||
int8 GetZoneMinimumExpansion(uint32 zone_id, int version = 0);
|
||||
int8 GetZoneMaximumExpansion(uint32 zone_id, int version = 0);
|
||||
const std::string GetZoneContentFlags(uint32 zone_id, int version = 0);
|
||||
|
||||
33
zone/bot.cpp
33
zone/bot.cpp
@ -7390,39 +7390,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
|
||||
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 need_healed = 0;
|
||||
|
||||
102
zone/client.cpp
102
zone/client.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2087,12 +2087,13 @@ private:
|
||||
Timer m_client_npc_aggro_scan_timer;
|
||||
void CheckClientToNpcAggroTimer();
|
||||
void ClientToNpcAggroProcess();
|
||||
void BroadcastPositionUpdate();
|
||||
|
||||
// bulk position updates
|
||||
glm::vec4 m_last_position_before_bulk_update;
|
||||
Timer m_client_zone_wide_full_position_update_timer;
|
||||
Timer m_client_bulk_npc_pos_update_timer;
|
||||
Timer m_position_update_timer;
|
||||
void CheckSendBulkClientPositionUpdate();
|
||||
void CheckSendBulkNpcPositions();
|
||||
|
||||
void BulkSendInventoryItems();
|
||||
|
||||
|
||||
@ -971,6 +971,16 @@ void Client::CompleteConnect()
|
||||
RecordStats();
|
||||
AutoGrantAAPoints();
|
||||
|
||||
// set initial position for mob tracking
|
||||
m_last_seen_mob_position.reserve(entity_list.GetMobList().size());
|
||||
for (auto& mob : entity_list.GetMobList()) {
|
||||
if (!mob.second->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_last_seen_mob_position[mob.second->GetID()] = mob.second->GetPosition();
|
||||
}
|
||||
|
||||
// enforce some rules..
|
||||
if (!CanEnterZone()) {
|
||||
LogInfo("Kicking character [{}] from zone, not allowed here (missing requirements)", GetCleanName());
|
||||
@ -4956,7 +4966,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
|
||||
CheckScanCloseMobsMovingTimer();
|
||||
}
|
||||
|
||||
CheckSendBulkClientPositionUpdate();
|
||||
CheckSendBulkNpcPositions();
|
||||
|
||||
int32 new_animation = ppu->animation;
|
||||
|
||||
|
||||
@ -122,7 +122,7 @@ bool Client::Process() {
|
||||
|
||||
/* I haven't naturally updated my position in 10 seconds, updating manually */
|
||||
if (!IsMoving() && m_position_update_timer.Check()) {
|
||||
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
BroadcastPositionUpdate();
|
||||
}
|
||||
|
||||
if (mana_timer.Check())
|
||||
|
||||
@ -5653,16 +5653,6 @@ int Perl__GetZoneNPCMaximumAggroDistance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 Perl__GetZoneMaximumMovementUpdateRange(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 Perl__GetZoneMinimumExpansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@ -6112,8 +6102,6 @@ void perl_register_quest()
|
||||
package.add("GetZoneMaximumExpansion", (int8(*)(uint32, int))&Perl__GetZoneMaximumExpansion);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumLevel", (uint8(*)(uint32, int))&Perl__GetZoneMaximumLevel);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumMovementUpdateRange", (uint32(*)(uint32, int))&Perl__GetZoneMaximumMovementUpdateRange);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMaximumPlayers", (int(*)(uint32, int))&Perl__GetZoneMaximumPlayers);
|
||||
package.add("GetZoneMinimumClip", (float(*)(uint32))&Perl__GetZoneMinimumClip);
|
||||
|
||||
@ -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(
|
||||
Mob *sender,
|
||||
const EQApplicationPacket *app,
|
||||
@ -1742,7 +1733,7 @@ void EntityList::QueueCloseClients(
|
||||
}
|
||||
|
||||
if (distance <= 0) {
|
||||
distance = 600;
|
||||
distance = zone->GetClientUpdateRange();
|
||||
}
|
||||
|
||||
float distance_squared = distance * distance;
|
||||
@ -2878,6 +2869,8 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
|
||||
);
|
||||
|
||||
it->second->m_close_mobs.erase(entity_id);
|
||||
it->second->m_last_seen_mob_position.erase(entity_id);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
@ -2931,6 +2924,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) {
|
||||
@ -2941,7 +2937,9 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
return;
|
||||
}
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
|
||||
g_scan_bench_timer.reset();
|
||||
|
||||
float scan_range = RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
// 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.
|
||||
@ -2957,7 +2955,7 @@ void EntityList::ScanCloseMobs(Mob *scanning_mob)
|
||||
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) {
|
||||
// add mob to scanning_mob's close list and vice versa
|
||||
// check if the mob is already in the close mobs list before inserting
|
||||
@ -2969,10 +2967,11 @@ void EntityList::ScanCloseMobs(Mob *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()
|
||||
);
|
||||
}
|
||||
|
||||
@ -5759,10 +5758,6 @@ void EntityList::ReloadMerchants() {
|
||||
* then we return the full list
|
||||
*
|
||||
* See comments @EntityList::ScanCloseMobs for system explanation
|
||||
*
|
||||
* @param mob
|
||||
* @param distance
|
||||
* @return
|
||||
*/
|
||||
std::unordered_map<uint16, Mob *> &EntityList::GetCloseMobList(Mob *mob, float distance)
|
||||
{
|
||||
|
||||
@ -631,8 +631,6 @@ private:
|
||||
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 ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob);
|
||||
|
||||
void GetBotList(std::list<Bot*> &b_list);
|
||||
private:
|
||||
std::list<Bot*> bot_list;
|
||||
|
||||
@ -4668,16 +4668,6 @@ int lua_get_zone_npc_maximum_aggro_distance(uint32 zone_id, int version)
|
||||
return zone_store.GetZoneNPCMaximumAggroDistance(zone_id, version);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id);
|
||||
}
|
||||
|
||||
uint32 lua_get_zone_maximum_movement_update_range(uint32 zone_id, int version)
|
||||
{
|
||||
return zone_store.GetZoneMaximumMovementUpdateRange(zone_id, version);
|
||||
}
|
||||
|
||||
int8 lua_get_zone_minimum_expansion(uint32 zone_id)
|
||||
{
|
||||
return zone_store.GetZoneMinimumExpansion(zone_id);
|
||||
@ -6287,8 +6277,6 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("get_zone_fast_regen_endurance", (int(*)(uint32,int))&lua_get_zone_fast_regen_endurance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_aggro_distance", (int(*)(uint32,int))&lua_get_zone_npc_maximum_aggro_distance),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_npc_maximum_movement_update_range", (uint32(*)(uint32,int))&lua_get_zone_maximum_movement_update_range),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_minimum_expansion", (int8(*)(uint32,int))&lua_get_zone_minimum_expansion),
|
||||
luabind::def("get_zone_maximum_expansion", (int8(*)(uint32))&lua_get_zone_maximum_expansion),
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -8612,15 +8613,15 @@ std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float distance)
|
||||
void Mob::ClearDataBucketCache()
|
||||
{
|
||||
if (IsOfClientBot()) {
|
||||
uint64 id = 0;
|
||||
uint64 id = 0;
|
||||
DataBucketLoadType::Type t{};
|
||||
if (IsBot()) {
|
||||
id = CastToBot()->GetBotID();
|
||||
t = DataBucketLoadType::Bot;
|
||||
t = DataBucketLoadType::Bot;
|
||||
}
|
||||
else if (IsClient()) {
|
||||
id = CastToClient()->CharacterID();
|
||||
t = DataBucketLoadType::Client;
|
||||
t = DataBucketLoadType::Client;
|
||||
}
|
||||
|
||||
DataBucket::DeleteFromCache(id, t);
|
||||
|
||||
@ -201,9 +201,11 @@ public:
|
||||
|
||||
void DisplayInfo(Mob *mob);
|
||||
|
||||
std::unordered_map<uint16, Mob *> m_close_mobs;
|
||||
Timer m_scan_close_mobs_timer;
|
||||
Timer m_mob_check_moving_timer;
|
||||
std::unordered_map<uint16, Mob *> m_close_mobs;
|
||||
std::unordered_map<int, glm::vec4> m_last_seen_mob_position;
|
||||
Timer m_scan_close_mobs_timer;
|
||||
Timer m_see_close_mobs_timer;
|
||||
Timer m_mob_check_moving_timer;
|
||||
|
||||
// Bot attack flag
|
||||
Timer bot_attack_flag_timer;
|
||||
|
||||
@ -851,12 +851,24 @@ void MobMovementManager::SendCommandToClients(
|
||||
_impl->Stats.TotalSentPosition++;
|
||||
}
|
||||
|
||||
if (c->m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (c->m_last_seen_mob_position[mob->GetID()] == mob->GetPosition() && anim == 0) {
|
||||
LogPositionUpdate(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
c->GetCleanName()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c->QueuePacket(&outapp, false);
|
||||
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||
}
|
||||
}
|
||||
else {
|
||||
float short_range = RuleR(Pathing, ShortMovementUpdateRange);
|
||||
float long_range = zone->GetNpcPositionUpdateDistance();
|
||||
float long_range = RuleI(Range, MobCloseScanDistance);
|
||||
|
||||
for (auto &c : _impl->Clients) {
|
||||
if (single_client && c != single_client) {
|
||||
@ -901,7 +913,19 @@ void MobMovementManager::SendCommandToClients(
|
||||
_impl->Stats.TotalSentPosition++;
|
||||
}
|
||||
|
||||
if (c->m_last_seen_mob_position.contains(mob->GetID())) {
|
||||
if (c->m_last_seen_mob_position[mob->GetID()] == mob->GetPosition() && anim == 0) {
|
||||
LogPositionUpdate(
|
||||
"Mob [{}] has already been sent to client [{}] at this position, skipping",
|
||||
mob->GetCleanName(),
|
||||
c->GetCleanName()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c->QueuePacket(&outapp, false);
|
||||
c->m_last_seen_mob_position[mob->GetID()] = mob->GetPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -997,8 +997,8 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4
|
||||
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
npc_type->race = 127;
|
||||
npc_type->gender = 0;
|
||||
npc_type->class_ = 9;
|
||||
npc_type->deity = 1;
|
||||
npc_type->level = 200;
|
||||
|
||||
@ -7378,15 +7378,17 @@ void Mob::SetHP(int64 hp)
|
||||
|
||||
void Mob::DrawDebugCoordinateNode(std::string node_name, const glm::vec4 vec)
|
||||
{
|
||||
NPC *node = nullptr;
|
||||
NPC *node = nullptr;
|
||||
|
||||
for (const auto &n: entity_list.GetNPCList()) {
|
||||
if (n.second->GetCleanName() == node_name) {
|
||||
if (n.second->GetEntityVariable("node_parent_id") == std::to_string(GetID())) {
|
||||
node = n.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
node = NPC::SpawnNodeNPC(node_name, "", GetPosition());
|
||||
node->SetEntityVariable("node_parent_id", std::to_string(GetID()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1091,7 +1091,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
|
||||
mMovementManager = &MobMovementManager::Get();
|
||||
|
||||
SetNpcPositionUpdateDistance(0);
|
||||
SetQuestHotReloadQueued(false);
|
||||
}
|
||||
|
||||
@ -1374,17 +1373,17 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_version)
|
||||
newzone_data.suspend_buffs = z->suspendbuffs;
|
||||
|
||||
// local attributes
|
||||
can_bind = z->canbind != 0;
|
||||
is_city = z->canbind == 2;
|
||||
can_combat = z->cancombat != 0;
|
||||
can_levitate = z->canlevitate != 0;
|
||||
can_castoutdoor = z->castoutdoor != 0;
|
||||
is_hotzone = z->hotzone != 0;
|
||||
max_movement_update_range = z->max_movement_update_range;
|
||||
default_ruleset = z->ruleset;
|
||||
allow_mercs = true;
|
||||
m_graveyard_id = z->graveyard_id;
|
||||
m_max_clients = z->maxclients;
|
||||
can_bind = z->canbind != 0;
|
||||
is_city = z->canbind == 2;
|
||||
can_combat = z->cancombat != 0;
|
||||
can_levitate = z->canlevitate != 0;
|
||||
can_castoutdoor = z->castoutdoor != 0;
|
||||
is_hotzone = z->hotzone != 0;
|
||||
m_client_update_range = z->client_update_range;
|
||||
default_ruleset = z->ruleset;
|
||||
allow_mercs = true;
|
||||
m_graveyard_id = z->graveyard_id;
|
||||
m_max_clients = z->maxclients;
|
||||
|
||||
SetIdleWhenEmpty(z->idle_when_empty);
|
||||
SetSecondsBeforeIdle(z->seconds_before_idle);
|
||||
@ -1538,10 +1537,6 @@ bool Zone::Process() {
|
||||
if (adv_data && !did_adventure_actions) {
|
||||
DoAdventureActions();
|
||||
}
|
||||
|
||||
if (GetNpcPositionUpdateDistance() == 0) {
|
||||
CalculateNpcUpdateDistanceSpread();
|
||||
}
|
||||
}
|
||||
|
||||
if (hot_reload_timer.Check() && IsQuestHotReloadQueued()) {
|
||||
@ -2735,62 +2730,6 @@ void Zone::SetUCSServerAvailable(bool ucss_available, uint32 update_timestamp) {
|
||||
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
|
||||
{
|
||||
return quest_hot_reload_queued;
|
||||
|
||||
@ -156,9 +156,6 @@ public:
|
||||
bool SaveZoneCFG();
|
||||
bool DoesAlternateCurrencyExist(uint32 currency_id);
|
||||
|
||||
int GetNpcPositionUpdateDistance() const;
|
||||
void SetNpcPositionUpdateDistance(int in_npc_position_update_distance);
|
||||
|
||||
char *adv_data;
|
||||
|
||||
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
||||
@ -417,7 +414,7 @@ public:
|
||||
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
|
||||
};
|
||||
|
||||
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
||||
double GetClientUpdateRange() const { return m_client_update_range; }
|
||||
|
||||
void SetIsHotzone(bool is_hotzone);
|
||||
|
||||
@ -469,7 +466,7 @@ private:
|
||||
bool staticzone;
|
||||
bool zone_has_current_time;
|
||||
bool quest_hot_reload_queued;
|
||||
double max_movement_update_range;
|
||||
double m_client_update_range;
|
||||
char *long_name;
|
||||
char *map_name;
|
||||
char *short_name;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user