mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-08 17:22:30 +00:00
[Performance] Reworked how client to NPC aggro checks are made
- Before when reverse aggro checks were done (client to NPC), checks would happen every 750 millseconds where a client would check an entire entity list with distance calcs and other checks for aggro, with many clients in a zone and many NPC's this would add a lot of unecessary overhead. A temporary adjustment on 3/25 was made and upped the check to 6 seconds. - Now, there is a new methodology to scanning. The client will build a cache list of NPC's within close range as defined in new rule: RULE_INT(Range, ClientNPCScan, 300) and will also get any NPC that has an aggro range beyond that defined range to use in the frequent checks for aggro, the result is far less overhead - Client scanning changes when moving versus not moving, the client will scan aggro every 500 milliseconds while moving, and 3000 millseconds aggro check when not moving, with a 6000ms re-fetch for close NPC's - A demo of these changes can be found here: https://youtu.be/aGroiwLSTVU
This commit is contained in:
parent
940f3b03e8
commit
4b6ce1c19e
@ -1,8 +1,21 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 03/27/2017 ==
|
||||||
|
Akkadius: [Performance] Reworked how client to NPC aggro checks are made
|
||||||
|
- Before when reverse aggro checks were done (client to NPC), checks would happen every 750 millseconds where a client would
|
||||||
|
check an entire entity list with distance calcs and other checks for aggro, with many clients in a zone and many NPC's this would
|
||||||
|
add a lot of unecessary overhead. A temporary adjustment on 3/25 was made and upped the check to 6 seconds.
|
||||||
|
- Now, there is a new methodology to scanning. The client will build a cache list of NPC's within close range as defined in new rule:
|
||||||
|
RULE_INT(Range, ClientNPCScan, 300) and will also get any NPC that has an aggro range beyond that defined range to use in
|
||||||
|
the frequent checks for aggro, the result is far less overhead
|
||||||
|
- Client scanning changes when moving versus not moving, the client will scan aggro every 500 milliseconds while moving, and
|
||||||
|
3000 millseconds aggro check when not moving, with a 6000ms re-fetch for close NPC's
|
||||||
|
- A demo of these changes can be found here:
|
||||||
|
https://youtu.be/aGroiwLSTVU
|
||||||
|
|
||||||
== 03/25/2017 ==
|
== 03/25/2017 ==
|
||||||
Akkadius: Reduced CPU footprint in non-combat zones doing constant checks for combat related activities
|
Akkadius: [Performance] Reduced CPU footprint in non-combat zones doing constant checks for combat related activities
|
||||||
Akkadius: Reduced CPU footprint in cases where a client is checking for aggro excessively every 750 millseconds. This has
|
Akkadius: [Performance] Reduced CPU footprint in cases where a client is checking for aggro excessively every 750 millseconds. This has
|
||||||
been adjusted to 6 seconds per new rule RULE_INT(Aggro, ClientAggroCheckInterval)
|
been adjusted to 6 seconds per new rule RULE_INT(Aggro, ClientAggroCheckInterval)
|
||||||
- When zones have many players, with many NPC's, this adds up quickly
|
- When zones have many players, with many NPC's, this adds up quickly
|
||||||
|
|
||||||
|
|||||||
@ -559,6 +559,7 @@ RULE_INT(Range, SpellMessages, 75)
|
|||||||
RULE_INT(Range, SongMessages, 75)
|
RULE_INT(Range, SongMessages, 75)
|
||||||
RULE_INT(Range, MobPositionUpdates, 600)
|
RULE_INT(Range, MobPositionUpdates, 600)
|
||||||
RULE_INT(Range, CriticalDamage, 80)
|
RULE_INT(Range, CriticalDamage, 80)
|
||||||
|
RULE_INT(Range, ClientNPCScan, 300)
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -284,7 +284,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
|||||||
if(( t1 > iAggroRange)
|
if(( t1 > iAggroRange)
|
||||||
|| ( t2 > iAggroRange)
|
|| ( t2 > iAggroRange)
|
||||||
|| ( t3 > iAggroRange)
|
|| ( t3 > iAggroRange)
|
||||||
||(mob->IsInvisible(this))
|
|| (mob->IsInvisible(this))
|
||||||
|| (mob->IsClient() &&
|
|| (mob->IsClient() &&
|
||||||
(!mob->CastToClient()->Connected()
|
(!mob->CastToClient()->Connected()
|
||||||
|| mob->CastToClient()->IsLD()
|
|| mob->CastToClient()->IsLD()
|
||||||
|
|||||||
@ -135,7 +135,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
forget_timer(0),
|
forget_timer(0),
|
||||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||||
#ifdef REVERSE_AGGRO
|
#ifdef REVERSE_AGGRO
|
||||||
scanarea_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
|
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckInterval) * 1000),
|
||||||
#endif
|
#endif
|
||||||
tribute_timer(Tribute_duration),
|
tribute_timer(Tribute_duration),
|
||||||
proximity_timer(ClientProximity_interval),
|
proximity_timer(ClientProximity_interval),
|
||||||
@ -160,7 +160,8 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
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),
|
||||||
|
npc_close_scan_timer(6000)
|
||||||
{
|
{
|
||||||
for(int cf=0; cf < _FilterCount; cf++)
|
for(int cf=0; cf < _FilterCount; cf++)
|
||||||
ClientFilters[cf] = FilterShow;
|
ClientFilters[cf] = FilterShow;
|
||||||
@ -358,6 +359,8 @@ Client::~Client() {
|
|||||||
m_tradeskill_object = nullptr;
|
m_tradeskill_object = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close_npcs.clear();
|
||||||
|
|
||||||
if(IsDueling() && GetDuelTarget() != 0) {
|
if(IsDueling() && GetDuelTarget() != 0) {
|
||||||
Entity* entity = entity_list.GetID(GetDuelTarget());
|
Entity* entity = entity_list.GetID(GetDuelTarget());
|
||||||
if(entity != nullptr && entity->IsClient()) {
|
if(entity != nullptr && entity->IsClient()) {
|
||||||
|
|||||||
@ -221,6 +221,9 @@ public:
|
|||||||
Client(EQStreamInterface * ieqs);
|
Client(EQStreamInterface * ieqs);
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
|
std::unordered_map<NPC *, float> close_npcs;
|
||||||
|
bool is_client_moving;
|
||||||
|
|
||||||
//abstract virtual function implementations required by base abstract class
|
//abstract virtual function implementations required by base abstract class
|
||||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||||
@ -1458,7 +1461,7 @@ private:
|
|||||||
Timer forget_timer; // our 2 min everybody forgets you timer
|
Timer forget_timer; // our 2 min everybody forgets you timer
|
||||||
Timer autosave_timer;
|
Timer autosave_timer;
|
||||||
#ifdef REVERSE_AGGRO
|
#ifdef REVERSE_AGGRO
|
||||||
Timer scanarea_timer;
|
Timer client_scan_npc_aggro_timer;
|
||||||
#endif
|
#endif
|
||||||
Timer tribute_timer;
|
Timer tribute_timer;
|
||||||
|
|
||||||
@ -1477,6 +1480,7 @@ private:
|
|||||||
Timer helm_toggle_timer;
|
Timer helm_toggle_timer;
|
||||||
Timer light_update_timer;
|
Timer light_update_timer;
|
||||||
Timer aggro_meter_timer;
|
Timer aggro_meter_timer;
|
||||||
|
Timer npc_close_scan_timer;
|
||||||
|
|
||||||
glm::vec3 m_Proximity;
|
glm::vec3 m_Proximity;
|
||||||
|
|
||||||
|
|||||||
@ -4580,6 +4580,34 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
|
|||||||
rewind_timer.Start(30000, true);
|
rewind_timer.Start(30000, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Handle client aggro scanning timers NPCs */
|
||||||
|
is_client_moving = (ppu->y_pos == m_Position.y && ppu->x_pos == m_Position.x) ? false : true;
|
||||||
|
|
||||||
|
if (is_client_moving) {
|
||||||
|
Log.Out(Logs::Detail, Logs::Normal, "ClientUpdate: Client is moving - scan timer is: %u", client_scan_npc_aggro_timer.GetDuration());
|
||||||
|
if (client_scan_npc_aggro_timer.GetDuration() > 1000) {
|
||||||
|
|
||||||
|
npc_close_scan_timer.Disable();
|
||||||
|
npc_close_scan_timer.Start(500);
|
||||||
|
|
||||||
|
client_scan_npc_aggro_timer.Disable();
|
||||||
|
client_scan_npc_aggro_timer.Start(500);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log.Out(Logs::Detail, Logs::Normal, "ClientUpdate: Client is NOT moving - scan timer is: %u", client_scan_npc_aggro_timer.GetDuration());
|
||||||
|
if (client_scan_npc_aggro_timer.GetDuration() < 1000) {
|
||||||
|
|
||||||
|
npc_close_scan_timer.Disable();
|
||||||
|
npc_close_scan_timer.Start(6000);
|
||||||
|
|
||||||
|
client_scan_npc_aggro_timer.Disable();
|
||||||
|
client_scan_npc_aggro_timer.Start(3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Outgoing client packet
|
// Outgoing client packet
|
||||||
float tmpheading = EQ19toFloat(ppu->heading);
|
float tmpheading = EQ19toFloat(ppu->heading);
|
||||||
/* The clients send an update at best every 1.3 seconds
|
/* The clients send an update at best every 1.3 seconds
|
||||||
|
|||||||
@ -63,7 +63,7 @@ extern EntityList entity_list;
|
|||||||
bool Client::Process() {
|
bool Client::Process() {
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
if(Connected() || IsLD())
|
if (Connected() || IsLD())
|
||||||
{
|
{
|
||||||
// try to send all packets that weren't sent before
|
// try to send all packets that weren't sent before
|
||||||
if (!IsLD() && zoneinpacket_timer.Check())
|
if (!IsLD() && zoneinpacket_timer.Check())
|
||||||
@ -71,58 +71,58 @@ bool Client::Process() {
|
|||||||
SendAllPackets();
|
SendAllPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_request_timer)
|
if (adventure_request_timer)
|
||||||
{
|
{
|
||||||
if(adventure_request_timer->Check())
|
if (adventure_request_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_request_timer);
|
safe_delete(adventure_request_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_create_timer)
|
if (adventure_create_timer)
|
||||||
{
|
{
|
||||||
if(adventure_create_timer->Check())
|
if (adventure_create_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_create_timer);
|
safe_delete(adventure_create_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_leave_timer)
|
if (adventure_leave_timer)
|
||||||
{
|
{
|
||||||
if(adventure_leave_timer->Check())
|
if (adventure_leave_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_leave_timer);
|
safe_delete(adventure_leave_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_door_timer)
|
if (adventure_door_timer)
|
||||||
{
|
{
|
||||||
if(adventure_door_timer->Check())
|
if (adventure_door_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_door_timer);
|
safe_delete(adventure_door_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_stats_timer)
|
if (adventure_stats_timer)
|
||||||
{
|
{
|
||||||
if(adventure_stats_timer->Check())
|
if (adventure_stats_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_stats_timer);
|
safe_delete(adventure_stats_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(adventure_leaderboard_timer)
|
if (adventure_leaderboard_timer)
|
||||||
{
|
{
|
||||||
if(adventure_leaderboard_timer->Check())
|
if (adventure_leaderboard_timer->Check())
|
||||||
{
|
{
|
||||||
safe_delete(adventure_leaderboard_timer);
|
safe_delete(adventure_leaderboard_timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dead)
|
if (dead)
|
||||||
{
|
{
|
||||||
SetHP(-100);
|
SetHP(-100);
|
||||||
if(RespawnFromHoverTimer.Check())
|
if (RespawnFromHoverTimer.Check())
|
||||||
HandleRespawnFromHover(0);
|
HandleRespawnFromHover(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,13 +131,13 @@ bool Client::Process() {
|
|||||||
|
|
||||||
// SendHPUpdate calls hpupdate_timer.Start so it can delay this timer, so lets not reset with the check
|
// SendHPUpdate calls hpupdate_timer.Start so it can delay this timer, so lets not reset with the check
|
||||||
// since the function will anyways
|
// since the function will anyways
|
||||||
if(hpupdate_timer.Check(false))
|
if (hpupdate_timer.Check(false))
|
||||||
SendHPUpdate();
|
SendHPUpdate();
|
||||||
|
|
||||||
if(mana_timer.Check())
|
if (mana_timer.Check())
|
||||||
SendManaUpdatePacket();
|
SendManaUpdatePacket();
|
||||||
|
|
||||||
if(dead && dead_timer.Check()) {
|
if (dead && dead_timer.Check()) {
|
||||||
database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId));
|
database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId));
|
||||||
|
|
||||||
m_pp.zone_id = m_pp.binds[0].zoneId;
|
m_pp.zone_id = m_pp.binds[0].zoneId;
|
||||||
@ -150,7 +150,7 @@ bool Client::Process() {
|
|||||||
Group *mygroup = GetGroup();
|
Group *mygroup = GetGroup();
|
||||||
if (mygroup)
|
if (mygroup)
|
||||||
{
|
{
|
||||||
entity_list.MessageGroup(this,true,15,"%s died.", GetName());
|
entity_list.MessageGroup(this, true, 15, "%s died.", GetName());
|
||||||
mygroup->MemberZoned(this);
|
mygroup->MemberZoned(this);
|
||||||
}
|
}
|
||||||
Raid *myraid = entity_list.GetRaidByClient(this);
|
Raid *myraid = entity_list.GetRaidByClient(this);
|
||||||
@ -161,34 +161,29 @@ bool Client::Process() {
|
|||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(charm_update_timer.Check())
|
if (charm_update_timer.Check()) {
|
||||||
{
|
|
||||||
CalcItemScale();
|
CalcItemScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(TaskPeriodic_Timer.Check() && taskstate)
|
if (TaskPeriodic_Timer.Check() && taskstate)
|
||||||
taskstate->TaskPeriodicChecks(this);
|
taskstate->TaskPeriodicChecks(this);
|
||||||
|
|
||||||
if(linkdead_timer.Check())
|
if (linkdead_timer.Check()) {
|
||||||
{
|
|
||||||
LeaveGroup();
|
LeaveGroup();
|
||||||
Save();
|
Save();
|
||||||
if (GetMerc())
|
if (GetMerc()) {
|
||||||
{
|
|
||||||
GetMerc()->Save();
|
GetMerc()->Save();
|
||||||
GetMerc()->Depop();
|
GetMerc()->Depop();
|
||||||
}
|
}
|
||||||
|
|
||||||
Raid *myraid = entity_list.GetRaidByClient(this);
|
Raid *myraid = entity_list.GetRaidByClient(this);
|
||||||
if (myraid)
|
if (myraid) {
|
||||||
{
|
|
||||||
myraid->MemberZoned(this);
|
myraid->MemberZoned(this);
|
||||||
}
|
}
|
||||||
return false; //delete client
|
return false; //delete client
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camp_timer.Check())
|
if (camp_timer.Check()) {
|
||||||
{
|
|
||||||
LeaveGroup();
|
LeaveGroup();
|
||||||
Save();
|
Save();
|
||||||
if (GetMerc())
|
if (GetMerc())
|
||||||
@ -202,8 +197,7 @@ bool Client::Process() {
|
|||||||
if (IsStunned() && stunned_timer.Check())
|
if (IsStunned() && stunned_timer.Check())
|
||||||
Mob::UnStun();
|
Mob::UnStun();
|
||||||
|
|
||||||
if(!m_CheatDetectMoved)
|
if (!m_CheatDetectMoved) {
|
||||||
{
|
|
||||||
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
|
m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,32 +205,32 @@ bool Client::Process() {
|
|||||||
//NOTE: this is kinda a heavy-handed check to make sure the mob still exists before
|
//NOTE: this is kinda a heavy-handed check to make sure the mob still exists before
|
||||||
//doing the next pulse on them...
|
//doing the next pulse on them...
|
||||||
Mob *song_target = nullptr;
|
Mob *song_target = nullptr;
|
||||||
if(bardsong_target_id == GetID()) {
|
if (bardsong_target_id == GetID()) {
|
||||||
song_target = this;
|
song_target = this;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
song_target = entity_list.GetMob(bardsong_target_id);
|
song_target = entity_list.GetMob(bardsong_target_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (song_target == nullptr) {
|
if (song_target == nullptr) {
|
||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
} else {
|
}
|
||||||
if(!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
|
else {
|
||||||
|
if (!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
|
||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
//SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
|
//SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetMerc())
|
if (GetMerc()) {
|
||||||
{
|
|
||||||
UpdateMercTimer();
|
UpdateMercTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended)
|
if (GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended) {
|
||||||
{
|
|
||||||
CheckMercSuspendTimer();
|
CheckMercSuspendTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsAIControlled())
|
if (IsAIControlled())
|
||||||
AI_Process();
|
AI_Process();
|
||||||
|
|
||||||
// Don't reset the bindwound timer so we can check it in BindWound as well.
|
// Don't reset the bindwound timer so we can check it in BindWound as well.
|
||||||
@ -244,31 +238,49 @@ bool Client::Process() {
|
|||||||
BindWound(bindwound_target, false);
|
BindWound(bindwound_target, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(KarmaUpdateTimer)
|
if (KarmaUpdateTimer) {
|
||||||
{
|
if (KarmaUpdateTimer->Check(false)) {
|
||||||
if(KarmaUpdateTimer->Check(false))
|
|
||||||
{
|
|
||||||
KarmaUpdateTimer->Start(RuleI(Chat, KarmaUpdateIntervalMS));
|
KarmaUpdateTimer->Start(RuleI(Chat, KarmaUpdateIntervalMS));
|
||||||
database.UpdateKarma(AccountID(), ++TotalKarma);
|
database.UpdateKarma(AccountID(), ++TotalKarma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(qGlobals)
|
if (qGlobals) {
|
||||||
{
|
if (qglobal_purge_timer.Check()) {
|
||||||
if(qglobal_purge_timer.Check())
|
|
||||||
{
|
|
||||||
qGlobals->PurgeExpiredGlobals();
|
qGlobals->PurgeExpiredGlobals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(light_update_timer.Check()) {
|
if (light_update_timer.Check()) {
|
||||||
|
|
||||||
UpdateEquipmentLight();
|
UpdateEquipmentLight();
|
||||||
if(UpdateActiveLight()) {
|
if (UpdateActiveLight()) {
|
||||||
SendAppearancePacket(AT_Light, GetActiveLightType());
|
SendAppearancePacket(AT_Light, GetActiveLightType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Build a close range list of NPC's */
|
||||||
|
if (npc_close_scan_timer.Check()) {
|
||||||
|
|
||||||
|
close_npcs.clear();
|
||||||
|
|
||||||
|
std::list<NPC*> npc_list;
|
||||||
|
entity_list.GetNPCList(npc_list);
|
||||||
|
|
||||||
|
float scan_range = RuleI(Range, ClientNPCScan);
|
||||||
|
for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) {
|
||||||
|
NPC* npc = *itr;
|
||||||
|
float distance = DistanceNoZ(m_Position, npc->GetPosition());
|
||||||
|
if(distance <= scan_range) {
|
||||||
|
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
||||||
|
}
|
||||||
|
else if (npc->GetAggroRange() > scan_range) {
|
||||||
|
close_npcs.insert(std::pair<NPC *, float>(npc, distance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool may_use_attacks = false;
|
bool may_use_attacks = false;
|
||||||
/*
|
/*
|
||||||
Things which prevent us from attacking:
|
Things which prevent us from attacking:
|
||||||
@ -279,35 +291,35 @@ bool Client::Process() {
|
|||||||
- being stunned or mezzed
|
- being stunned or mezzed
|
||||||
- having used a ranged weapon recently
|
- having used a ranged weapon recently
|
||||||
*/
|
*/
|
||||||
if(auto_attack) {
|
if (auto_attack) {
|
||||||
if(!IsAIControlled() && !dead
|
if (!IsAIControlled() && !dead
|
||||||
&& !(spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
|
&& !(spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
|
||||||
&& !IsStunned() && !IsFeared() && !IsMezzed() && GetAppearance() != eaDead && !IsMeleeDisabled()
|
&& !IsStunned() && !IsFeared() && !IsMezzed() && GetAppearance() != eaDead && !IsMeleeDisabled()
|
||||||
)
|
)
|
||||||
may_use_attacks = true;
|
may_use_attacks = true;
|
||||||
|
|
||||||
if(may_use_attacks && ranged_timer.Enabled()) {
|
if (may_use_attacks && ranged_timer.Enabled()) {
|
||||||
//if the range timer is enabled, we need to consider it
|
//if the range timer is enabled, we need to consider it
|
||||||
if(!ranged_timer.Check(false)) {
|
if (!ranged_timer.Check(false)) {
|
||||||
//the ranged timer has not elapsed, cannot attack.
|
//the ranged timer has not elapsed, cannot attack.
|
||||||
may_use_attacks = false;
|
may_use_attacks = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(AutoFireEnabled()){
|
if (AutoFireEnabled()) {
|
||||||
EQEmu::ItemInstance *ranged = GetInv().GetItem(EQEmu::inventory::slotRange);
|
EQEmu::ItemInstance *ranged = GetInv().GetItem(EQEmu::inventory::slotRange);
|
||||||
if(ranged)
|
if (ranged)
|
||||||
{
|
{
|
||||||
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQEmu::item::ItemTypeBow){
|
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQEmu::item::ItemTypeBow) {
|
||||||
if(ranged_timer.Check(false)){
|
if (ranged_timer.Check(false)) {
|
||||||
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())) {
|
||||||
if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||||
if(CheckLosFN(GetTarget())){
|
if (CheckLosFN(GetTarget())) {
|
||||||
//client has built in los check, but auto fire does not.. done last.
|
//client has built in los check, but auto fire does not.. done last.
|
||||||
RangedAttack(GetTarget());
|
RangedAttack(GetTarget());
|
||||||
if (CheckDoubleRangedAttack())
|
if (CheckDoubleRangedAttack())
|
||||||
RangedAttack(GetTarget(), true);
|
RangedAttack(GetTarget(), true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
@ -319,11 +331,11 @@ bool Client::Process() {
|
|||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQEmu::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQEmu::item::ItemTypeSmallThrowing)){
|
else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQEmu::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQEmu::item::ItemTypeSmallThrowing)) {
|
||||||
if(ranged_timer.Check(false)){
|
if (ranged_timer.Check(false)) {
|
||||||
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())) {
|
||||||
if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||||
if(CheckLosFN(GetTarget())){
|
if (CheckLosFN(GetTarget())) {
|
||||||
//client has built in los check, but auto fire does not.. done last.
|
//client has built in los check, but auto fire does not.. done last.
|
||||||
ThrowingAttack(GetTarget());
|
ThrowingAttack(GetTarget());
|
||||||
}
|
}
|
||||||
@ -345,9 +357,9 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
//check if change
|
//check if change
|
||||||
//only check on primary attack.. sorry offhand you gotta wait!
|
//only check on primary attack.. sorry offhand you gotta wait!
|
||||||
if(aa_los_them_mob)
|
if (aa_los_them_mob)
|
||||||
{
|
{
|
||||||
if(auto_attack_target != aa_los_them_mob ||
|
if (auto_attack_target != aa_los_them_mob ||
|
||||||
m_AutoAttackPosition.x != GetX() ||
|
m_AutoAttackPosition.x != GetX() ||
|
||||||
m_AutoAttackPosition.y != GetY() ||
|
m_AutoAttackPosition.y != GetY() ||
|
||||||
m_AutoAttackPosition.z != GetZ() ||
|
m_AutoAttackPosition.z != GetZ() ||
|
||||||
@ -379,11 +391,11 @@ bool Client::Process() {
|
|||||||
|
|
||||||
if (!CombatRange(auto_attack_target))
|
if (!CombatRange(auto_attack_target))
|
||||||
{
|
{
|
||||||
Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
Message_StringID(MT_TooFarAway, TARGET_TOO_FAR);
|
||||||
}
|
}
|
||||||
else if (auto_attack_target == this)
|
else if (auto_attack_target == this)
|
||||||
{
|
{
|
||||||
Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
Message_StringID(MT_TooFarAway, TRY_ATTACKING_SOMEONE);
|
||||||
}
|
}
|
||||||
else if (!los_status || !los_status_facing)
|
else if (!los_status || !los_status_facing)
|
||||||
{
|
{
|
||||||
@ -412,23 +424,23 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto_attack && may_use_attacks && auto_attack_target != nullptr
|
if (auto_attack && may_use_attacks && auto_attack_target != nullptr
|
||||||
&& CanThisClassDualWield() && attack_dw_timer.Check())
|
&& CanThisClassDualWield() && attack_dw_timer.Check())
|
||||||
{
|
{
|
||||||
// Range check
|
// Range check
|
||||||
if(!CombatRange(auto_attack_target)) {
|
if (!CombatRange(auto_attack_target)) {
|
||||||
// this is a duplicate message don't use it.
|
// this is a duplicate message don't use it.
|
||||||
//Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
//Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
||||||
}
|
}
|
||||||
// Don't attack yourself
|
// Don't attack yourself
|
||||||
else if(auto_attack_target == this) {
|
else if (auto_attack_target == this) {
|
||||||
//Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
//Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
||||||
}
|
}
|
||||||
else if (!los_status || !los_status_facing)
|
else if (!los_status || !los_status_facing)
|
||||||
{
|
{
|
||||||
//you can't see your target
|
//you can't see your target
|
||||||
}
|
}
|
||||||
else if(auto_attack_target->GetHP() > -10) {
|
else if (auto_attack_target->GetHP() > -10) {
|
||||||
CheckIncreaseSkill(EQEmu::skills::SkillDualWield, auto_attack_target, -10);
|
CheckIncreaseSkill(EQEmu::skills::SkillDualWield, auto_attack_target, -10);
|
||||||
if (CheckDualWield()) {
|
if (CheckDualWield()) {
|
||||||
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::inventory::slotSecondary);
|
||||||
@ -442,7 +454,7 @@ bool Client::Process() {
|
|||||||
if (position_timer.Check()) {
|
if (position_timer.Check()) {
|
||||||
if (IsAIControlled())
|
if (IsAIControlled())
|
||||||
{
|
{
|
||||||
if(!IsMoving())
|
if (!IsMoving())
|
||||||
{
|
{
|
||||||
animation = 0;
|
animation = 0;
|
||||||
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
||||||
@ -464,25 +476,25 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(HasVirus()) {
|
if (HasVirus()) {
|
||||||
if(viral_timer.Check()) {
|
if (viral_timer.Check()) {
|
||||||
viral_timer_counter++;
|
viral_timer_counter++;
|
||||||
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) {
|
for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i += 2) {
|
||||||
if(viral_spells[i]) {
|
if (viral_spells[i]) {
|
||||||
if(viral_timer_counter % spells[viral_spells[i]].viral_timer == 0) {
|
if (viral_timer_counter % spells[viral_spells[i]].viral_timer == 0) {
|
||||||
SpreadVirus(viral_spells[i], viral_spells[i+1]);
|
SpreadVirus(viral_spells[i], viral_spells[i + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(viral_timer_counter > 999)
|
if (viral_timer_counter > 999)
|
||||||
viral_timer_counter = 0;
|
viral_timer_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectileAttack();
|
ProjectileAttack();
|
||||||
|
|
||||||
if(spellbonuses.GravityEffect == 1) {
|
if (spellbonuses.GravityEffect == 1) {
|
||||||
if(gravity_timer.Check())
|
if (gravity_timer.Check())
|
||||||
DoGravityEffect();
|
DoGravityEffect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +526,7 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SpellProcess();
|
SpellProcess();
|
||||||
if (endupkeep_timer.Check() && !dead){
|
if (endupkeep_timer.Check() && !dead) {
|
||||||
DoEnduranceUpkeep();
|
DoEnduranceUpkeep();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,7 +542,7 @@ bool Client::Process() {
|
|||||||
BuffProcess();
|
BuffProcess();
|
||||||
DoStaminaUpdate();
|
DoStaminaUpdate();
|
||||||
|
|
||||||
if(tribute_timer.Check()) {
|
if (tribute_timer.Check()) {
|
||||||
ToggleTribute(true); //re-activate the tribute.
|
ToggleTribute(true); //re-activate the tribute.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,18 +554,18 @@ bool Client::Process() {
|
|||||||
Save(0);
|
Save(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_pp.intoxication > 0)
|
if (m_pp.intoxication > 0)
|
||||||
{
|
{
|
||||||
--m_pp.intoxication;
|
--m_pp.intoxication;
|
||||||
CalcBonuses();
|
CalcBonuses();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ItemTickTimer.Check())
|
if (ItemTickTimer.Check())
|
||||||
{
|
{
|
||||||
TickItemCheck();
|
TickItemCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ItemQuestTimer.Check())
|
if (ItemQuestTimer.Check())
|
||||||
{
|
{
|
||||||
ItemTimerCheck();
|
ItemTimerCheck();
|
||||||
}
|
}
|
||||||
@ -592,8 +604,8 @@ bool Client::Process() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if(!linkdead_timer.Enabled()){
|
else if (!linkdead_timer.Enabled()) {
|
||||||
linkdead_timer.Start(RuleI(Zone,ClientLinkdeadMS));
|
linkdead_timer.Start(RuleI(Zone, ClientLinkdeadMS));
|
||||||
client_state = CLIENT_LINKDEAD;
|
client_state = CLIENT_LINKDEAD;
|
||||||
AI_Start(CLIENT_LD_TIMEOUT);
|
AI_Start(CLIENT_LD_TIMEOUT);
|
||||||
SendAppearancePacket(AT_Linkdead, 1);
|
SendAppearancePacket(AT_Linkdead, 1);
|
||||||
@ -603,10 +615,10 @@ bool Client::Process() {
|
|||||||
|
|
||||||
/************ Get all packets from packet manager out queue and process them ************/
|
/************ Get all packets from packet manager out queue and process them ************/
|
||||||
EQApplicationPacket *app = nullptr;
|
EQApplicationPacket *app = nullptr;
|
||||||
if(!eqs->CheckState(CLOSING))
|
if (!eqs->CheckState(CLOSING))
|
||||||
{
|
{
|
||||||
while(ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
|
while (ret && (app = (EQApplicationPacket *)eqs->PopPacket())) {
|
||||||
if(app)
|
if (app)
|
||||||
ret = HandlePacket(app);
|
ret = HandlePacket(app);
|
||||||
safe_delete(app);
|
safe_delete(app);
|
||||||
}
|
}
|
||||||
@ -616,8 +628,17 @@ bool Client::Process() {
|
|||||||
//At this point, we are still connected, everything important has taken
|
//At this point, we are still connected, everything important has taken
|
||||||
//place, now check to see if anybody wants to aggro us.
|
//place, now check to see if anybody wants to aggro us.
|
||||||
// only if client is not feigned
|
// only if client is not feigned
|
||||||
if(zone->CanDoCombat() && ret && !GetFeigned() && scanarea_timer.Check()) {
|
if (zone->CanDoCombat() && ret && !GetFeigned() && client_scan_npc_aggro_timer.Check()) {
|
||||||
entity_list.CheckClientAggro(this);
|
int npc_scan_count = 0;
|
||||||
|
for (auto it = close_npcs.begin(); it != close_npcs.end(); ++it) {
|
||||||
|
NPC *npc = it->first;
|
||||||
|
|
||||||
|
if (npc->CheckWillAggro(this) && !npc->CheckAggro(this)) {
|
||||||
|
npc->AddToHateList(this, 25);
|
||||||
|
}
|
||||||
|
npc_scan_count++;
|
||||||
|
}
|
||||||
|
Log.Out(Logs::General, Logs::Aggro, "Checking Reverse Aggro (client->npc) scanned_npcs (%i)", npc_scan_count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -2288,10 +2288,15 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
|||||||
{
|
{
|
||||||
auto it = npc_list.find(delete_id);
|
auto it = npc_list.find(delete_id);
|
||||||
if (it != npc_list.end()) {
|
if (it != npc_list.end()) {
|
||||||
|
NPC *npc = it->second;
|
||||||
// make sure its proximity is removed
|
// make sure its proximity is removed
|
||||||
RemoveProximity(delete_id);
|
RemoveProximity(delete_id);
|
||||||
|
// remove from client close lists
|
||||||
|
RemoveNPCFromClientCloseLists(npc);
|
||||||
// remove from the list
|
// remove from the list
|
||||||
npc_list.erase(it);
|
npc_list.erase(it);
|
||||||
|
|
||||||
|
|
||||||
// remove from limit list if needed
|
// remove from limit list if needed
|
||||||
if (npc_limit_list.count(delete_id))
|
if (npc_limit_list.count(delete_id))
|
||||||
npc_limit_list.erase(delete_id);
|
npc_limit_list.erase(delete_id);
|
||||||
@ -2300,6 +2305,16 @@ bool EntityList::RemoveNPC(uint16 delete_id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityList::RemoveNPCFromClientCloseLists(NPC *npc)
|
||||||
|
{
|
||||||
|
auto it = client_list.begin();
|
||||||
|
while (it != client_list.end()) {
|
||||||
|
it->second->close_npcs.erase(npc);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool EntityList::RemoveMerc(uint16 delete_id)
|
bool EntityList::RemoveMerc(uint16 delete_id)
|
||||||
{
|
{
|
||||||
auto it = merc_list.find(delete_id);
|
auto it = merc_list.find(delete_id);
|
||||||
|
|||||||
@ -279,6 +279,7 @@ public:
|
|||||||
bool RemoveTrap(uint16 delete_id);
|
bool RemoveTrap(uint16 delete_id);
|
||||||
bool RemoveObject(uint16 delete_id);
|
bool RemoveObject(uint16 delete_id);
|
||||||
bool RemoveProximity(uint16 delete_npc_id);
|
bool RemoveProximity(uint16 delete_npc_id);
|
||||||
|
bool RemoveNPCFromClientCloseLists(NPC *npc);
|
||||||
void RemoveAllMobs();
|
void RemoveAllMobs();
|
||||||
void RemoveAllClients();
|
void RemoveAllClients();
|
||||||
void RemoveAllNPCs();
|
void RemoveAllNPCs();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user