Fix HP update issues, rework logic for more accurate and responsive HP updates

This commit is contained in:
Akkadius 2017-07-09 17:35:08 -05:00
parent 127f51e758
commit ccdeb4d385
6 changed files with 87 additions and 69 deletions

View File

@ -1,6 +1,7 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 7/9/2017 ==
Akkadius: Fix HP update issues, rework logic for more accurate HP updates
Akkadius: Massive reductions in unnecessary network traffic especially during high spam combat fights
- HP Updates now only send to others when HP percentage changes (0-100%)
- HP Updates were sending excessively even during idle zones when HP wasn't changing at all

View File

@ -134,7 +134,6 @@ RULE_INT(Character, TradeskillUpMakePoison, 2) // Make Poison skillup rate adjus
RULE_INT(Character, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster.
RULE_INT(Character, TradeskillUpResearch, 1) // Research skillup rate adjust. Lower is faster.
RULE_INT(Character, TradeskillUpTinkering, 2) // Tinkering skillup rate adjust. Lower is faster.
RULE_BOOL(Character, SpamHPUpdates, false) // if your server has stupid amounts of HP that causes client display issues, turn this on!
RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of screen < 100%
RULE_INT(Character, IksarCommonTongue, 95) // 95 By default (live-like?)
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)

View File

