1
0

Fix #19 Position updates ignored when dead, new rule MiniDing, fix

Fix #19 - ignore position updates when dead
New rule R_Player MiniDingPercentage
Fixed ordering of locks in RemoveSpawn
ResetSpawnPackets function created to test resetting the spawn packet to a spawn (testing purposes only not live code)
This commit is contained in:
Emagi 2025-05-30 21:47:57 -04:00
parent 6d52f19108
commit 97d1393627
6 changed files with 67 additions and 18 deletions

View File

@ -999,7 +999,7 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
if (version <= 561) { if (version <= 561) {
packet->setDataByName("exp_yellow", info_struct->get_xp_yellow() / 10); packet->setDataByName("exp_yellow", info_struct->get_xp_yellow() / 10);
packet->setDataByName("exp_blue", info_struct->get_xp_blue()/10); packet->setDataByName("exp_blue", info_struct->get_xp_blue()/100);
} }
else { else {
packet->setDataByName("exp_yellow", info_struct->get_xp_yellow()); packet->setDataByName("exp_yellow", info_struct->get_xp_yellow());
@ -3577,9 +3577,9 @@ void Player::RemoveSpellEffect(LuaSpell* spell){
GetSpellEffectMutex()->releasewritelock(__FUNCTION__, __LINE__); GetSpellEffectMutex()->releasewritelock(__FUNCTION__, __LINE__);
} }
void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version) void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version, bool dead_window_sent)
{ {
if(GetClient() && GetClient()->IsReloadingZone()) if((GetClient() && GetClient()->IsReloadingZone()) || dead_window_sent)
return; return;
LogWrite(PLAYER__DEBUG, 7, "Player", "Enter: %s", __FUNCTION__); // trace LogWrite(PLAYER__DEBUG, 7, "Player", "Enter: %s", __FUNCTION__); // trace
@ -4503,7 +4503,14 @@ bool Player::AddXP(int32 xp_amount){
int32 prev_level = GetLevel(); int32 prev_level = GetLevel();
float current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100; float current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100;
float miniding_min_percent = ((int)(current_xp_percent/10)+1)*10; int32 mini_ding_pct = rule_manager.GetGlobalRule(R_Player, MiniDingPercentage)->GetInt32();
float miniding_min_percent = 0.0f;
if(mini_ding_pct < 10 || mini_ding_pct > 50) {
mini_ding_pct = 0;
}
else {
miniding_min_percent = ((int)(current_xp_percent/mini_ding_pct)+1)*mini_ding_pct;
}
while((xp_amount + GetXP()) >= GetNeededXP()){ while((xp_amount + GetXP()) >= GetNeededXP()){
if (!CheckLevelStatus(GetLevel() + 1)) { if (!CheckLevelStatus(GetLevel() + 1)) {
if(GetClient()) { if(GetClient()) {
@ -4518,7 +4525,7 @@ bool Player::AddXP(int32 xp_amount){
SetXP(GetXP() + xp_amount); SetXP(GetXP() + xp_amount);
GetPlayerInfo()->CalculateXPPercentages(); GetPlayerInfo()->CalculateXPPercentages();
current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100; current_xp_percent = ((float)GetXP()/(float)GetNeededXP())*100;
if(current_xp_percent >= miniding_min_percent){ if(miniding_min_percent > 0.0f && current_xp_percent >= miniding_min_percent){
if(GetClient() && rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8()) if(GetClient() && rule_manager.GetGlobalRule(R_Spells, UseClassicSpellLevel)->GetInt8())
GetClient()->SendNewAdventureSpells(); // mini ding involves checking spells again in classic level settings GetClient()->SendNewAdventureSpells(); // mini ding involves checking spells again in classic level settings
SetHP(GetTotalHP()); SetHP(GetTotalHP());
@ -4632,6 +4639,27 @@ bool Player::WasSpawnRemoved(Spawn* spawn){
return wasRemoved; return wasRemoved;
} }
void Player::ResetSpawnPackets(int32 id) {
info_mutex.writelock(__FUNCTION__, __LINE__);
vis_mutex.writelock(__FUNCTION__, __LINE__);
pos_mutex.writelock(__FUNCTION__, __LINE__);
index_mutex.writelock(__FUNCTION__, __LINE__);
if (spawn_info_packet_list.count(id))
spawn_info_packet_list.erase(id);
if (spawn_pos_packet_list.count(id))
spawn_pos_packet_list.erase(id);
if (spawn_vis_packet_list.count(id))
spawn_vis_packet_list.erase(id);
index_mutex.releasewritelock(__FUNCTION__, __LINE__);
vis_mutex.releasewritelock(__FUNCTION__, __LINE__);
pos_mutex.releasewritelock(__FUNCTION__, __LINE__);
info_mutex.releasewritelock(__FUNCTION__, __LINE__);
}
void Player::RemoveSpawn(Spawn* spawn, bool delete_spawn) void Player::RemoveSpawn(Spawn* spawn, bool delete_spawn)
{ {
LogWrite(PLAYER__DEBUG, 3, "Player", "Remove Spawn '%s' (%u)", spawn->GetName(), spawn->GetID()); LogWrite(PLAYER__DEBUG, 3, "Player", "Remove Spawn '%s' (%u)", spawn->GetName(), spawn->GetID());
@ -4664,10 +4692,9 @@ void Player::RemoveSpawn(Spawn* spawn, bool delete_spawn)
spawn_vis_packet_list.erase(id); spawn_vis_packet_list.erase(id);
index_mutex.releasewritelock(__FUNCTION__, __LINE__); index_mutex.releasewritelock(__FUNCTION__, __LINE__);
info_mutex.releasewritelock(__FUNCTION__, __LINE__);
pos_mutex.releasewritelock(__FUNCTION__, __LINE__); pos_mutex.releasewritelock(__FUNCTION__, __LINE__);
vis_mutex.releasewritelock(__FUNCTION__, __LINE__); vis_mutex.releasewritelock(__FUNCTION__, __LINE__);
info_mutex.releasewritelock(__FUNCTION__, __LINE__);
} }
vector<int32> Player::GetQuestIDs(){ vector<int32> Player::GetQuestIDs(){

View File

@ -624,7 +624,7 @@ public:
float CalculateTSXP(int8 level); float CalculateTSXP(int8 level);
void CalculateOfflineDebtRecovery(int32 unix_timestamp); void CalculateOfflineDebtRecovery(int32 unix_timestamp);
void InCombat(bool val, bool range = false); void InCombat(bool val, bool range = false);
void PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version); void PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version, bool dead_window_sent = false);
uchar* GetMovementPacketData(){ uchar* GetMovementPacketData(){
return movement_packet; return movement_packet;
} }
@ -655,6 +655,7 @@ public:
Spawn* GetSpawnByIndex(int16 index); Spawn* GetSpawnByIndex(int16 index);
int16 GetIndexForSpawn(Spawn* spawn); int16 GetIndexForSpawn(Spawn* spawn);
bool WasSpawnRemoved(Spawn* spawn); bool WasSpawnRemoved(Spawn* spawn);
void ResetSpawnPackets(int32 id);
void RemoveSpawn(Spawn* spawn, bool delete_spawn = true); void RemoveSpawn(Spawn* spawn, bool delete_spawn = true);
bool ShouldSendSpawn(Spawn* spawn); bool ShouldSendSpawn(Spawn* spawn);
Client* client = 0; Client* client = 0;

View File

@ -243,6 +243,10 @@ void RuleManager::Init()
RULE_INIT(R_Player, HarvestSkillUpMultiplier, "2.0"); /* multiplier for node to take the "min skill" max and use a multiplier to offset the max skill allowed to skill up on node. RULE_INIT(R_Player, HarvestSkillUpMultiplier, "2.0"); /* multiplier for node to take the "min skill" max and use a multiplier to offset the max skill allowed to skill up on node.
** Eg. 50 min skill on node, 50*1.5=75, no one with higher than 75 skill gets a skill up ** Eg. 50 min skill on node, 50*1.5=75, no one with higher than 75 skill gets a skill up
*/ */
RULE_INIT(R_Player, MiniDingPercentage, "10"); /* Mini ding percentage for EverQuest 2, eg. default is every 10% (triggers at 10%, 20%, 30%, 40%, 50%, .. so on). setting 20% (triggers at 20%, 40%, 60%, 80%)
** Setting to less than 10 or greater than 50 will disable completely
** Range supported is 10 - 50%.
**/
/* PVP */ /* PVP */
RULE_INIT(R_PVP, AllowPVP, "0"); RULE_INIT(R_PVP, AllowPVP, "0");
RULE_INIT(R_PVP, LevelRange, "4"); RULE_INIT(R_PVP, LevelRange, "4");

View File

@ -101,6 +101,7 @@ enum RuleType {
MaxTargetCommandDistance, MaxTargetCommandDistance,
MinSkillMultiplierValue, MinSkillMultiplierValue,
HarvestSkillUpMultiplier, HarvestSkillUpMultiplier,
MiniDingPercentage,
/* PVP */ /* PVP */
AllowPVP, AllowPVP,

View File

@ -184,6 +184,11 @@ Client::Client(EQStream* ieqs) : underworld_cooldown_timer(5000), pos_update(125
lua_debug = false; lua_debug = false;
ready_for_spawns = false; ready_for_spawns = false;
ready_for_updates = false; ready_for_updates = false;
dead_window_sent = false;
dead_x = 0.0f;
dead_y = 0.0f;
dead_z = 0.0f;
dead_h = 0.0f;
lua_debug_timer.Disable(); lua_debug_timer.Disable();
transport_spawn = 0; transport_spawn = 0;
MBuyBack.SetName("Client::MBuyBack"); MBuyBack.SetName("Client::MBuyBack");
@ -478,7 +483,7 @@ void Client::SendPlayerDeathWindow()
vector<RevivePoint*>* results = GetCurrentZone()->GetRevivePoints(this); vector<RevivePoint*>* results = GetCurrentZone()->GetRevivePoints(this);
vector<RevivePoint*>::iterator itr; vector<RevivePoint*>::iterator itr;
if (results && results->size() > 0) if (results && results->size() > 0) // we always populate a safe point if there is no revive point
{ {
PacketStruct* packet = configReader.getStruct("WS_DeathWindow", GetVersion()); PacketStruct* packet = configReader.getStruct("WS_DeathWindow", GetVersion());
if (packet) if (packet)
@ -542,13 +547,19 @@ void Client::DisplayDeadWindow()
QueuePacket(packet->serialize()); QueuePacket(packet->serialize());
safe_delete(packet); safe_delete(packet);
} }
dead_x = player->GetX();
dead_y = player->GetY();
dead_z = player->GetZ();
dead_window_sent = true;
SendPlayerDeathWindow(); SendPlayerDeathWindow();
} }
void Client::HandlePlayerRevive(int32 point_id) void Client::HandlePlayerRevive(int32 point_id)
{ {
dead_window_sent = false;
if (GetVersion() <= 561) { if (GetVersion() <= 561) {
ClientPacketFunctions::SendServerControlFlagsClassic(this, 8, 0); ClientPacketFunctions::SendServerControlFlagsClassic(this, 8, 0);
ClientPacketFunctions::SendServerControlFlagsClassic(this, 16, 0); ClientPacketFunctions::SendServerControlFlagsClassic(this, 16, 0);
@ -845,9 +856,6 @@ void Client::SendCharInfo() {
safe_delete(items); safe_delete(items);
if (!player->Alive())
DisplayDeadWindow();
ClientPacketFunctions::SendLocalizedTextMessage(this); ClientPacketFunctions::SendLocalizedTextMessage(this);
if (GetCurrentZone()->GetInstanceID()) if (GetCurrentZone()->GetInstanceID())
@ -1934,6 +1942,9 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
if (zone_script && lua_interface) { if (zone_script && lua_interface) {
lua_interface->RunZoneScript(zone_script, "enter_location", GetPlayer()->GetZone(), GetPlayer(), GetPlayer()->GetLocation()); lua_interface->RunZoneScript(zone_script, "enter_location", GetPlayer()->GetZone(), GetPlayer(), GetPlayer()->GetLocation());
} }
if (!GetPlayer()->Alive())
DisplayDeadWindow();
if (GetPlayer()->GetHP() < GetPlayer()->GetTotalHP() || GetPlayer()->GetPower() < GetPlayer()->GetTotalPower()) if (GetPlayer()->GetHP() < GetPlayer()->GetTotalHP() || GetPlayer()->GetPower() < GetPlayer()->GetTotalPower())
GetCurrentZone()->AddDamagedSpawn(GetPlayer()); GetCurrentZone()->AddDamagedSpawn(GetPlayer());
@ -2089,13 +2100,13 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
float x = player->GetX(); float x = player->GetX();
float y = player->GetY(); float y = player->GetY();
float z = player->GetZ(); float z = player->GetZ();
player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version); player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version, dead_window_sent);
distance = player->GetDistance(x, y, z, false); distance = player->GetDistance(x, y, z, false);
if (distance > .5) if (distance > .5)
current_zone->Interrupted(player, 0, SPELL_ERROR_INTERRUPTED, false, true); current_zone->Interrupted(player, 0, SPELL_ERROR_INTERRUPTED, false, true);
} }
else else
player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version); player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version, dead_window_sent);
player_pos_changed = true; player_pos_changed = true;
GetPlayer()->changed = true; GetPlayer()->changed = true;
@ -2144,13 +2155,13 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
float x = player->GetX(); float x = player->GetX();
float y = player->GetY(); float y = player->GetY();
float z = player->GetZ(); float z = player->GetZ();
player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version); player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version, dead_window_sent);
distance = player->GetDistance(x, y, z, false); distance = player->GetDistance(x, y, z, false);
if (distance > .5) if (distance > .5)
current_zone->Interrupted(player, 0, SPELL_ERROR_INTERRUPTED, false, true); current_zone->Interrupted(player, 0, SPELL_ERROR_INTERRUPTED, false, true);
} }
else else
player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version); player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version, dead_window_sent);
player_pos_changed = true; player_pos_changed = true;
GetPlayer()->changed = true; GetPlayer()->changed = true;

View File

@ -782,6 +782,11 @@ private:
bool connected; bool connected;
std::atomic<bool> ready_for_spawns; std::atomic<bool> ready_for_spawns;
std::atomic<bool> ready_for_updates; std::atomic<bool> ready_for_updates;
std::atomic<bool> dead_window_sent;
float dead_x;
float dead_y;
float dead_z;
float dead_h;
bool seencharsel; bool seencharsel;
bool connected_to_zone; bool connected_to_zone;