mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 06:21:28 +00:00
Fix HP update issues, rework logic for more accurate and responsive HP updates
This commit is contained in:
parent
127f51e758
commit
ccdeb4d385
@ -1,6 +1,7 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
== 7/9/2017 ==
|
== 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
|
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 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
|
- HP Updates were sending excessively even during idle zones when HP wasn't changing at all
|
||||||
|
|||||||
@ -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, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster.
|
||||||
RULE_INT(Character, TradeskillUpResearch, 1) // Research 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_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_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, IksarCommonTongue, 95) // 95 By default (live-like?)
|
||||||
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)
|
RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?)
|
||||||
|
|||||||
@ -158,7 +158,8 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
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)
|
npc_close_scan_timer(6000),
|
||||||
|
hp_self_update_throttle_timer(500)
|
||||||
{
|
{
|
||||||
for(int cf=0; cf < _FilterCount; cf++)
|
for(int cf=0; cf < _FilterCount; cf++)
|
||||||
ClientFilters[cf] = FilterShow;
|
ClientFilters[cf] = FilterShow;
|
||||||
@ -8745,8 +8746,8 @@ void Client::SendHPUpdateMarquee(){
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Health Update Marquee Display: Custom*/
|
/* Health Update Marquee Display: Custom*/
|
||||||
int8 health_percentage = (int8)(this->cur_hp * 100 / this->max_hp);
|
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
|
||||||
if (health_percentage == 100)
|
if (health_percentage >= 100)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);
|
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);
|
||||||
|
|||||||
@ -1485,6 +1485,7 @@ private:
|
|||||||
Timer helm_toggle_timer;
|
Timer helm_toggle_timer;
|
||||||
Timer aggro_meter_timer;
|
Timer aggro_meter_timer;
|
||||||
Timer npc_close_scan_timer;
|
Timer npc_close_scan_timer;
|
||||||
|
Timer hp_self_update_throttle_timer;
|
||||||
|
|
||||||
glm::vec3 m_Proximity;
|
glm::vec3 m_Proximity;
|
||||||
|
|
||||||
|
|||||||
143
zone/mob.cpp
143
zone/mob.cpp
@ -125,7 +125,7 @@ Mob::Mob(const char* in_name,
|
|||||||
|
|
||||||
last_z = 0;
|
last_z = 0;
|
||||||
|
|
||||||
last_hp = 100;
|
|
||||||
|
|
||||||
AI_Init();
|
AI_Init();
|
||||||
SetMoving(false);
|
SetMoving(false);
|
||||||
@ -180,6 +180,8 @@ Mob::Mob(const char* in_name,
|
|||||||
fearspeed = ((float)base_fearspeed) * 0.025f;
|
fearspeed = ((float)base_fearspeed) * 0.025f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_hp_percent = 0;
|
||||||
|
last_hp = 0;
|
||||||
|
|
||||||
current_speed = base_runspeed;
|
current_speed = base_runspeed;
|
||||||
|
|
||||||
@ -1303,123 +1305,136 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
|
|||||||
// sends hp update of this mob to people who might care
|
// sends hp update of this mob to people who might care
|
||||||
void Mob::SendHPUpdate(bool skip_self)
|
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);
|
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||||
if (current_hp == last_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");
|
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: Same HP - skipping update");
|
||||||
ResetHPUpdateTimer();
|
ResetHPUpdateTimer();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
|
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
|
||||||
|
this->CastToClient()->SendHPUpdateMarquee();
|
||||||
|
|
||||||
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: HP Changed - Send update");
|
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;
|
EQApplicationPacket hp_app;
|
||||||
Group *group = nullptr;
|
Group *group = nullptr;
|
||||||
|
|
||||||
// destructor will free the pBuffer
|
|
||||||
CreateHPPacket(&hp_app);
|
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);
|
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);
|
entity_list.QueueClientsByXTarget(this, &hp_app, false);
|
||||||
|
|
||||||
|
/* Update groups using Group LAA health name tag counter */
|
||||||
entity_list.QueueToGroupsForNPCHealthAA(this, &hp_app);
|
entity_list.QueueToGroupsForNPCHealthAA(this, &hp_app);
|
||||||
|
|
||||||
// send to group
|
/* Update group */
|
||||||
if(IsGrouped())
|
if(IsGrouped()) {
|
||||||
{
|
|
||||||
group = entity_list.GetGroupByMob(this);
|
group = entity_list.GetGroupByMob(this);
|
||||||
if(group) //not sure why this might be null, but it happens
|
if(group) //not sure why this might be null, but it happens
|
||||||
group->SendHPPacketsFrom(this);
|
group->SendHPPacketsFrom(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update Raid */
|
||||||
if(IsClient()){
|
if(IsClient()){
|
||||||
Raid *r = entity_list.GetRaidByClient(CastToClient());
|
Raid *raid = entity_list.GetRaidByClient(CastToClient());
|
||||||
if(r){
|
if (raid)
|
||||||
r->SendHPPacketsFrom(this);
|
raid->SendHPPacketsFrom(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send to master
|
/* Pet - Update master - group and raid if exists */
|
||||||
if(GetOwner() && GetOwner()->IsClient())
|
if(GetOwner() && GetOwner()->IsClient()) {
|
||||||
{
|
|
||||||
GetOwner()->CastToClient()->QueuePacket(&hp_app, false);
|
GetOwner()->CastToClient()->QueuePacket(&hp_app, false);
|
||||||
group = entity_list.GetGroupByClient(GetOwner()->CastToClient());
|
group = entity_list.GetGroupByClient(GetOwner()->CastToClient());
|
||||||
|
|
||||||
if(group)
|
if(group)
|
||||||
group->SendHPPacketsFrom(this);
|
group->SendHPPacketsFrom(this);
|
||||||
Raid *r = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
|
||||||
if(r)
|
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
||||||
r->SendHPPacketsFrom(this);
|
if(raid)
|
||||||
|
raid->SendHPPacketsFrom(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send to pet
|
/* Send to pet */
|
||||||
if(GetPet() && GetPet()->IsClient())
|
if(GetPet() && GetPet()->IsClient()) {
|
||||||
{
|
|
||||||
GetPet()->CastToClient()->QueuePacket(&hp_app, false);
|
GetPet()->CastToClient()->QueuePacket(&hp_app, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the damage state of destructible objects
|
/* Destructible objects */
|
||||||
if(IsNPC() && IsDestructibleObject())
|
if (IsNPC() && IsDestructibleObject()) {
|
||||||
{
|
if (GetHPRatio() > 74) {
|
||||||
if (GetHPRatio() > 74)
|
if (GetAppearance() != eaStanding) {
|
||||||
{
|
SendAppearancePacket(AT_DamageState, eaStanding);
|
||||||
if (GetAppearance() != eaStanding)
|
_appearance = eaStanding;
|
||||||
{
|
|
||||||
SendAppearancePacket(AT_DamageState, eaStanding);
|
|
||||||
_appearance = eaStanding;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GetHPRatio() > 49)
|
else if (GetHPRatio() > 49) {
|
||||||
{
|
if (GetAppearance() != eaSitting) {
|
||||||
if (GetAppearance() != eaSitting)
|
|
||||||
{
|
|
||||||
SendAppearancePacket(AT_DamageState, eaSitting);
|
SendAppearancePacket(AT_DamageState, eaSitting);
|
||||||
_appearance = eaSitting;
|
_appearance = eaSitting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GetHPRatio() > 24)
|
else if (GetHPRatio() > 24) {
|
||||||
{
|
if (GetAppearance() != eaCrouching) {
|
||||||
if (GetAppearance() != eaCrouching)
|
|
||||||
{
|
|
||||||
SendAppearancePacket(AT_DamageState, eaCrouching);
|
SendAppearancePacket(AT_DamageState, eaCrouching);
|
||||||
_appearance = eaCrouching;
|
_appearance = eaCrouching;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GetHPRatio() > 0)
|
else if (GetHPRatio() > 0) {
|
||||||
{
|
if (GetAppearance() != eaDead) {
|
||||||
if (GetAppearance() != eaDead)
|
|
||||||
{
|
|
||||||
SendAppearancePacket(AT_DamageState, eaDead);
|
SendAppearancePacket(AT_DamageState, eaDead);
|
||||||
_appearance = eaDead;
|
_appearance = eaDead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (GetAppearance() != eaLooting)
|
else if (GetAppearance() != eaLooting) {
|
||||||
{
|
|
||||||
SendAppearancePacket(AT_DamageState, eaLooting);
|
SendAppearancePacket(AT_DamageState, eaLooting);
|
||||||
_appearance = 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
|
// this one just warps the mob to the current location
|
||||||
|
|||||||
@ -1389,7 +1389,8 @@ protected:
|
|||||||
int wandertype;
|
int wandertype;
|
||||||
int pausetype;
|
int pausetype;
|
||||||
|
|
||||||
int8 last_hp;
|
int8 last_hp_percent;
|
||||||
|
int32 last_hp;
|
||||||
|
|
||||||
int cur_wp;
|
int cur_wp;
|
||||||
glm::vec4 m_CurrentWayPoint;
|
glm::vec4 m_CurrentWayPoint;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user