@ -158,7 +158,8 @@ Client::Client(EQStreamInterface* ieqs)
m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f),
last_region_type(RegionTypeUnsupported),
m_dirtyautohaters(false),
npc_close_scan_timer(6000)
npc_close_scan_timer(6000),
hp_self_update_throttle_timer(500)
{
for(int cf=0; cf < _FilterCount; cf++)
ClientFilters[cf] = FilterShow;
@ -8745,8 +8746,8 @@ void Client::SendHPUpdateMarquee(){
return;
/* Health Update Marquee Display: Custom*/
int8 health_percentage = (int8)(this->cur_hp * 100 / this->max_hp);
if (health_percentage == 100)
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
if (health_percentage >= 100)
return;
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);

View File

@ -1485,6 +1485,7 @@ private:
Timer helm_toggle_timer;
Timer aggro_meter_timer;
Timer npc_close_scan_timer;
Timer hp_self_update_throttle_timer;
glm::vec3 m_Proximity;

View File

@ -125,7 +125,7 @@ Mob::Mob(const char* in_name,
last_z = 0;
last_hp = 100;
AI_Init();
SetMoving(false);
@ -180,6 +180,8 @@ Mob::Mob(const char* in_name,
fearspeed = ((float)base_fearspeed) * 0.025f;
}
last_hp_percent = 0;
last_hp = 0;
current_speed = base_runspeed;
@ -1303,123 +1305,136 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
// sends hp update of this mob to people who might care
void Mob::SendHPUpdate(bool skip_self)
{
/* If our HP is different from last HP update call - let's update ourself */
if (IsClient() && cur_hp != last_hp) {
/* This is to prevent excessive packet sending under trains/fast combat */
if (this->CastToClient()->hp_self_update_throttle_timer.Check()) {
Log(Logs::General, Logs::HP_Update,
"Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s",
this->GetCleanName(),
cur_hp,
last_hp,
(skip_self ? "true" : "false")
);
int8 current_hp = (max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp));
if (!skip_self || this->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::UF) {
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
SpawnHPUpdate_Struct* hp_packet_client = (SpawnHPUpdate_Struct*)client_packet->pBuffer;
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i", this->GetCleanName(), current_hp, last_hp);
if (current_hp == last_hp) {
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
hp_packet_client->spawn_id = GetID();
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
CastToClient()->QueuePacket(client_packet);
safe_delete(client_packet);
ResetHPUpdateTimer();
}
}
}
/* Used to check if HP has changed to update self next round */
last_hp = cur_hp;
int8 current_hp_percent = (max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp));
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i", this->GetCleanName(), current_hp_percent, last_hp_percent);
if (current_hp_percent == last_hp_percent) {
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: Same HP - skipping update");
ResetHPUpdateTimer();
return;
}
else {
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
this->CastToClient()->SendHPUpdateMarquee();
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: HP Changed - Send update");
last_hp = current_hp;
last_hp_percent = current_hp_percent;
}
EQApplicationPacket hp_app;
Group *group = nullptr;
// destructor will free the pBuffer
CreateHPPacket(&hp_app);
// send to people who have us targeted
/* Update those who have use targeted */
entity_list.QueueClientsByTarget(this, &hp_app, false, 0, false, true, EQEmu::versions::bit_AllClients);
/* Update those who have us on x-target */
entity_list.QueueClientsByXTarget(this, &hp_app, false);
/* Update groups using Group LAA health name tag counter */
entity_list.QueueToGroupsForNPCHealthAA(this, &hp_app);
// send to group
if(IsGrouped())
{
/* Update group */
if(IsGrouped()) {
group = entity_list.GetGroupByMob(this);
if(group) //not sure why this might be null, but it happens
group->SendHPPacketsFrom(this);
}
/* Update Raid */
if(IsClient()){
Raid *r = entity_list.GetRaidByClient(CastToClient());
if(r){
r->SendHPPacketsFrom(this);
}
Raid *raid = entity_list.GetRaidByClient(CastToClient());
if (raid)
raid->SendHPPacketsFrom(this);
}
// send to master
if(GetOwner() && GetOwner()->IsClient())
{
/* Pet - Update master - group and raid if exists */
if(GetOwner() && GetOwner()->IsClient()) {
GetOwner()->CastToClient()->QueuePacket(&hp_app, false);
group = entity_list.GetGroupByClient(GetOwner()->CastToClient());
if(group)
group->SendHPPacketsFrom(this);
Raid *r = entity_list.GetRaidByClient(GetOwner()->CastToClient());
if(r)
r->SendHPPacketsFrom(this);
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
if(raid)
raid->SendHPPacketsFrom(this);
}
// send to pet
if(GetPet() && GetPet()->IsClient())
{
/* Send to pet */
if(GetPet() && GetPet()->IsClient()) {
GetPet()->CastToClient()->QueuePacket(&hp_app, false);
}
// Update the damage state of destructible objects
if(IsNPC() && IsDestructibleObject())
{
if (GetHPRatio() > 74)
{
if (GetAppearance() != eaStanding)
{
SendAppearancePacket(AT_DamageState, eaStanding);
_appearance = eaStanding;
/* Destructible objects */
if (IsNPC() && IsDestructibleObject()) {
if (GetHPRatio() > 74) {
if (GetAppearance() != eaStanding) {
SendAppearancePacket(AT_DamageState, eaStanding);
_appearance = eaStanding;
}
}
else if (GetHPRatio() > 49)
{
if (GetAppearance() != eaSitting)
{
else if (GetHPRatio() > 49) {
if (GetAppearance() != eaSitting) {
SendAppearancePacket(AT_DamageState, eaSitting);
_appearance = eaSitting;
}
}
else if (GetHPRatio() > 24)
{
if (GetAppearance() != eaCrouching)
{
else if (GetHPRatio() > 24) {
if (GetAppearance() != eaCrouching) {
SendAppearancePacket(AT_DamageState, eaCrouching);
_appearance = eaCrouching;
}
}
else if (GetHPRatio() > 0)
{
if (GetAppearance() != eaDead)
{
else if (GetHPRatio() > 0) {
if (GetAppearance() != eaDead) {
SendAppearancePacket(AT_DamageState, eaDead);
_appearance = eaDead;
}
}
else if (GetAppearance() != eaLooting)
{
else if (GetAppearance() != eaLooting) {
SendAppearancePacket(AT_DamageState, eaLooting);
_appearance = eaLooting;
}
}
bool dospam = RuleB(Character, SpamHPUpdates);
// send to self - we need the actual hps here
if(IsClient() && (!skip_self || dospam)) {
if (RuleB(Character, MarqueeHPUpdates))
this->CastToClient()->SendHPUpdateMarquee();
auto hp_app2 = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer;
ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
ds->spawn_id = GetID();
ds->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
CastToClient()->QueuePacket(hp_app2);
safe_delete(hp_app2);
}
if (!dospam)
ResetHPUpdateTimer(); // delay the timer
}
// this one just warps the mob to the current location

View File

@ -1389,7 +1389,8 @@ protected:
int wandertype;
int pausetype;
int8 last_hp;
int8 last_hp_percent;
int32 last_hp;
int cur_wp;
glm::vec4 m_CurrentWayPoint;