[Code Cleanup] Optimization Code Cleanup (#4489)

* Initial push

* More

* More

* Further simplify

* More cleanup

* More consolidation

* Fix

* Update

* Update npc.cpp

---------

Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
Chris Miles 2024-09-30 17:34:42 -05:00 committed by GitHub
parent 56608e84bd
commit bcd943a964
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 309 additions and 486 deletions

View File

@ -1739,7 +1739,7 @@ bool Mob::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
(HasOwner() && GetOwner()->IsClient() && other->IsClient()) (HasOwner() && GetOwner()->IsClient() && other->IsClient())
) )
) { ) {
for (auto const& [id, mob] : entity_list.GetCloseMobList(other)) { for (auto const& [id, mob] : other->GetCloseMobList()) {
if (!mob) { if (!mob) {
continue; continue;
} }
@ -2319,8 +2319,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
//Guard Assist Code //Guard Assist Code
if (RuleB(Character, PVPEnableGuardFactionAssist)) { if (RuleB(Character, PVPEnableGuardFactionAssist)) {
if (IsClient() && other->IsClient() || (HasOwner() && GetOwner()->IsClient() && other->IsClient())) { if (IsClient() && other->IsClient() || (HasOwner() && GetOwner()->IsClient() && other->IsClient())) {
auto& mob_list = entity_list.GetCloseMobList(other); for (auto& e : other->GetCloseMobList()) {
for (auto& e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -2973,8 +2972,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.UnMarkNPC(GetID()); entity_list.UnMarkNPC(GetID());
entity_list.RemoveNPC(GetID()); entity_list.RemoveNPC(GetID());
// entity_list.RemoveMobFromCloseLists(this); m_close_mobs.clear();
close_mobs.clear();
SetID(0); SetID(0);
ApplyIllusionToCorpse(illusion_spell_id, corpse); ApplyIllusionToCorpse(illusion_spell_id, corpse);

View File

@ -72,7 +72,7 @@ Mob *Aura::GetOwner()
// not 100% sure how this one should work and PVP affects ... // not 100% sure how this one should work and PVP affects ...
void Aura::ProcessOnAllFriendlies(Mob *owner) void Aura::ProcessOnAllFriendlies(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this, distance); auto &mob_list = GetCloseMobList(distance);
std::set<int> delayed_remove; std::set<int> delayed_remove;
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
@ -127,7 +127,7 @@ void Aura::ProcessOnAllFriendlies(Mob *owner)
void Aura::ProcessOnAllGroupMembers(Mob *owner) void Aura::ProcessOnAllGroupMembers(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this, distance); auto &mob_list = GetCloseMobList(distance);
std::set<int> delayed_remove; std::set<int> delayed_remove;
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
@ -369,7 +369,7 @@ void Aura::ProcessOnAllGroupMembers(Mob *owner)
void Aura::ProcessOnGroupMembersPets(Mob *owner) void Aura::ProcessOnGroupMembersPets(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this,distance); auto &mob_list = GetCloseMobList(distance);
std::set<int> delayed_remove; std::set<int> delayed_remove;
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
// This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura) // This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura)
@ -576,7 +576,7 @@ void Aura::ProcessOnGroupMembersPets(Mob *owner)
void Aura::ProcessTotem(Mob *owner) void Aura::ProcessTotem(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this, distance); auto &mob_list = GetCloseMobList(distance);
std::set<int> delayed_remove; std::set<int> delayed_remove;
bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
@ -634,9 +634,7 @@ void Aura::ProcessTotem(Mob *owner)
void Aura::ProcessEnterTrap(Mob *owner) void Aura::ProcessEnterTrap(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this, distance); for (auto &e : GetCloseMobList(distance)) {
for (auto &e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -656,9 +654,7 @@ void Aura::ProcessEnterTrap(Mob *owner)
void Aura::ProcessExitTrap(Mob *owner) void Aura::ProcessExitTrap(Mob *owner)
{ {
auto &mob_list = entity_list.GetCloseMobList(this, distance); for (auto &e : GetCloseMobList(distance)) {
for (auto &e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -689,8 +685,7 @@ void Aura::ProcessExitTrap(Mob *owner)
// and hard to reason about // and hard to reason about
void Aura::ProcessSpawns() void Aura::ProcessSpawns()
{ {
const auto &clients = entity_list.GetCloseMobList(this, distance); for (auto &e: GetCloseMobList(distance)) {
for (auto &e : clients) {
if (!e.second) { if (!e.second) {
continue; continue;
} }

View File

@ -1578,17 +1578,7 @@ bool Bot::Process()
return false; return false;
} }
if (mob_close_scan_timer.Check()) { ScanCloseMobProcess();
LogAIScanCloseDetail(
"is_moving [{}] bot [{}] timer [{}]",
moving ? "true" : "false",
GetCleanName(),
mob_close_scan_timer.GetDuration()
);
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
}
SpellProcess(); SpellProcess();
if (tic_timer.Check()) { if (tic_timer.Check()) {

View File

@ -145,49 +145,48 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
0, // in_heroic_strikethrough 0, // in_heroic_strikethrough
false // in_keeps_sold_items false // in_keeps_sold_items
), ),
hpupdate_timer(2000), hpupdate_timer(2000),
camp_timer(29000), camp_timer(29000),
process_timer(100), process_timer(100),
consume_food_timer(CONSUMPTION_TIMER), consume_food_timer(CONSUMPTION_TIMER),
zoneinpacket_timer(1000), zoneinpacket_timer(1000),
linkdead_timer(RuleI(Zone,ClientLinkdeadMS)), linkdead_timer(RuleI(Zone, ClientLinkdeadMS)),
dead_timer(2000), dead_timer(2000),
global_channel_timer(1000), global_channel_timer(1000),
fishing_timer(8000), fishing_timer(8000),
endupkeep_timer(1000), endupkeep_timer(1000),
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000), autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)), m_client_npc_aggro_scan_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
client_zone_wide_full_position_update_timer(5 * 60 * 1000), m_client_zone_wide_full_position_update_timer(5 * 60 * 1000),
tribute_timer(Tribute_duration), tribute_timer(Tribute_duration),
proximity_timer(ClientProximity_interval), proximity_timer(ClientProximity_interval),
TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000), TaskPeriodic_Timer(RuleI(TaskSystem, PeriodicCheckTimer) * 1000),
charm_update_timer(6000), charm_update_timer(6000),
rest_timer(1), rest_timer(1),
pick_lock_timer(1000), pick_lock_timer(1000),
charm_class_attacks_timer(3000), charm_class_attacks_timer(3000),
charm_cast_timer(3500), charm_cast_timer(3500),
qglobal_purge_timer(30000), qglobal_purge_timer(30000),
TrackingTimer(2000), TrackingTimer(2000),
RespawnFromHoverTimer(0), RespawnFromHoverTimer(0),
merc_timer(RuleI(Mercs, UpkeepIntervalMS)), merc_timer(RuleI(Mercs, UpkeepIntervalMS)),
ItemQuestTimer(500), ItemQuestTimer(500),
anon_toggle_timer(250), anon_toggle_timer(250),
afk_toggle_timer(250), afk_toggle_timer(250),
helm_toggle_timer(250), helm_toggle_timer(250),
aggro_meter_timer(AGGRO_METER_UPDATE_MS), aggro_meter_timer(AGGRO_METER_UPDATE_MS),
m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number
m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f,-2.0f), m_ZoneSummonLocation(-2.0f, -2.0f, -2.0f, -2.0f),
m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f), m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f),
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f), m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
last_region_type(RegionTypeUnsupported), last_region_type(RegionTypeUnsupported),
m_dirtyautohaters(false), m_dirtyautohaters(false),
mob_close_scan_timer(6000), m_position_update_timer(10000),
position_update_timer(10000), consent_throttle_timer(2000),
consent_throttle_timer(2000), tmSitting(0),
tmSitting(0), parcel_timer(RuleI(Parcel, ParcelDeliveryDelay)),
parcel_timer(RuleI(Parcel, ParcelDeliveryDelay)), lazy_load_bank_check_timer(1000),
lazy_load_bank_check_timer(1000), bandolier_throttle_timer(0)
bandolier_throttle_timer(0)
{ {
for (auto client_filter = FilterNone; client_filter < _FilterCount; client_filter = eqFilterType(client_filter + 1)) { for (auto client_filter = FilterNone; client_filter < _FilterCount; client_filter = eqFilterType(client_filter + 1)) {
SetFilter(client_filter, FilterShow); SetFilter(client_filter, FilterShow);
@ -446,7 +445,7 @@ Client::~Client() {
m_tradeskill_object = nullptr; m_tradeskill_object = nullptr;
} }
close_mobs.clear(); m_close_mobs.clear();
if(IsDueling() && GetDuelTarget() != 0) { if(IsDueling() && GetDuelTarget() != 0) {
Entity* entity = entity_list.GetID(GetDuelTarget()); Entity* entity = entity_list.GetID(GetDuelTarget());
@ -9253,19 +9252,6 @@ bool Client::GotoPlayerRaid(const std::string& player_name)
return true; return true;
} }
glm::vec4 &Client::GetLastPositionBeforeBulkUpdate()
{
return last_position_before_bulk_update;
}
/**
* @param in_last_position_before_bulk_update
*/
void Client::SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update)
{
Client::last_position_before_bulk_update = in_last_position_before_bulk_update;
}
void Client::SendToGuildHall() void Client::SendToGuildHall()
{ {
std::string zone_short_name = "guildhall"; std::string zone_short_name = "guildhall";
@ -12749,3 +12735,98 @@ 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()
{
float distance_moved = DistanceNoZ(m_last_position_before_bulk_update, GetPosition());
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
bool is_ready_to_update = (
m_client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
);
if (IsMoving() && is_ready_to_update) {
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
auto &mob_movement_manager = MobMovementManager::Get();
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
int animation_speed = 0;
if (entity->IsMoving()) {
if (entity->IsRunning()) {
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
}
else {
animation_speed = entity->GetWalkspeed();
}
}
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
}
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);
void Client::CheckClientToNpcAggroTimer()
{
LogAggroDetail(
"ClientUpdate [{}] {}moving, scan timer [{}]",
GetCleanName(),
IsMoving() ? "" : "NOT ",
m_client_npc_aggro_scan_timer.GetRemainingTime()
);
if (IsMoving()) {
if (m_client_npc_aggro_scan_timer.GetRemainingTime() > scan_npc_aggro_timer_moving) {
LogAggroDetail("Client [{}] Restarting with moving timer", GetCleanName());
m_client_npc_aggro_scan_timer.Disable();
m_client_npc_aggro_scan_timer.Start(scan_npc_aggro_timer_moving);
m_client_npc_aggro_scan_timer.Trigger();
}
}
else if (m_client_npc_aggro_scan_timer.GetDuration() == scan_npc_aggro_timer_moving) {
LogAggroDetail("Client [{}] Restarting with idle timer", GetCleanName());
m_client_npc_aggro_scan_timer.Disable();
m_client_npc_aggro_scan_timer.Start(scan_npc_aggro_timer_idle);
}
}
void Client::ClientToNpcAggroProcess()
{
if (zone->CanDoCombat() && !GetFeigned() && m_client_npc_aggro_scan_timer.Check()) {
int npc_scan_count = 0;
for (auto &close_mob: GetCloseMobList()) {
Mob *mob = close_mob.second;
if (!mob) {
continue;
}
if (mob->IsClient()) {
continue;
}
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
mob->AddToHateList(this, 25);
}
npc_scan_count++;
}
LogAggro("Checking Reverse Aggro (client->npc) scanned_npcs ([{}])", npc_scan_count);
}
}

View File

@ -1794,9 +1794,6 @@ public:
uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns. uint32 trapid; //ID of trap player has triggered. This is cleared when the player leaves the trap's radius, or it despawns.
void SetLastPositionBeforeBulkUpdate(glm::vec4 in_last_position_before_bulk_update);
glm::vec4 &GetLastPositionBeforeBulkUpdate();
Raid *p_raid_instance; Raid *p_raid_instance;
void ShowDevToolsMenu(); void ShowDevToolsMenu();
@ -2033,8 +2030,6 @@ private:
Timer fishing_timer; Timer fishing_timer;
Timer endupkeep_timer; Timer endupkeep_timer;
Timer autosave_timer; Timer autosave_timer;
Timer client_scan_npc_aggro_timer;
Timer client_zone_wide_full_position_update_timer;
Timer tribute_timer; Timer tribute_timer;
Timer proximity_timer; Timer proximity_timer;
@ -2051,8 +2046,6 @@ private:
Timer afk_toggle_timer; Timer afk_toggle_timer;
Timer helm_toggle_timer; Timer helm_toggle_timer;
Timer aggro_meter_timer; Timer aggro_meter_timer;
Timer mob_close_scan_timer;
Timer position_update_timer; /* Timer used when client hasn't updated within a 10 second window */
Timer consent_throttle_timer; Timer consent_throttle_timer;
Timer dynamiczone_removal_timer; Timer dynamiczone_removal_timer;
Timer task_request_timer; Timer task_request_timer;
@ -2065,7 +2058,17 @@ private:
int m_lazy_load_sent_bank_slots = 0; int m_lazy_load_sent_bank_slots = 0;
glm::vec3 m_Proximity; glm::vec3 m_Proximity;
glm::vec4 last_position_before_bulk_update;
// client aggro
Timer m_client_npc_aggro_scan_timer;
void CheckClientToNpcAggroTimer();
void ClientToNpcAggroProcess();
// bulk position updates
glm::vec4 m_last_position_before_bulk_update;
Timer m_client_zone_wide_full_position_update_timer;
Timer m_position_update_timer;
void CheckSendBulkClientPositionUpdate();
void BulkSendInventoryItems(); void BulkSendInventoryItems();

View File

@ -794,7 +794,7 @@ void Client::CompleteConnect()
// sent to a succor point // sent to a succor point
SendMobPositions(); SendMobPositions();
SetLastPositionBeforeBulkUpdate(GetPosition()); m_last_position_before_bulk_update = GetPosition();
/* This sub event is for if a player logs in for the first time since entering world. */ /* This sub event is for if a player logs in for the first time since entering world. */
if (firstlogon == 1) { if (firstlogon == 1) {
@ -940,7 +940,7 @@ void Client::CompleteConnect()
worldserver.RequestTellQueue(GetName()); worldserver.RequestTellQueue(GetName());
entity_list.ScanCloseMobs(close_mobs, this, true); entity_list.ScanCloseMobs(this);
if (GetGM() && IsDevToolsEnabled()) { if (GetGM() && IsDevToolsEnabled()) {
ShowDevToolsMenu(); ShowDevToolsMenu();
@ -5012,103 +5012,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) {
SetMoving(!(cy == m_Position.y && cx == m_Position.x)); SetMoving(!(cy == m_Position.y && cx == m_Position.x));
/** CheckClientToNpcAggroTimer();
* Client aggro scanning CheckScanCloseMobsMovingTimer();
*/ CheckSendBulkClientPositionUpdate();
const uint16 client_scan_npc_aggro_timer_idle = RuleI(Aggro, ClientAggroCheckIdleInterval);
const uint16 client_scan_npc_aggro_timer_moving = RuleI(Aggro, ClientAggroCheckMovingInterval);
LogAggroDetail(
"ClientUpdate [{}] {}moving, scan timer [{}]",
GetCleanName(),
IsMoving() ? "" : "NOT ",
client_scan_npc_aggro_timer.GetRemainingTime()
);
if (IsMoving()) {
if (client_scan_npc_aggro_timer.GetRemainingTime() > client_scan_npc_aggro_timer_moving) {
LogAggroDetail("Client [{}] Restarting with moving timer", GetCleanName());
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_moving);
client_scan_npc_aggro_timer.Trigger();
}
}
else if (client_scan_npc_aggro_timer.GetDuration() == client_scan_npc_aggro_timer_moving) {
LogAggroDetail("Client [{}] Restarting with idle timer", GetCleanName());
client_scan_npc_aggro_timer.Disable();
client_scan_npc_aggro_timer.Start(client_scan_npc_aggro_timer_idle);
}
/**
* Client mob close list cache scan timer
*/
const uint16 client_mob_close_scan_timer_moving = 6000;
const uint16 client_mob_close_scan_timer_idle = 60000;
LogAIScanCloseDetail(
"Client [{}] {}moving, scan timer [{}]",
GetCleanName(),
IsMoving() ? "" : "NOT ",
mob_close_scan_timer.GetRemainingTime()
);
if (IsMoving()) {
if (mob_close_scan_timer.GetRemainingTime() > client_mob_close_scan_timer_moving) {
LogAIScanCloseDetail("Client [{}] Restarting with moving timer", GetCleanName());
mob_close_scan_timer.Disable();
mob_close_scan_timer.Start(client_mob_close_scan_timer_moving);
mob_close_scan_timer.Trigger();
}
}
else if (mob_close_scan_timer.GetDuration() == client_mob_close_scan_timer_moving) {
LogAIScanCloseDetail("Client [{}] Restarting with idle timer", GetCleanName());
mob_close_scan_timer.Disable();
mob_close_scan_timer.Start(client_mob_close_scan_timer_idle);
}
/**
* 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
*/
float distance_moved = DistanceNoZ(GetLastPositionBeforeBulkUpdate(), GetPosition());
bool moved_far_enough_before_bulk_update = distance_moved >= zone->GetNpcPositionUpdateDistance();
bool is_ready_to_update = (
client_zone_wide_full_position_update_timer.Check() || moved_far_enough_before_bulk_update
);
if (IsMoving() && is_ready_to_update) {
LogDebug("[[{}]] Client Zone Wide Position Update NPCs", GetCleanName());
auto &mob_movement_manager = MobMovementManager::Get();
auto &mob_list = entity_list.GetMobList();
for (auto &it : mob_list) {
Mob *entity = it.second;
if (!entity->IsNPC()) {
continue;
}
int animation_speed = 0;
if (entity->IsMoving()) {
if (entity->IsRunning()) {
animation_speed = (entity->IsFeared() ? entity->GetFearSpeed() : entity->GetRunspeed());
}
else {
animation_speed = entity->GetWalkspeed();
}
}
mob_movement_manager.SendCommandToClients(entity, 0.0, 0.0, 0.0, 0.0, animation_speed, ClientRangeAny, this);
}
SetLastPositionBeforeBulkUpdate(GetPosition());
}
int32 new_animation = ppu->animation; int32 new_animation = ppu->animation;

View File

@ -121,7 +121,7 @@ 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() && position_update_timer.Check()) { if (!IsMoving() && m_position_update_timer.Check()) {
SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0); SentPositionPacket(0.0f, 0.0f, 0.0f, 0.0f, 0);
} }
@ -281,13 +281,7 @@ bool Client::Process() {
} }
} }
/** ScanCloseMobProcess();
* Scan close range mobs
* Used in aggro checks
*/
if (mob_close_scan_timer.Check()) {
entity_list.ScanCloseMobs(close_mobs, this, IsMoving());
}
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
@ -608,30 +602,7 @@ bool Client::Process() {
} }
} }
//At this point, we are still connected, everything important has taken ClientToNpcAggroProcess();
//place, now check to see if anybody wants to aggro us.
// only if client is not feigned
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
int npc_scan_count = 0;
for (auto & close_mob : close_mobs) {
Mob *mob = close_mob.second;
if (!mob) {
continue;
}
if (mob->IsClient()) {
continue;
}
if (mob->CheckWillAggro(this) && !mob->CheckAggro(this)) {
mob->AddToHateList(this, 25);
}
npc_scan_count++;
}
LogAggro("Checking Reverse Aggro (client->npc) scanned_npcs ([{}])", npc_scan_count);
}
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED))) if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
{ {

View File

@ -1036,7 +1036,7 @@ void EntityList::AETaunt(Client* taunter, float range, int bonus_hate)
float range_squared = range * range; float range_squared = range * range;
for (auto& it: entity_list.GetCloseMobList(taunter, range)) { for (auto& it: taunter->GetCloseMobList(range)) {
Mob *them = it.second; Mob *them = it.second;
if (!them) { if (!them) {
continue; continue;
@ -1120,7 +1120,7 @@ void EntityList::AESpell(
distance distance
); );
for (auto& it: entity_list.GetCloseMobList(caster_mob, distance)) { for (auto& it: caster_mob->GetCloseMobList(distance)) {
current_mob = it.second; current_mob = it.second;
if (!current_mob) { if (!current_mob) {
continue; continue;
@ -1256,7 +1256,7 @@ void EntityList::MassGroupBuff(
float distance_squared = distance * distance; float distance_squared = distance * distance;
bool is_detrimental_spell = IsDetrimentalSpell(spell_id); bool is_detrimental_spell = IsDetrimentalSpell(spell_id);
for (auto& it: entity_list.GetCloseMobList(caster, distance)) { for (auto& it: caster->GetCloseMobList(distance)) {
current_mob = it.second; current_mob = it.second;
if (!current_mob) { if (!current_mob) {
continue; continue;
@ -1306,7 +1306,7 @@ void EntityList::AEAttack(
float distance_squared = distance * distance; float distance_squared = distance * distance;
int current_hits = 0; int current_hits = 0;
for (auto& it: entity_list.GetCloseMobList(attacker, distance)) { for (auto& it: attacker->GetCloseMobList(distance)) {
current_mob = it.second; current_mob = it.second;
if (!current_mob) { if (!current_mob) {
continue; continue;

View File

@ -696,7 +696,7 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue)
npc_list.emplace(std::pair<uint16, NPC *>(npc->GetID(), npc)); npc_list.emplace(std::pair<uint16, NPC *>(npc->GetID(), npc));
mob_list.emplace(std::pair<uint16, Mob *>(npc->GetID(), npc)); mob_list.emplace(std::pair<uint16, Mob *>(npc->GetID(), npc));
entity_list.ScanCloseMobs(npc->close_mobs, npc, true); entity_list.ScanCloseMobs(npc);
if (parse->HasQuestSub(npc->GetNPCTypeID(), EVENT_SPAWN)) { if (parse->HasQuestSub(npc->GetNPCTypeID(), EVENT_SPAWN)) {
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
@ -1742,8 +1742,7 @@ void EntityList::QueueCloseClients(
} }
float distance_squared = distance * distance; float distance_squared = distance * distance;
for (auto &e : sender->GetCloseMobList(distance)) {
for (auto &e : GetCloseMobList(sender, distance)) {
Mob *mob = e.second; Mob *mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -2886,7 +2885,7 @@ bool EntityList::RemoveMobFromCloseLists(Mob *mob)
entity_id entity_id
); );
it->second->close_mobs.erase(entity_id); it->second->m_close_mobs.erase(entity_id);
++it; ++it;
} }
@ -2911,49 +2910,40 @@ void EntityList::RemoveAuraFromMobs(Mob *aura)
} }
} }
/** // The purpose of this system is so that we cache relevant entities that are "close"
* The purpose of this system is so that we cache relevant entities that are "close" //
* // In general; it becomes incredibly expensive to run zone-wide checks against every single mob in the zone when in reality
* In general; it becomes incredibly expensive to run zone-wide checks against every single mob in the zone when in reality // we only care about entities closest to us
* we only care about entities closest to us //
* // A very simple example of where this is relevant is Aggro, the below example is skewed because the overall implementation
* A very simple example of where this is relevant is Aggro, the below example is skewed because the overall implementation // of Aggro was also tweaked in conjunction with close lists. We also scan more aggressively when entities are moving (1-6 seconds)
* of Aggro was also tweaked in conjunction with close lists. We also scan more aggressively when entities are moving (1-6 seconds) // versus 60 seconds when idle. We also have entities that are moving add themselves to those closest to them so that their close
* versus 60 seconds when idle. We also have entities that are moving add themselves to those closest to them so that their close // lists remain always up to date
* lists remain always up to date //
* // Before: Aggro checks for NPC to Client aggro | (40 clients in zone) x (525 npcs) x 2 (times a second) = 2,520,000 checks a minute
* Before: Aggro checks for NPC to Client aggro | (40 clients in zone) x (525 npcs) x 2 (times a second) = 2,520,000 checks a minute // After: Aggro checks for NPC to Client aggro | (40 clients in zone) x (20-30 npcs) x 2 (times a second) = 144,000 checks a minute (This is // tually far less today)
* After: Aggro checks for NPC to Client aggro | (40 clients in zone) x (20-30 npcs) x 2 (times a second) = 144,000 checks a minute (This is actually far less today) //
* // Places in the code where this logic makes a huge impact
* Places in the code where this logic makes a huge impact //
* // Aggro checks (zone wide -> close)
* Aggro checks (zone wide -> close) // Aura processing (zone wide -> close)
* Aura processing (zone wide -> close) // AE Taunt (zone wide -> close)
* AE Taunt (zone wide -> close) // AOE Spells (zone wide -> close)
* AOE Spells (zone wide -> close) // Bard Pulse AOE (zone wide -> close)
* Bard Pulse AOE (zone wide -> close) // Mass Group Buff (zone wide -> close)
* Mass Group Buff (zone wide -> close) // AE Attack (zone wide -> close)
* AE Attack (zone wide -> close) // Packet QueueCloseClients (zone wide -> close)
* Packet QueueCloseClients (zone wide -> close) // Check Close Beneficial Spells (Buffs; should I heal other npcs) (zone wide -> close)
* Check Close Beneficial Spells (Buffs; should I heal other npcs) (zone wide -> close) // AI Yell for Help (NPC Assist other NPCs) (zone wide -> close)
* AI Yell for Help (NPC Assist other NPCs) (zone wide -> close) //
* // 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) void EntityList::ScanCloseMobs(Mob *scanning_mob)
*
* @param close_mobs
* @param scanning_mob
*/
void EntityList::ScanCloseMobs(
std::unordered_map<uint16, Mob *> &close_mobs,
Mob *scanning_mob,
bool add_self_to_other_lists
)
{ {
float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance); float scan_range = RuleI(Range, MobCloseScanDistance) * RuleI(Range, MobCloseScanDistance);
close_mobs.clear(); scanning_mob->m_close_mobs.clear();
for (auto &e : mob_list) { for (auto &e : mob_list) {
auto mob = e.second; auto mob = e.second;
@ -2963,12 +2953,13 @@ void EntityList::ScanCloseMobs(
float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition()); float distance = DistanceSquared(scanning_mob->GetPosition(), mob->GetPosition());
if (distance <= scan_range || mob->GetAggroRange() >= scan_range) { if (distance <= scan_range || mob->GetAggroRange() >= scan_range) {
close_mobs.emplace(std::pair<uint16, Mob *>(mob->GetID(), mob)); scanning_mob->m_close_mobs.emplace(std::pair<uint16, Mob *>(mob->GetID(), mob));
if (add_self_to_other_lists && scanning_mob->GetID() > 0) { // add self to other mobs close list
if (scanning_mob->GetID() > 0) {
bool has_mob = false; bool has_mob = false;
for (auto &cm: mob->close_mobs) { for (auto &cm: mob->m_close_mobs) {
if (scanning_mob->GetID() == cm.first) { if (scanning_mob->GetID() == cm.first) {
has_mob = true; has_mob = true;
break; break;
@ -2976,7 +2967,7 @@ void EntityList::ScanCloseMobs(
} }
if (!has_mob) { if (!has_mob) {
mob->close_mobs.insert(std::pair<uint16, Mob *>(scanning_mob->GetID(), scanning_mob)); mob->m_close_mobs.insert(std::pair<uint16, Mob *>(scanning_mob->GetID(), scanning_mob));
} }
} }
} }
@ -2985,7 +2976,7 @@ void EntityList::ScanCloseMobs(
LogAIScanCloseDetail( LogAIScanCloseDetail(
"[{}] Scanning Close List | list_size [{}] moving [{}]", "[{}] Scanning Close List | list_size [{}] moving [{}]",
scanning_mob->GetCleanName(), scanning_mob->GetCleanName(),
close_mobs.size(), scanning_mob->m_close_mobs.size(),
scanning_mob->IsMoving() ? "true" : "false" scanning_mob->IsMoving() ? "true" : "false"
); );
} }
@ -4448,7 +4439,7 @@ void EntityList::QuestJournalledSayClose(
buf.WriteInt32(0); buf.WriteInt32(0);
if (RuleB(Chat, QuestDialogueUsesDialogueWindow)) { if (RuleB(Chat, QuestDialogueUsesDialogueWindow)) {
for (auto &e : GetCloseMobList(sender, (dist * dist))) { for (auto &e : sender->GetCloseMobList(dist)) {
Mob *mob = e.second; Mob *mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -5651,7 +5642,7 @@ std::vector<Mob*> EntityList::GetTargetsForVirusEffect(Mob *spreader, Mob *origi
std::vector<Mob *> spreader_list = {}; std::vector<Mob *> spreader_list = {};
bool is_detrimental_spell = IsDetrimentalSpell(spell_id); bool is_detrimental_spell = IsDetrimentalSpell(spell_id);
for (auto &it : entity_list.GetCloseMobList(spreader, range)) { for (auto &it : spreader->GetCloseMobList(range)) {
Mob *mob = it.second; Mob *mob = it.second;
if (!mob) { if (!mob) {
continue; continue;
@ -5781,7 +5772,7 @@ void EntityList::ReloadMerchants() {
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 <= RuleI(Range, MobCloseScanDistance)) {
return mob->close_mobs; return mob->m_close_mobs;
} }
return mob_list; return mob_list;

View File

@ -566,11 +566,7 @@ public:
void RefreshAutoXTargets(Client *c); void RefreshAutoXTargets(Client *c);
void RefreshClientXTargets(Client *c); void RefreshClientXTargets(Client *c);
void SendAlternateAdvancementStats(); void SendAlternateAdvancementStats();
void ScanCloseMobs( void ScanCloseMobs(Mob *scanning_mob);
std::unordered_map<uint16, Mob *> &close_mobs,
Mob *scanning_mob,
bool add_self_to_other_lists = false
);
void GetTrapInfo(Client* c); void GetTrapInfo(Client* c);
bool IsTrapGroupSpawned(uint32 trap_id, uint8 group); bool IsTrapGroupSpawned(uint32 trap_id, uint8 group);

View File

@ -128,8 +128,8 @@ Mob::Mob(
attack_anim_timer(500), attack_anim_timer(500),
position_update_melee_push_timer(500), position_update_melee_push_timer(500),
hate_list_cleanup_timer(6000), hate_list_cleanup_timer(6000),
mob_close_scan_timer(6000), m_scan_close_mobs_timer(6000),
mob_check_moving_timer(1000), m_mob_check_moving_timer(1000),
bot_attack_flag_timer(10000) bot_attack_flag_timer(10000)
{ {
mMovementManager = &MobMovementManager::Get(); mMovementManager = &MobMovementManager::Get();
@ -517,7 +517,7 @@ Mob::Mob(
m_manual_follow = false; m_manual_follow = false;
mob_close_scan_timer.Trigger(); m_scan_close_mobs_timer.Trigger();
SetCanOpenDoors(true); SetCanOpenDoors(true);
@ -570,7 +570,7 @@ Mob::~Mob()
entity_list.RemoveMobFromCloseLists(this); entity_list.RemoveMobFromCloseLists(this);
entity_list.RemoveAuraFromMobs(this); entity_list.RemoveAuraFromMobs(this);
close_mobs.clear(); m_close_mobs.clear();
LeaveHealRotationTargetPool(); LeaveHealRotationTargetPool();
} }
@ -5017,7 +5017,7 @@ void Mob::Say(const char *format, ...)
int16 distance = 200; int16 distance = 200;
if (RuleB(Chat, QuestDialogueUsesDialogueWindow)) { if (RuleB(Chat, QuestDialogueUsesDialogueWindow)) {
for (auto &e : entity_list.GetCloseMobList(talker, (distance * distance))) { for (auto &e : talker->GetCloseMobList(distance)) {
Mob *mob = e.second; Mob *mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -6176,9 +6176,7 @@ int32 Mob::GetPositionalDmgTakenAmt(Mob *attacker)
void Mob::SetBottomRampageList() void Mob::SetBottomRampageList()
{ {
auto &mob_list = entity_list.GetCloseMobList(this); for (auto &e : GetCloseMobList()) {
for (auto &e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -6203,9 +6201,7 @@ void Mob::SetBottomRampageList()
void Mob::SetTopRampageList() void Mob::SetTopRampageList()
{ {
auto &mob_list = entity_list.GetCloseMobList(this); for (auto &e : GetCloseMobList()) {
for (auto &e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;
@ -8619,7 +8615,7 @@ void Mob::SetExtraHaste(int haste, bool need_to_save)
bool Mob::IsCloseToBanker() bool Mob::IsCloseToBanker()
{ {
for (auto &e: entity_list.GetCloseMobList(this)) { for (auto &e: GetCloseMobList()) {
auto mob = e.second; auto mob = e.second;
if (mob && mob->IsNPC() && mob->GetClass() == Class::Banker) { if (mob && mob->IsNPC() && mob->GetClass() == Class::Banker) {
return true; return true;
@ -8648,3 +8644,48 @@ bool Mob::HasBotAttackFlag(Mob* tar) {
return false; return false;
} }
const uint16 scan_close_mobs_timer_moving = 6000; // 6 seconds
const uint16 scan_close_mobs_timer_idle = 60000; // 60 seconds
void Mob::CheckScanCloseMobsMovingTimer()
{
LogAIScanCloseDetail(
"Mob [{}] {}moving, scan timer [{}]",
GetCleanName(),
IsMoving() ? "" : "NOT ",
m_scan_close_mobs_timer.GetRemainingTime()
);
// If the moving timer triggers, lets see if we are moving or idle to restart the appropriate
// dynamic timer
if (m_mob_check_moving_timer.Check()) {
// If the mob is still moving, restart the moving timer
if (moving) {
if (m_scan_close_mobs_timer.GetRemainingTime() > scan_close_mobs_timer_moving) {
LogAIScanCloseDetail("Mob [{}] Restarting with moving timer", GetCleanName());
m_scan_close_mobs_timer.Disable();
m_scan_close_mobs_timer.Start(scan_close_mobs_timer_moving);
m_scan_close_mobs_timer.Trigger();
}
}
// If the mob is not moving, restart the idle timer
else if (m_scan_close_mobs_timer.GetDuration() == scan_close_mobs_timer_moving) {
LogAIScanCloseDetail("Mob [{}] Restarting with idle timer", GetCleanName());
m_scan_close_mobs_timer.Disable();
m_scan_close_mobs_timer.Start(scan_close_mobs_timer_idle);
}
}
}
void Mob::ScanCloseMobProcess()
{
if (m_scan_close_mobs_timer.Check()) {
entity_list.ScanCloseMobs(this);
}
}
std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float distance)
{
return entity_list.GetCloseMobList(this, distance);
}

View File

@ -201,9 +201,9 @@ public:
void DisplayInfo(Mob *mob); void DisplayInfo(Mob *mob);
std::unordered_map<uint16, Mob *> close_mobs; std::unordered_map<uint16, Mob *> m_close_mobs;
Timer mob_close_scan_timer; Timer m_scan_close_mobs_timer;
Timer mob_check_moving_timer; Timer m_mob_check_moving_timer;
// Bot attack flag // Bot attack flag
Timer bot_attack_flag_timer; Timer bot_attack_flag_timer;
@ -1487,6 +1487,10 @@ public:
bool IsCloseToBanker(); bool IsCloseToBanker();
void ScanCloseMobProcess();
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
void CheckScanCloseMobsMovingTimer();
protected: protected:
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None); void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index); static uint16 GetProcID(uint16 spell_id, uint8 effect_index);

View File

@ -1391,29 +1391,8 @@ void Mob::AI_Process() {
StopNavigation(); StopNavigation();
} }
} }
else if (zone->CanDoCombat() && CastToNPC()->GetNPCAggro() && AI_scan_area_timer->Check()) { else if (zone->CanDoCombat() && IsNPC() && CastToNPC()->GetNPCAggro() && AI_scan_area_timer->Check()) {
CastToNPC()->DoNpcToNpcAggroScan();
/**
* NPC to NPC aggro (npc_aggro flag set)
*/
for (auto &close_mob : close_mobs) {
Mob *mob = close_mob.second;
if (mob->IsClient()) {
continue;
}
if (CheckWillAggro(mob)) {
AddToHateList(mob);
}
}
AI_scan_area_timer->Disable();
AI_scan_area_timer->Start(
RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)),
false
);
} }
else if (AI_movement_timer->Check() && !IsRooted()) { else if (AI_movement_timer->Check() && !IsRooted()) {
if (IsPet()) { if (IsPet()) {

View File

@ -127,11 +127,6 @@ public:
} }
/**
* @param mob_movement_manager
* @param mob
* @return
*/
virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob) virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
{ {
if (!mob->IsAIControlled()) { if (!mob->IsAIControlled()) {
@ -286,11 +281,6 @@ public:
} }
/**
* @param mob_movement_manager
* @param mob
* @return
*/
virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob) virtual bool Process(MobMovementManager *mob_movement_manager, Mob *mob)
{ {
if (!mob->IsAIControlled()) { if (!mob->IsAIControlled()) {
@ -707,33 +697,21 @@ void MobMovementManager::Process()
} }
} }
/**
* @param mob
*/
void MobMovementManager::AddMob(Mob *mob) void MobMovementManager::AddMob(Mob *mob)
{ {
_impl->Entries.insert(std::make_pair(mob, MobMovementEntry())); _impl->Entries.insert(std::make_pair(mob, MobMovementEntry()));
} }
/**
* @param mob
*/
void MobMovementManager::RemoveMob(Mob *mob) void MobMovementManager::RemoveMob(Mob *mob)
{ {
_impl->Entries.erase(mob); _impl->Entries.erase(mob);
} }
/**
* @param client
*/
void MobMovementManager::AddClient(Client *client) void MobMovementManager::AddClient(Client *client)
{ {
_impl->Clients.push_back(client); _impl->Clients.push_back(client);
} }
/**
* @param client
*/
void MobMovementManager::RemoveClient(Client *client) void MobMovementManager::RemoveClient(Client *client)
{ {
auto iter = _impl->Clients.begin(); auto iter = _impl->Clients.begin();
@ -747,11 +725,6 @@ void MobMovementManager::RemoveClient(Client *client)
} }
} }
/**
* @param who
* @param to
* @param mob_movement_mode
*/
void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode) void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mob_movement_mode)
{ {
auto iter = _impl->Entries.find(who); auto iter = _impl->Entries.find(who);
@ -764,13 +737,6 @@ void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mob_moveme
PushRotateTo(ent.second, who, to, mob_movement_mode); PushRotateTo(ent.second, who, to, mob_movement_mode);
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param heading
*/
void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float heading) void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float heading)
{ {
auto iter = _impl->Entries.find(who); auto iter = _impl->Entries.find(who);
@ -781,13 +747,6 @@ void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float hea
PushTeleportTo(ent.second, x, y, z, heading); PushTeleportTo(ent.second, x, y, z, heading);
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param mode
*/
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode) void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode)
{ {
if (IsPositionEqualWithinCertainZ(glm::vec3(x, y, z), glm::vec3(who->GetX(), who->GetY(), who->GetZ()), 6.0f)) { if (IsPositionEqualWithinCertainZ(glm::vec3(x, y, z), glm::vec3(who->GetX(), who->GetY(), who->GetZ()), 6.0f)) {
@ -824,9 +783,6 @@ void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMove
} }
} }
/**
* @param who
*/
void MobMovementManager::StopNavigation(Mob *who) void MobMovementManager::StopNavigation(Mob *who)
{ {
auto iter = _impl->Entries.find(who); auto iter = _impl->Entries.find(who);
@ -852,16 +808,6 @@ void MobMovementManager::StopNavigation(Mob *who)
PushStopMoving(ent.second); PushStopMoving(ent.second);
} }
/**
* @param mob
* @param delta_x
* @param delta_y
* @param delta_z
* @param delta_heading
* @param anim
* @param range
* @param single_client
*/
void MobMovementManager::SendCommandToClients( void MobMovementManager::SendCommandToClients(
Mob *mob, Mob *mob,
float delta_x, float delta_x,
@ -961,10 +907,6 @@ void MobMovementManager::SendCommandToClients(
} }
} }
/**
* @param in
* @return
*/
float MobMovementManager::FixHeading(float in) float MobMovementManager::FixHeading(float in)
{ {
auto h = in; auto h = in;
@ -979,9 +921,6 @@ float MobMovementManager::FixHeading(float in)
return h; return h;
} }
/**
* @param client
*/
void MobMovementManager::DumpStats(Client *client) void MobMovementManager::DumpStats(Client *client)
{ {
auto current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0; auto current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
@ -1062,13 +1001,6 @@ void MobMovementManager::FillCommandStruct(
} }
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param mob_movement_mode
*/
void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
Mob *target=who->GetTarget(); Mob *target=who->GetTarget();
@ -1114,13 +1046,6 @@ void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMove
} }
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param mode
*/
void MobMovementManager::UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode) void MobMovementManager::UpdatePathGround(Mob *who, float x, float y, float z, MobMovementMode mode)
{ {
PathfinderOptions opts; PathfinderOptions opts;
@ -1253,13 +1178,6 @@ void MobMovementManager::UpdatePathGround(Mob *who, float x, float y, float z, M
} }
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param movement_mode
*/
void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode) void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float z, MobMovementMode movement_mode)
{ {
auto eiter = _impl->Entries.find(who); auto eiter = _impl->Entries.find(who);
@ -1368,13 +1286,6 @@ void MobMovementManager::UpdatePathUnderwater(Mob *who, float x, float y, float
} }
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param mode
*/
void MobMovementManager::UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode) void MobMovementManager::UpdatePathBoat(Mob *who, float x, float y, float z, MobMovementMode mode)
{ {
auto eiter = _impl->Entries.find(who); auto eiter = _impl->Entries.find(who);
@ -1386,48 +1297,21 @@ void MobMovementManager::UpdatePathBoat(Mob *who, float x, float y, float z, Mob
PushStopMoving(ent.second); PushStopMoving(ent.second);
} }
/**
* @param ent
* @param x
* @param y
* @param z
* @param heading
*/
void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading) void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading)
{ {
ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new TeleportToCommand(x, y, z, heading))); ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new TeleportToCommand(x, y, z, heading)));
} }
/**
* @param ent
* @param x
* @param y
* @param z
* @param mob_movement_mode
*/
void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new MoveToCommand(x, y, z, mob_movement_mode))); ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new MoveToCommand(x, y, z, mob_movement_mode)));
} }
/**
* @param ent
* @param x
* @param y
* @param z
* @param mob_movement_mode
*/
void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new SwimToCommand(x, y, z, mob_movement_mode))); ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new SwimToCommand(x, y, z, mob_movement_mode)));
} }
/**
* @param ent
* @param who
* @param to
* @param mob_movement_mode
*/
void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode) void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mob_movement_mode)
{ {
auto from = FixHeading(who->GetHeading()); auto from = FixHeading(who->GetHeading());
@ -1450,41 +1334,21 @@ void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to,
ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode))); ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode)));
} }
/**
* @param ent
* @param x
* @param y
* @param z
* @param mob_movement_mode
*/
void MobMovementManager::PushFlyTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::PushFlyTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new FlyToCommand(x, y, z, mob_movement_mode))); ent.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new FlyToCommand(x, y, z, mob_movement_mode)));
} }
/**
* @param mob_movement_entry
*/
void MobMovementManager::PushStopMoving(MobMovementEntry &mob_movement_entry) void MobMovementManager::PushStopMoving(MobMovementEntry &mob_movement_entry)
{ {
mob_movement_entry.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new StopMovingCommand())); mob_movement_entry.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new StopMovingCommand()));
} }
/**
* @param mob_movement_entry
*/
void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry) void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry)
{ {
mob_movement_entry.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new EvadeCombatCommand())); mob_movement_entry.Commands.emplace_back(std::unique_ptr<IMovementCommand>(new EvadeCombatCommand()));
} }
/**
* @param who
* @param x
* @param y
* @param z
* @param mob_movement_mode
*/
void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode)
{ {
LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, static_cast<int>(mob_movement_mode)); LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, static_cast<int>(mob_movement_mode));

