From 539fa8b2628ed97b75638ea4f1eae0c23fa5f303 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Wed, 28 Jun 2017 02:38:20 -0500 Subject: [PATCH] Fixed issues with Z correctness when NPCs are pathing on normal grids Fixed issues with Z correctness when NPCs are engaged with players following NPC corpses should fall into the ground far less --- changelog.txt | 45 +++++++++------ common/ruletypes.h | 1 + zone/attack.cpp | 7 +++ zone/mob.cpp | 4 +- zone/mob.h | 3 + zone/mob_ai.cpp | 3 + zone/waypoints.cpp | 141 +++++++++++++-------------------------------- 7 files changed, 85 insertions(+), 119 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8edf925b0..0614ff4a8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,25 +1,36 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 6/28/2017 == +Akkadius: Fixed issues with Z correctness when NPCs are pathing on normal grids +Akkadius: Fixed issues with Z correctness when NPCs are engaged with players following +Akkadius: NPC corpses should fall into the ground far less + +== 6/25/2017 == +Akkadius: New rules made by developers are now automatically created when world boots up, this keeps + from having to issue schema SQL updates every time rules are added. + - Whenever a rule isn't present in the database, it will be automatically created +Akkadius: Sped up saylink retrieval x1000 helpful for dialogues, plugins with many saylinks + == 4/16/2017 == KLS: Merge eqstream branch - -UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs). - -TCP Server to Server connection stack completely rewritten. - -Server connections reconnect much more reliably and quickly now. - -Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/). - -Protocol behind the tcp connections has changed (see breaking changes section). - -API significantly changed and should be easier to write new servers or handlers for. - -Telnet console connection has been separated out from the current port (see breaking changes section). - -Because of changes to the TCP stack, lsreconnect and echo have been disabled. - -The server tic rate has been changed to be approx 30 fps from 500+ fps. - -Changed how missiles and movement were calculated slightly to account for this (Missiles in particular are not perfect but close enough). + - UDP client stack completely rewritten should both have better throughput and recover better (peq has had far fewer reports of desyncs). + - TCP Server to Server connection stack completely rewritten. + - Server connections reconnect much more reliably and quickly now. + - Now supports optional packet encryption via libsodium (https://download.libsodium.org/doc/). + - Protocol behind the tcp connections has changed (see breaking changes section). + - API significantly changed and should be easier to write new servers or handlers for. + - Telnet console connection has been separated out from the current port (see breaking changes section). + - Because of changes to the TCP stack, lsreconnect and echo have been disabled. + - The server tic rate has been changed to be approx 30 fps from 500+ fps. + - Changed how missiles and movement were calculated slightly to account for this (Missiles in particular are not perfect but close enough). - -Breaking changes: - -Users who use the cmake install feature should be aware that the install directory is now %cmake_install_dir%/bin instead of just %cmake_install_dir%/ - -To support new features such as encryption the underlying protocol had to change... however some servers such as the public login server will be slow to change so we've included a compatibility layer for legacy login connections: - -You should add 1 to the login section of your configuration file when connecting to a server that is using the old protocol. - -The central eqemu login server uses the old protocol and probably will for the forseeable future so if your server is connecting to it be sure to add that tag to your configuration file in that section. - -Telnet no longer uses the same port as the Server to Server connection and because of this the tcp tag no longer has any effect on telnet connections. - -To enable telnet you need to add a telnet tag in the world section of configuration such as: + - Breaking changes: + - Users who use the cmake install feature should be aware that the install directory is now %cmake_install_dir%/bin instead of just %cmake_install_dir%/ + - To support new features such as encryption the underlying protocol had to change... however some servers such as the public login server will be slow to change so we've included a compatibility layer for legacy login connections: + - You should add 1 to the login section of your configuration file when connecting to a server that is using the old protocol. + - The central eqemu login server uses the old protocol and probably will for the forseeable future so if your server is connecting to it be sure to add that tag to your configuration file in that section. + - Telnet no longer uses the same port as the Server to Server connection and because of this the tcp tag no longer has any effect on telnet connections. + - To enable telnet you need to add a telnet tag in the world section of configuration such as: == 4/1/2017 == diff --git a/common/ruletypes.h b/common/ruletypes.h index 11a55c423..945c2625a 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -274,6 +274,7 @@ RULE_BOOL(Map, FixPathingZWhenLoading, true) //increases zone boot times a bit RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, accomplishes the same thing but does it at each waypoint instead of once at boot time. RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints. RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well. +RULE_BOOL(Map, FixZWhenMoving, true) // Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor) RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply. diff --git a/zone/attack.cpp b/zone/attack.cpp index 388a959c2..28ff607dc 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2388,6 +2388,13 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil entity_list.UnMarkNPC(GetID()); entity_list.RemoveNPC(GetID()); + + /* Fix Z on Corpse Creation */ + glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); + float new_z = zone->zonemap->FindBestZ(dest, nullptr); + corpse->SetFlyMode(1); + corpse->GMMove(m_Position.x, m_Position.y, new_z + 5, m_Position.w); + this->SetID(0); if (killer != 0 && emoteid != 0) diff --git a/zone/mob.cpp b/zone/mob.cpp index 64ada4b71..c411f6a3c 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -112,7 +112,9 @@ Mob::Mob(const char* in_name, m_Position(position), tmHidden(-1), mitigation_ac(0), - m_specialattacks(eSpecialAttacks::None) + m_specialattacks(eSpecialAttacks::None), + fix_z_timer(1000), + fix_z_timer_engaged(100) { targeted = 0; tar_ndx=0; diff --git a/zone/mob.h b/zone/mob.h index f2516b613..a8bf043c6 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -913,6 +913,7 @@ public: float GetGroundZ(float new_x, float new_y, float z_offset=0.0); void SendTo(float new_x, float new_y, float new_z); void SendToFixZ(float new_x, float new_y, float new_z); + void FixZ(); void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false); inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; } inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; } @@ -1373,6 +1374,8 @@ protected: bool flee_mode; Timer flee_timer; + Timer fix_z_timer; + Timer fix_z_timer_engaged; bool pAIControlled; bool roamer; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index fd0ec5d81..405382033 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -991,6 +991,9 @@ void Mob::AI_Process() { if (engaged) { + if (moving && fix_z_timer_engaged.Check()) + this->FixZ(); + if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) SendAddPlayerState(PlayerState::Aggressive); // we are prevented from getting here if we are blind and don't have a target in range diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 64f674cde..6ceee481e 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -513,39 +513,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.y = new_y; m_Position.z = new_z; - uint8 NPCFlyMode = 0; - - if (IsNPC()) { - if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2) - NPCFlyMode = 1; - } - - //fix up pathing Z - if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) - { - if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || - (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) - { - glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); - - float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f; - - if ((newz > -2000) && - std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check. - { - if ((std::abs(x - m_Position.x) < 0.5) && - (std::abs(y - m_Position.y) < 0.5)) { - if (std::abs(z - m_Position.z) <= - RuleR(Map, FixPathingZMaxDeltaMoving)) - m_Position.z = z; - else - m_Position.z = newz + 1; - } - else - m_Position.z = newz + 1; - } - } - } + if(fix_z_timer.Check()) + this->FixZ(); tar_ndx++; return true; @@ -651,37 +620,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo m_Position.w = CalculateHeadingToTarget(x, y); } - uint8 NPCFlyMode = 0; - - if (IsNPC()) { - if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2) - NPCFlyMode = 1; - } - - //fix up pathing Z - if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) { - - if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || - (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) - { - glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); - - float newz = zone->zonemap->FindBestZ(dest, nullptr); - - if ((newz > -2000) && - std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check. - { - if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) { - if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving)) - m_Position.z = z; - else - m_Position.z = newz + 1; - } - else - m_Position.z = newz + 1; - } - } - } + if (fix_z_timer.Check()) + this->FixZ(); SetMoving(true); moved = true; @@ -769,39 +709,8 @@ bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ Log(Logs::Detail, Logs::AI, "Next position (%.3f, %.3f, %.3f)", m_Position.x, m_Position.y, m_Position.z); } - uint8 NPCFlyMode = 0; - - if (IsNPC()) { - if (CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2) - NPCFlyMode = 1; - } - - //fix up pathing Z - if (!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) - { - if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || - (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) - { - glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); - - float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f; - - Log(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z); - - if ((newz > -2000) && - std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check. - { - if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) { - if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving)) - m_Position.z = z; - else - m_Position.z = newz + 1; - } - else - m_Position.z = newz + 1; - } - } - } + if (fix_z_timer.Check()) + this->FixZ(); //OP_MobUpdate if ((old_test_vector != test_vector) || tar_ndx>20) { //send update @@ -943,9 +852,6 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { m_Position.y = new_y; m_Position.z = new_z + 0.1; - //fix up pathing Z, this shouldent be needed IF our waypoints - //are corrected instead - if (zone->HasMap() && RuleB(Map, FixPathingZOnSendTo)) { if (!RuleB(Watermap, CheckForWaterOnSendTo) || !zone->HasWaterMap() || @@ -955,7 +861,7 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { float newz = zone->zonemap->FindBestZ(dest, nullptr); - Log(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z); + Log(Logs::Moderate, Logs::Pathing, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz, m_Position.x, m_Position.y, m_Position.z); if ((newz > -2000) && std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaSendTo)) // Sanity check. m_Position.z = newz + 1; @@ -963,6 +869,39 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { } } +void Mob::FixZ() { + BenchTimer timer; + timer.reset(); + + if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && (flymode != 1 && flymode != 2)) + { + if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || + (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) + { + glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); + + float new_z = zone->zonemap->FindBestZ(dest, nullptr); + + auto duration = timer.elapsed(); + + Log( + Logs::Moderate, + Logs::Pathing, + "Mob::FixZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf", + this->GetCleanName(), + new_z, + m_Position.x, + m_Position.y, + m_Position.z, + duration + ); + + if ((new_z > -2000) && std::abs(new_z - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) + m_Position.z = new_z + 1; + } + } +} + int ZoneDatabase::GetHighestGrid(uint32 zoneid) { std::string query = StringFormat("SELECT COALESCE(MAX(id), 0) FROM grid WHERE zoneid = %i", zoneid);