View File

@ -601,28 +601,8 @@ bool NPC::Process()
DepopSwarmPets(); DepopSwarmPets();
} }
if (mob_close_scan_timer.Check()) { ScanCloseMobProcess();
entity_list.ScanCloseMobs(close_mobs, this, IsMoving()); CheckScanCloseMobsMovingTimer();
}
const uint16 npc_mob_close_scan_timer_moving = 6000;
const uint16 npc_mob_close_scan_timer_idle = 60000;
if (mob_check_moving_timer.Check()) {
if (moving) {
if (mob_close_scan_timer.GetRemainingTime() > npc_mob_close_scan_timer_moving) {
LogAIScanCloseDetail("NPC [{}] Restarting with moving timer", GetCleanName());
mob_close_scan_timer.Disable();
mob_close_scan_timer.Start(npc_mob_close_scan_timer_moving);
mob_close_scan_timer.Trigger();
}
}
else if (mob_close_scan_timer.GetDuration() == npc_mob_close_scan_timer_moving) {
LogAIScanCloseDetail("NPC [{}] Restarting with idle timer", GetCleanName());
mob_close_scan_timer.Disable();
mob_close_scan_timer.Start(npc_mob_close_scan_timer_idle);
}
}
if (hp_regen_per_second > 0 && hp_regen_per_second_timer.Check()) { if (hp_regen_per_second > 0 && hp_regen_per_second_timer.Check()) {
if (GetHP() < GetMaxHP()) { if (GetHP() < GetMaxHP()) {
@ -3327,7 +3307,7 @@ bool NPC::AICheckCloseBeneficialSpells(
/** /**
* Check through close range mobs * Check through close range mobs
*/ */
for (auto & close_mob : entity_list.GetCloseMobList(caster, cast_range)) { for (auto & close_mob : caster->GetCloseMobList(cast_range)) {
Mob *mob = close_mob.second; Mob *mob = close_mob.second;
if (!mob) { if (!mob) {
continue; continue;
@ -3406,8 +3386,8 @@ void NPC::AIYellForHelp(Mob *sender, Mob *attacker)
GetID() GetID()
); );
for (auto &close_mob : entity_list.GetCloseMobList(sender)) { for (auto &close_mob: sender->GetCloseMobList()) {
Mob *mob = close_mob.second; Mob *mob = close_mob.second;
if (!mob) { if (!mob) {
continue; continue;
} }
@ -4019,3 +3999,27 @@ void NPC::DescribeSpecialAbilities(Client* c)
c->Message(Chat::White, e.c_str()); c->Message(Chat::White, e.c_str());
} }
} }
void NPC::DoNpcToNpcAggroScan()
{
for (auto &close_mob : GetCloseMobList(GetAggroRange())) {
Mob *mob = close_mob.second;
if (!mob) {
continue;
}
if (!mob->IsNPC()) {
continue;
}
if (CheckWillAggro(mob)) {
AddToHateList(mob);
}
}
AI_scan_area_timer->Disable();
AI_scan_area_timer->Start(
RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)),
false
);
}

View File

@ -557,6 +557,7 @@ public:
bool CanPathTo(float x, float y, float z); bool CanPathTo(float x, float y, float z);
void DoNpcToNpcAggroScan();
protected: protected:
void HandleRoambox(); void HandleRoambox();

View File

@ -2473,8 +2473,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
//Guard Assist Code //Guard Assist Code
if (RuleB(Character, PVPEnableGuardFactionAssist) && spell_target && IsDetrimentalSpell(spell_id) && spell_target != this) { if (RuleB(Character, PVPEnableGuardFactionAssist) && spell_target && IsDetrimentalSpell(spell_id) && spell_target != this) {
if (IsClient() && spell_target->IsClient()|| (HasOwner() && GetOwner()->IsClient() && spell_target->IsClient())) { if (IsClient() && spell_target->IsClient()|| (HasOwner() && GetOwner()->IsClient() && spell_target->IsClient())) {
auto& mob_list = entity_list.GetCloseMobList(spell_target); for (auto& e : spell_target->GetCloseMobList()) {
for (auto& e : mob_list) {
auto mob = e.second; auto mob = e.second;
if (!mob) { if (!mob) {
continue; continue;