From 9935e723417f28eff260d345264fc1ea66b5e695 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 22 Oct 2023 09:14:41 -0300 Subject: [PATCH 01/16] feat(Core/Unit): Implement OnPowerUpdate() unit script hook (#17560) --- src/server/game/AI/CoreAI/UnitAI.h | 5 ++++- src/server/game/Entities/Unit/Unit.cpp | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index e69c9811d..2b1b574d4 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -353,11 +353,14 @@ public: // Called at any Damage from any attacker (before damage apply) // Note: it for recalculation damage or special reaction at damage // for attack reaction use AttackedBy called for not DOT damage in Unit::DealDamage also - virtual void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) {} + virtual void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) {} // Called when the creature receives heal virtual void HealReceived(Unit* /*done_by*/, uint32& /*addhealth*/) {} + // Called when the creature power updates + virtual void OnPowerUpdate(Powers /*power*/, int32 /*updateVal*/, int32 /*gain*/, uint32 /*currPower*/) {} + // Called when the unit heals virtual void HealDone(Unit* /*done_to*/, uint32& /*addhealth*/) {} diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ae48a25e3..b308603bc 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14115,6 +14115,11 @@ int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true* gain = maxPower - curPower; } + if (GetAI()) + { + GetAI()->OnPowerUpdate(power, gain, dVal, curPower); + } + return gain; } From 69418ab93616cd04d2a91060c12e110d675b6941 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 22 Oct 2023 10:12:30 -0300 Subject: [PATCH 02/16] =?UTF-8?q?fix(Scripts/Ulduar):=20Don't=20treat=20Al?= =?UTF-8?q?galon=20respawns=20as=20if=20they=20were=20the=E2=80=A6=20(#175?= =?UTF-8?q?62)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(Scripts/Ulduar): Don't treat Algalon respawns as if they were the first pull * Update boss_algalon_the_observer.cpp --- .../Ulduar/Ulduar/boss_algalon_the_observer.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 86fc02904..1f90c584a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -388,6 +388,11 @@ public: _phaseTwo = false; _heraldOfTheTitans = true; + if (m_pInstance->GetData(TYPE_ALGALON) == FAIL) + { + _firstPull = false; + } + if (m_pInstance) m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED); } @@ -1151,6 +1156,14 @@ public: if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02))) sigil->SetGoState(GO_STATE_ACTIVE); + + if (Map* map = player->GetMap()) + { + if (InstanceMap* instanceMap = map->ToInstanceMap()) + { + instanceMap->PermBindAllPlayers(); + } + } } return false; From a56a224bd72603f79a95fad7b8b9642c7b72015e Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Mon, 23 Oct 2023 05:28:29 -0300 Subject: [PATCH 03/16] fix(Scripts/Karazhan): Update Aran with the new OnPowerUpdate() hook (#17561) --- .../Karazhan/boss_shade_of_aran.cpp | 68 +++++++++---------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index b8ca05175..55929ee77 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -211,6 +211,38 @@ struct boss_shade_of_aran : public BossAI } } + void OnPowerUpdate(Powers /*power*/, int32 /*gain*/, int32 /*updateVal*/, uint32 currentPower) override + { + // Should drink at 10%, need 10% mana for mass polymorph + if (!_hasDrunk && me->GetMaxPower(POWER_MANA) && (currentPower * 100 / me->GetMaxPower(POWER_MANA)) < 13) + { + _drinking = true; + _hasDrunk = true; + me->InterruptNonMeleeSpells(true); + Talk(SAY_DRINK); + DoCastAOE(SPELL_MASS_POLY); + me->SetReactState(REACT_PASSIVE); + + // Start drinking after conjuring drinks + _drinkScheduler.Schedule(2s, GROUP_DRINKING, [this](TaskContext) + { + DoCastSelf(SPELL_CONJURE); + }).Schedule(4s, GROUP_DRINKING, [this](TaskContext) + { + me->SetStandState(UNIT_STAND_STATE_SIT); + DoCastSelf(SPELL_DRINK); + }).Schedule(10s, GROUP_DRINKING, [this](TaskContext) + { + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); + me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000); + DoCastSelf(SPELL_AOE_PYROBLAST); + _drinkScheduler.CancelGroup(GROUP_DRINKING); + _drinking = false; + }); + } + } + void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); @@ -226,8 +258,6 @@ struct boss_shade_of_aran : public BossAI } }).Schedule(1s, [this](TaskContext context) { - context.Repeat(2s); - if (!_drinking) { if (me->IsNonMeleeSpellCast(false)) @@ -255,39 +285,6 @@ struct boss_shade_of_aran : public BossAI ++AvailableSpells; } - // Should drink at 10%, need 10% mana for mass polymorph - if (!_hasDrunk && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 13) - { - _drinking = true; - _hasDrunk = true; - me->InterruptNonMeleeSpells(true); - Talk(SAY_DRINK); - DoCastAOE(SPELL_MASS_POLY); - me->SetReactState(REACT_PASSIVE); - - // Start drinking after conjuring drinks - _drinkScheduler.Schedule(2s, GROUP_DRINKING, [this](TaskContext) - { - DoCastSelf(SPELL_CONJURE); - }).Schedule(4s, GROUP_DRINKING, [this](TaskContext) - { - me->SetStandState(UNIT_STAND_STATE_SIT); - DoCastSelf(SPELL_DRINK); - }); - - _drinkScheduler.Schedule(10s, GROUP_DRINKING, [this](TaskContext) - { - me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetReactState(REACT_AGGRESSIVE); - me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000); - DoCastSelf(SPELL_AOE_PYROBLAST); - _drinkScheduler.CancelGroup(GROUP_DRINKING); - _drinking = false; - }); - - return; - } - //If no available spells wait 1 second and try again if (AvailableSpells) { @@ -318,6 +315,7 @@ struct boss_shade_of_aran : public BossAI } } } + context.Repeat(2s); }).Schedule(5s, [this](TaskContext context) { if (!_drinking) From 60e27511c530b0949fee361a89d3eb9d9f9125af Mon Sep 17 00:00:00 2001 From: AG <43139552+AGandrup@users.noreply.github.com> Date: Mon, 23 Oct 2023 10:37:11 +0200 Subject: [PATCH 04/16] fix(Core/Grid): Address bugs and performance issues introduced by visibility notifier implementation (#17480) * Bug fixes - Corrected std::chrono from seconds to milliseconds - Got rid of leftover code that caused objects to not show up on time * Removed logic to set gameobject as active - More alignement with TC. - Reduces CPU usage drastically * Revert back to using time_t instead of std chrono * Invoke SetNoCreate() method to reduce CPU usage drastically * Remove setActive from static and motion transports * Fix performance issues * Added SetFarVisible to WG and some dungeon scripts - Also removed setActive(true) from creatures in Wintergrasp. As for gameobjects they are set to active upon being damaged/destroyed and removed from active on rebuild (reset) * Removed comments related to VISIBILITY_COMPENSATION * Fix log * Deleted unused files + corrected a check * Added missing header * Removed unused parameter * Removed another unsued parameter * Changed vector to set for i_visibleNow - Changed vector to set for i_visibleNow in VisibleNotifer - Adjusted HaveAtClient to accept Object* - Adjusted SendUpdateToPlayer to send createobject packet only if not known to client --- src/server/game/Battlefield/Battlefield.cpp | 4 +- .../game/Battlefield/Zones/BattlefieldWG.h | 9 + .../game/Entities/Creature/Creature.cpp | 28 ++- src/server/game/Entities/Creature/Creature.h | 1 + .../Entities/DynamicObject/DynamicObject.cpp | 19 +- .../game/Entities/GameObject/GameObject.cpp | 58 +++--- .../game/Entities/GameObject/GameObject.h | 2 - src/server/game/Entities/Object/Object.cpp | 107 ++++------- src/server/game/Entities/Object/Object.h | 9 +- .../game/Entities/Object/ObjectDefines.h | 4 - src/server/game/Entities/Object/ObjectGuid.h | 1 + src/server/game/Entities/Player/Player.cpp | 22 +-- src/server/game/Entities/Player/Player.h | 13 +- .../game/Entities/Player/PlayerUpdates.cpp | 37 ++-- .../game/Entities/Transport/Transport.cpp | 65 ++++--- .../game/Entities/Transport/Transport.h | 3 - src/server/game/Entities/Unit/Unit.cpp | 60 +++---- src/server/game/Entities/Unit/Unit.h | 2 +- src/server/game/Entities/Vehicle/Vehicle.cpp | 3 +- src/server/game/Grids/NGrid.cpp | 2 +- src/server/game/Grids/NGrid.h | 8 +- .../game/Grids/Notifiers/GridNotifiers.cpp | 2 +- .../game/Grids/Notifiers/GridNotifiers.h | 12 +- .../game/Grids/Notifiers/GridNotifiersImpl.h | 4 - src/server/game/Grids/ObjectGridLoader.cpp | 25 ++- src/server/game/Handlers/MovementHandler.cpp | 167 +++++++++--------- src/server/game/Maps/Map.cpp | 138 +++++++-------- src/server/game/Maps/Map.h | 34 ++-- src/server/game/Maps/MapInstanced.cpp | 12 +- src/server/game/Maps/MapInstanced.h | 2 +- src/server/game/Maps/MapMgr.cpp | 4 +- src/server/game/Maps/TransportMgr.cpp | 2 - src/server/game/Misc/DynamicVisibility.cpp | 28 --- src/server/game/Misc/DynamicVisibility.h | 58 ------ .../game/Movement/Spline/MoveSpline.cpp | 46 ++++- .../game/Movement/Spline/MoveSplineInit.cpp | 1 + .../Movement/Spline/MovementPacketBuilder.cpp | 27 +-- .../Movement/Spline/MovementPacketBuilder.h | 1 + src/server/game/Movement/Spline/Spline.cpp | 20 ++- src/server/game/Movement/Spline/Spline.h | 21 +-- .../game/Spells/Auras/SpellAuraEffects.cpp | 2 +- src/server/game/Spells/SpellEffects.cpp | 6 +- src/server/game/World/World.cpp | 3 - .../BlackwingLair/boss_nefarian.cpp | 1 + .../BlackwingLair/instance_blackwing_lair.cpp | 1 + .../Karazhan/boss_nightbane.cpp | 1 + .../zone_the_scarlet_enclave.cpp | 1 + .../BattleForMountHyjal/hyjalAI.cpp | 8 + .../boss_baltharus_the_warborn.cpp | 1 + .../IcecrownCitadel/boss_sindragosa.cpp | 7 + .../Ulduar/boss_algalon_the_observer.cpp | 1 + .../Ulduar/Ulduar/boss_razorscale.cpp | 1 + .../Northrend/Ulduar/Ulduar/boss_thorim.cpp | 1 + 53 files changed, 509 insertions(+), 586 deletions(-) delete mode 100644 src/server/game/Misc/DynamicVisibility.cpp delete mode 100644 src/server/game/Misc/DynamicVisibility.h diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index fe609ea1f..675010655 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -815,7 +815,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl // Set creature in world map->AddToMap(creature); - creature->setActive(true); + creature->SetFarVisible(true); return creature; } @@ -840,7 +840,7 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z // Add to world map->AddToMap(go); - go->setActive(true); + go->SetFarVisible(true); return go; } diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 1c4cb586d..c0652d878 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -1159,6 +1159,7 @@ struct BfWGGameObjectBuilding // Rebuild gameobject go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true); go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[m_Team]); + go->setActive(false); // Everything is reset, no need keep active at this point. } // Update worldstate @@ -1170,6 +1171,10 @@ struct BfWGGameObjectBuilding // Called when associated gameobject is damaged void Damaged() { + GameObject* go = m_WG->GetGameObject(m_Build); + if (go) + go->setActive(true); + // Update worldstate m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE - (m_Team * 3); m_WG->SendUpdateWorldState(m_WorldState, m_State); @@ -1193,6 +1198,10 @@ struct BfWGGameObjectBuilding // Called when associated gameobject is destroyed void Destroyed() { + GameObject* go = m_WG->GetGameObject(m_Build); + if (go) + go->setActive(true); + // Update worldstate m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY - (m_Team * 3); m_WG->SendUpdateWorldState(m_WorldState, m_State); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index fb0ec8954..1d2ef9dfb 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -301,9 +301,6 @@ void Creature::RemoveFromWorld() if (m_formation) sFormationMgr->RemoveCreatureFromGroup(m_formation, this); - if (Transport* transport = GetTransport()) - transport->RemovePassenger(this, true); - Unit::RemoveFromWorld(); if (m_spawnId) @@ -1826,7 +1823,25 @@ void Creature::DeleteFromDB() return; } - GetMap()->RemoveCreatureRespawnTime(m_spawnId); + CreatureData const* data = sObjectMgr->GetCreatureData(m_spawnId); + if (!data) + return; + + CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction(); + + sMapMgr->DoForAllMapsWithMapId(data->mapid, + [this, charTrans](Map* map) -> void + { + // despawn all active creatures, and remove their respawns + std::vector toUnload; + for (auto const& pair : Acore::Containers::MapEqualRange(map->GetCreatureBySpawnIdStore(), m_spawnId)) + toUnload.push_back(pair.second); + for (Creature* creature : toUnload) + map->AddObjectToRemoveList(creature); + map->RemoveCreatureRespawnTime(m_spawnId); + } + ); + sObjectMgr->DeleteCreatureData(m_spawnId); WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction(); @@ -3060,10 +3075,7 @@ std::string const& Creature::GetNameForLocaleIdx(LocaleConstant loc_idx) const void Creature::SetPosition(float x, float y, float z, float o) { - if (!Acore::IsValidMapCoord(x, y, z, o)) - return; - - GetMap()->CreatureRelocation(this, x, y, z, o); + UpdatePosition(x, y, z, o, false); } bool Creature::IsDungeonBoss() const diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index ede229ff7..126b7b099 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -68,6 +68,7 @@ public: void Update(uint32 time) override; // overwrited Unit::Update void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr, float* dist = nullptr) const; + bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->mapid != GetMapId(); } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } void SetCorpseRemoveTime(uint32 delay); diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 779e44312..8346d74e8 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -47,14 +47,6 @@ DynamicObject::~DynamicObject() void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */) { - if (Transport* transport = GetTransport()) - { - transport->RemovePassenger(this); - SetTransport(nullptr); - m_movementInfo.transport.Reset(); - m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - } - WorldObject::CleanupsBeforeDelete(finalCleanup); } @@ -88,9 +80,6 @@ void DynamicObject::RemoveFromWorld() UnbindFromCaster(); - if (Transport* transport = GetTransport()) - transport->RemovePassenger(this, true); - WorldObject::RemoveFromWorld(); GetMap()->GetObjectsStore().Remove(GetGUID()); @@ -125,17 +114,15 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, GameTime::GetGameTimeMS().count()); + if (IsWorldObject()) + setActive(true); //must before add to map to be put in world container + if (!GetMap()->AddToMap(this, true)) { // Returning false will cause the object to be deleted - remove from transport return false; } - if (IsWorldObject()) - { - setActive(true); - } - return true; } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index aa164d4f7..68b215377 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -27,6 +27,7 @@ #include "GridNotifiersImpl.h" #include "Group.h" #include "GroupMgr.h" +#include "MapMgr.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" #include "PoolMgr.h" @@ -102,18 +103,9 @@ std::string const& GameObject::GetAIName() const return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName; } -void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) +void GameObject::CleanupsBeforeDelete(bool finalCleanup) { - if (GetTransport() && !ToTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(nullptr); - m_movementInfo.transport.Reset(); - m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - } - - if (IsInWorld()) - RemoveFromWorld(); + WorldObject::CleanupsBeforeDelete(finalCleanup); if (m_uint32Values) // field array can be not exist if GameOBject not loaded RemoveFromOwner(); @@ -182,9 +174,6 @@ void GameObject::RemoveFromWorld() if (GetMap()->ContainsGameObjectModel(*m_model)) GetMap()->RemoveGameObjectModel(*m_model); - if (Transport* transport = GetTransport()) - transport->RemovePassenger(this, true); - // If linked trap exists, despawn it if (GameObject* linkedTrap = GetLinkedTrap()) { @@ -888,7 +877,11 @@ void GameObject::Update(uint32 diff) if (!m_spawnedByDefault) { m_respawnTime = 0; - DestroyForNearbyPlayers(); // xinef: old UpdateObjectVisibility(); + if (m_spawnId) + DestroyForNearbyPlayers(); // xinef: old UpdateObjectVisibility(); + else + Delete(); + return; } @@ -1184,7 +1177,31 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo void GameObject::DeleteFromDB() { - GetMap()->RemoveGORespawnTime(m_spawnId); + if (!m_spawnId) + { + LOG_ERROR("entities.gameobject", "Trying to delete not saved gameobject: {}", GetGUID().ToString()); + return; + } + + GameObjectData const* data = sObjectMgr->GetGameObjectData(m_spawnId); + if (!data) + return; + + CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction(); + + sMapMgr->DoForAllMapsWithMapId(data->mapid, + [this, charTrans](Map* map) -> void + { + // despawn all active objects, and remove their respawns + std::vector toUnload; + for (auto const& pair : Acore::Containers::MapEqualRange(map->GetGameObjectBySpawnIdStore(), m_spawnId)) + toUnload.push_back(pair.second); + for (GameObject* obj : toUnload) + map->AddObjectToRemoveList(obj); + map->RemoveGORespawnTime(m_spawnId); + } + ); + sObjectMgr->DeleteGOData(m_spawnId); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); @@ -2173,15 +2190,6 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const && dz < (info->maxZ * scale) + radius && dz > (info->minZ * scale) - radius; } -void GameObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const -{ - dist += GetObjectSize(); - if (includeMargin) - dist += VISIBILITY_COMPENSATION * 2.0f; // pussywizard: to ensure everyone receives all important packets - Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr); - Cell::VisitWorldObjects(this, notifier, dist); -} - void GameObject::EventInform(uint32 eventId) { if (!eventId) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 61962e75d..945c648e0 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -289,8 +289,6 @@ public: void SendCustomAnim(uint32 anim); [[nodiscard]] bool IsInRange(float x, float y, float z, float radius) const; - void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard! - void ModifyHealth(int32 change, Unit* attackerOrHealer = nullptr, uint32 spellId = 0); void SetDestructibleBuildingModifyState(bool allow) { m_allowModifyDestructibleBuilding = allow; } // sets GameObject type 33 destruction flags and optionally default health for that state diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index c0584ef00..97f90bddd 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -21,7 +21,6 @@ #include "CellImpl.h" #include "Chat.h" #include "Creature.h" -#include "DynamicVisibility.h" #include "GameObjectAI.h" #include "GameTime.h" #include "GridNotifiers.h" @@ -249,7 +248,10 @@ void Object::SendUpdateToPlayer(Player* player) UpdateData upd; WorldPacket packet; - BuildCreateUpdateBlockForPlayer(&upd, player); + if (player->HaveAtClient(this)) + BuildValuesUpdateBlockForPlayer(&upd, player); + else + BuildCreateUpdateBlockForPlayer(&upd, player); upd.BuildPacket(&packet); player->GetSession()->SendPacket(&packet); } @@ -1048,7 +1050,7 @@ void MovementInfo::OutDebug() } WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), - LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), + LastUsedScriptID(0), m_name(""), m_isActive(false), m_isFarVisible(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), _zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr), m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0) { @@ -1105,8 +1107,6 @@ void WorldObject::setActive(bool on) map->AddToActive(this->ToCreature()); else if (GetTypeId() == TYPEID_DYNAMICOBJECT) map->AddToActive((DynamicObject*)this); - else if (GetTypeId() == TYPEID_GAMEOBJECT) - map->AddToActive((GameObject*)this); } else { @@ -1114,11 +1114,17 @@ void WorldObject::setActive(bool on) map->RemoveFromActive(this->ToCreature()); else if (GetTypeId() == TYPEID_DYNAMICOBJECT) map->RemoveFromActive((DynamicObject*)this); - else if (GetTypeId() == TYPEID_GAMEOBJECT) - map->RemoveFromActive((GameObject*)this); } } +void WorldObject::SetFarVisible(bool on) +{ + if (GetTypeId() == TYPEID_PLAYER) + return; + + m_isFarVisible = on; +} + void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type) { ASSERT(type < VisibilityDistanceType::Max); @@ -1134,6 +1140,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/) { if (IsInWorld()) RemoveFromWorld(); + + if (Transport* transport = GetTransport()) + transport->RemovePassenger(this, true); } void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask) @@ -1626,9 +1635,9 @@ float WorldObject::GetGridActivationRange() const { if (ToPlayer()->GetCinematicMgr()->IsOnCinematic()) { - return DEFAULT_VISIBILITY_INSTANCE; + return std::max(DEFAULT_VISIBILITY_INSTANCE, GetMap()->GetVisibilityRange()); } - return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); + return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange(); } else if (ToCreature()) { @@ -1644,29 +1653,12 @@ float WorldObject::GetGridActivationRange() const float WorldObject::GetVisibilityRange() const { - if (IsVisibilityOverridden() && GetTypeId() == TYPEID_UNIT) - { + if (IsVisibilityOverridden() && !ToPlayer()) return *m_visibilityDistanceOverride; - } - else if (GetTypeId() == TYPEID_GAMEOBJECT) - { - { - if (IsInWintergrasp()) - { - return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS; - } - else if (IsVisibilityOverridden()) - { - return *m_visibilityDistanceOverride; - } - else - { - return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS; - } - } - } + else if (IsFarVisible() && !ToPlayer()) + return MAX_VISIBILITY_DISTANCE; else - return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); + return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange(); } float WorldObject::GetSightRange(WorldObject const* target) const @@ -1675,44 +1667,19 @@ float WorldObject::GetSightRange(WorldObject const* target) const { if (ToPlayer()) { - if (target) - { - if (target->IsVisibilityOverridden() && target->GetTypeId() == TYPEID_UNIT) - { - return *target->m_visibilityDistanceOverride; - } - else if (target->GetTypeId() == TYPEID_GAMEOBJECT) - { - if (IsInWintergrasp() && target->IsInWintergrasp()) - { - return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS; - } - else if (target->IsVisibilityOverridden()) - { - return *target->m_visibilityDistanceOverride; - } - else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic()) - { - return DEFAULT_VISIBILITY_INSTANCE; - } - else - { - return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS; - } - } - - return IsInWintergrasp() && target->IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); - } - return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); + if (target && target->IsVisibilityOverridden() && !target->ToPlayer()) + return *target->m_visibilityDistanceOverride; + else if (target && target->IsFarVisible() && !target->ToPlayer()) + return MAX_VISIBILITY_DISTANCE; + else if (ToPlayer()->GetCinematicMgr()->IsOnCinematic()) + return DEFAULT_VISIBILITY_INSTANCE; + else + return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange(); } else if (ToCreature()) - { return ToCreature()->m_SightDistance; - } else - { return SIGHT_RANGE_UNIT; - } } if (ToDynObject() && isActiveObject()) @@ -2077,11 +2044,8 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const BuildMovementPacket(data); } -void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const +void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, Player const* skipped_rcvr) const { - dist += GetObjectSize(); - if (includeMargin) - dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr); Cell::VisitWorldObjects(this, notifier, dist); } @@ -2228,7 +2192,8 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert return nullptr; } - EnsureGridLoaded(Cell(pos.GetPositionX(), pos.GetPositionY())); + if (!IsGridLoaded(pos.GetPositionX(), pos.GetPositionY())) + EnsureGridLoaded(Cell(pos.GetPositionX(), pos.GetPositionY())); if (!summon->Create(GenerateLowGuid(), this, phase, entry, vehId, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation())) { delete summon; @@ -2901,8 +2866,8 @@ void WorldObject::DestroyForNearbyPlayers() return; std::list targets; - Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange() + VISIBILITY_COMPENSATION, false); - Acore::PlayerListSearcherWithSharedVision searcher(this, targets, check); + Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange(), false); + Acore::PlayerListSearcher searcher(this, targets, check); Cell::VisitWorldObjects(this, searcher, GetVisibilityRange()); for (std::list::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) { @@ -2984,7 +2949,7 @@ struct WorldObjectChangeAccumulator source = iter->GetSource(); ObjectGuid guid = source->GetCasterGUID(); - if (guid) + if (guid.IsPlayer()) { //Caster may be nullptr if DynObj is in removelist if (Player* caster = ObjectAccessor::FindPlayer(guid)) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index adaf92899..5ee201e8e 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -488,9 +488,9 @@ public: virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units - virtual void SendMessageToSet(WorldPacket const* data, bool self) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard! - virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const; // pussywizard! - virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), false, true, skipped_rcvr); } // pussywizard! + virtual void SendMessageToSet(WorldPacket const* data, bool self) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self); } // pussywizard! + virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, Player const* skipped_rcvr = nullptr) const; // pussywizard! + virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), false, skipped_rcvr); } // pussywizard! virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; } @@ -569,6 +569,7 @@ public: [[nodiscard]] bool isActiveObject() const { return m_isActive; } void setActive(bool isActiveObject); [[nodiscard]] bool IsFarVisible() const { return m_isFarVisible; } + void SetFarVisible(bool on); [[nodiscard]] bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); } void SetVisibilityDistanceOverride(VisibilityDistanceType type); void SetWorldObject(bool apply); @@ -577,7 +578,7 @@ public: [[nodiscard]] bool IsInWintergrasp() const { - return GetMapId() == 571 && GetPositionX() > 3733.33331f && GetPositionX() < 5866.66663f && GetPositionY() > 1599.99999f && GetPositionY() < 4799.99997f; + return GetMapId() == 571 && GetZoneId() == 4197; } #ifdef MAP_BASED_RAND_GEN diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h index 5d809c05f..0dfb5a705 100644 --- a/src/server/game/Entities/Object/ObjectDefines.h +++ b/src/server/game/Entities/Object/ObjectDefines.h @@ -23,10 +23,7 @@ #define CONTACT_DISTANCE 0.5f #define INTERACTION_DISTANCE 5.5f #define ATTACK_DISTANCE 5.0f -#define VISIBILITY_COMPENSATION 15.0f // increase searchers #define INSPECT_DISTANCE 28.0f -#define VISIBILITY_INC_FOR_GOBJECTS 30.0f // pussywizard -#define SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border #define TRADE_DISTANCE 11.11f #define MAX_VISIBILITY_DISTANCE SIZE_OF_GRIDS // max distance for visible objects, experimental #define SIGHT_RANGE_UNIT 50.0f @@ -38,7 +35,6 @@ #define VISIBILITY_DISTANCE_TINY 25.0f #define DEFAULT_VISIBILITY_DISTANCE VISIBILITY_DISTANCE_NORMAL // default visible distance, 100 yards on continents #define DEFAULT_VISIBILITY_INSTANCE 170.0f // default visible distance in instances, 170 yards -#define VISIBILITY_DIST_WINTERGRASP 175.0f #define DEFAULT_VISIBILITY_BGARENAS 533.0f // default visible distance in BG/Arenas, roughly 533 yards #define DEFAULT_WORLD_OBJECT_SIZE 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index bb8029048..3f626c780 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -134,6 +134,7 @@ class ObjectGuid ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { } ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { } + operator uint64() const { return _guid; } PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); } void Set(uint64 guid) { _guid = guid; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 14adb01c8..bc64ae0a3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1353,10 +1353,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (GetTransport()) { - m_transport->RemovePassenger(this); - m_transport = nullptr; - m_movementInfo.transport.Reset(); - m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + m_transport->RemovePassenger(this, true); RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } @@ -1398,10 +1395,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); else { - m_transport->RemovePassenger(this); - m_transport = nullptr; - m_movementInfo.transport.Reset(); - m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + m_transport->RemovePassenger(this, true); } } @@ -5581,14 +5575,11 @@ void Player::SaveRecallPosition() m_recallO = GetOrientation(); } -void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, Player const* skipped_rcvr) const +void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, Player const* skipped_rcvr) const { if (self) GetSession()->SendPacket(data); - dist += GetObjectSize(); - if (includeMargin) - dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr); Cell::VisitWorldObjects(this, notifier, dist); } @@ -11322,7 +11313,7 @@ WorldLocation Player::GetStartPosition() const return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); } -bool Player::HaveAtClient(WorldObject const* u) const +bool Player::HaveAtClient(Object const* u) const { if (u == this) { @@ -13096,14 +13087,11 @@ void Player::SetViewpoint(WorldObject* target, bool apply) UpdateVisibilityOf(target); if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) - ((Unit*)target)->AddPlayerToVision(this); + static_cast(target)->AddPlayerToVision(this); SetSeer(target); } else { - //must immediately set seer back otherwise may crash - m_seer = this; - LOG_DEBUG("maps", "Player::CreateViewpoint: Player {} remove seer", GetName()); if (!RemoveGuidValue(PLAYER_FARSIGHT, target->GetGUID())) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index bb4b0585c..c36fec295 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1986,10 +1986,10 @@ public: void ProcessTerrainStatusUpdate() override; - void SendMessageToSet(WorldPacket const* data, bool self) const override { SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard! - void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard! - void SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const; // pussywizard! param includeMargin not needed here - void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override { SendMessageToSetInRange(data, GetVisibilityRange(), skipped_rcvr != this, true, skipped_rcvr); } // pussywizard! + void SendMessageToSet(WorldPacket const* data, bool self) const override { SendMessageToSetInRange(data, GetVisibilityRange(), self); } // pussywizard! + void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, Player const* skipped_rcvr = nullptr) const override; // pussywizard! + void SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const; // pussywizard! + void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override { SendMessageToSetInRange(data, GetVisibilityRange(), skipped_rcvr != this, skipped_rcvr); } // pussywizard! void SendTeleportAckPacket(); @@ -2342,9 +2342,8 @@ public: // currently visible objects at player client GuidUnorderedSet m_clientGUIDs; - std::vector m_newVisible; // pussywizard - [[nodiscard]] bool HaveAtClient(WorldObject const* u) const; + [[nodiscard]] bool HaveAtClient(Object const* u) const; [[nodiscard]] bool HaveAtClient(ObjectGuid guid) const; [[nodiscard]] bool IsNeverVisible() const override; @@ -2358,7 +2357,7 @@ public: void UpdateTriggerVisibility(); template - void UpdateVisibilityOf(T* target, UpdateData& data, std::vector& visibleNow); + void UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow); uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 17c1319f9..f36708d46 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -1521,17 +1521,11 @@ void Player::UpdatePotionCooldown(Spell* spell) SetLastPotionId(0); } -template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, - std::vector& visibleNow); -template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, - std::vector& visibleNow); -template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, - std::vector& visibleNow); -template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, - std::vector& visibleNow); -template void Player::UpdateVisibilityOf(DynamicObject* target, - UpdateData& data, - std::vector& visibleNow); +template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, std::set& visibleNow); +template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, std::set& visibleNow); +template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, std::set& visibleNow); +template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, std::set& visibleNow); +template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, std::set& visibleNow); void Player::UpdateVisibilityForPlayer(bool mapChange) { @@ -1543,7 +1537,7 @@ void Player::UpdateVisibilityForPlayer(bool mapChange) } // updates visibility of all objects around point of view for current player - Acore::VisibleNotifier notifier(*this, mapChange); + Acore::VisibleNotifier notifier(*this); Cell::VisitAllObjects(m_seer, notifier, GetSightRange()); notifier.SendToSelf(); // send gathered data } @@ -1564,15 +1558,13 @@ void Player::UpdateObjectVisibility(bool forced) } template -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, - std::vector& /*v*/) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set& /*v*/) { s64.insert(target->GetGUID()); } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, - std::vector& /*v*/) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set& /*v*/) { // @HACK: This is to prevent objects like deeprun tram from disappearing // when player moves far from its spawn point while riding it @@ -1581,19 +1573,17 @@ inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, - std::vector& v) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set& v) { s64.insert(target->GetGUID()); - v.push_back(target); + v.insert(target); } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, - std::vector& v) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, std::set& v) { s64.insert(target->GetGUID()); - v.push_back(target); + v.insert(target); } template @@ -1609,8 +1599,7 @@ inline void BeforeVisibilityDestroy(Creature* t, Player* p) } template -void Player::UpdateVisibilityOf(T* target, UpdateData& data, - std::vector& visibleNow) +void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow) { if (HaveAtClient(target)) { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 3dc023eb4..3fb3e3b82 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -32,7 +32,7 @@ #include "World.h" #include "WorldModel.h" -MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false) +MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _delayedTeleport(false) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -230,8 +230,14 @@ void MotionTransport::Update(uint32 diff) 3. transport moves from active to inactive grid 4. the grid that transport is currently in unloads */ - if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2. + bool gridActive = GetMap()->IsGridLoaded(GetPositionX(), GetPositionY()); + + if (_staticPassengers.empty() && gridActive) // 2. LoadStaticPassengers(); + else if (!_staticPassengers.empty() && !gridActive) + // 4. - if transports stopped on grid edge, some passengers can remain in active grids + // unload all static passengers otherwise passengers won't load correctly when the grid that transport is currently in becomes active + UnloadStaticPassengers(); } } @@ -248,18 +254,27 @@ void MotionTransport::DelayedUpdate(uint32 /*diff*/) void MotionTransport::UpdatePosition(float x, float y, float z, float o) { - if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case - GetMap()->LoadGrid(x, y); + bool newActive = GetMap()->IsGridLoaded(x, y); + Cell oldCell(GetPositionX(), GetPositionY()); Relocate(x, y, z, o); UpdateModelPosition(); UpdatePassengerPositions(_passengers); - if (_staticPassengers.empty()) + /* There are four possible scenarios that trigger loading/unloading passengers: + 1. transport moves from inactive to active grid + 2. the grid that transport is currently in becomes active + 3. transport moves from active to inactive grid + 4. the grid that transport is currently in unloads + */ + if (_staticPassengers.empty() && newActive) // 1. LoadStaticPassengers(); + else if (!_staticPassengers.empty() && !newActive && oldCell.DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3. + UnloadStaticPassengers(); else UpdatePassengerPositions(_staticPassengers); + // 4. is handed by grid unload } void MotionTransport::AddPassenger(WorldObject* passenger, bool withAll) @@ -306,8 +321,7 @@ void MotionTransport::RemovePassenger(WorldObject* passenger, bool withAll) { passenger->SetTransport(nullptr); passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - passenger->m_movementInfo.transport.guid.Clear(); - passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); + passenger->m_movementInfo.transport.Reset(); if (passenger->ToUnit()) { passenger->ToUnit()->ClearUnitState(UNIT_STATE_IGNORE_PATHFINDING); @@ -407,9 +421,6 @@ GameObject* MotionTransport::CreateGOPassenger(ObjectGuid::LowType guid, GameObj void MotionTransport::LoadStaticPassengers() { - if (PassengersLoaded()) - return; - SetPassengersLoaded(true); if (uint32 mapId = GetGOInfo()->moTransport.mapID) { CellObjectGuidsMap const& cells = sObjectMgr->GetMapObjectGuids(mapId, GetMap()->GetSpawnMode()); @@ -431,7 +442,6 @@ void MotionTransport::LoadStaticPassengers() void MotionTransport::UnloadStaticPassengers() { - SetPassengersLoaded(false); while (!_staticPassengers.empty()) { WorldObject* obj = *_staticPassengers.begin(); @@ -542,11 +552,19 @@ void MotionTransport::DelayedTeleportTransport() _delayedTeleport = false; uint32 newMapId = _nextFrame->Node->mapid; + Map* newMap = sMapMgr->CreateBaseMap(newMapId); + GetMap()->RemoveFromMap(this, false); + float x = _nextFrame->Node->x, y = _nextFrame->Node->y, z = _nextFrame->Node->z, o = _nextFrame->InitialOrientation; + if (!newMap->IsGridLoaded(x, y) && !_passengers.empty()) + newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map + + SetMap(newMap); + PassengerSet _passengersCopy = _passengers; for (PassengerSet::iterator itr = _passengersCopy.begin(); itr != _passengersCopy.end(); ) { @@ -592,15 +610,8 @@ void MotionTransport::DelayedTeleportTransport() } } - Map* newMap = sMapMgr->CreateBaseMap(newMapId); - GetMap()->RemoveFromMap(this, false); - newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map - SetMap(newMap); - Relocate(x, y, z, o); GetMap()->AddToMap(this); - - LoadStaticPassengers(); } void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers) @@ -631,7 +642,7 @@ void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers) case TYPEID_UNIT: { Creature* creature = passenger->ToCreature(); - GetMap()->CreatureRelocation(creature, x, y, z, o); + GetMap()->CreatureRelocation(creature, x, y, z, o, false); creature->GetTransportHomePosition(x, y, z, o); CalculatePassengerPosition(x, y, z, &o); @@ -643,7 +654,7 @@ void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers) GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o); break; case TYPEID_GAMEOBJECT: - GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o); + GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false); break; case TYPEID_DYNAMICOBJECT: GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o); @@ -780,7 +791,6 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m LastUsedScriptID = GetGOInfo()->ScriptId; AIM_Initialize(); - this->setActive(true); return true; } @@ -915,7 +925,8 @@ void StaticTransport::UpdatePosition(float x, float y, float z, float o) if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case GetMap()->LoadGrid(x, y); - GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model + Relocate(x, y, z, o); + UpdateModelPosition(); UpdatePassengerPositions(); } @@ -942,17 +953,14 @@ void StaticTransport::UpdatePassengerPositions() switch (passenger->GetTypeId()) { case TYPEID_UNIT: - GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o); + GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o, false); break; case TYPEID_PLAYER: if (passenger->IsInWorld()) - { GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o); - passenger->ToPlayer()->SetFallInformation(GameTime::GetGameTime().count(), z); - } break; case TYPEID_GAMEOBJECT: - GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o); + GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false); break; case TYPEID_DYNAMICOBJECT: GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o); @@ -1001,8 +1009,7 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll) { passenger->SetTransport(nullptr); passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - passenger->m_movementInfo.transport.guid.Clear(); - passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); + passenger->m_movementInfo.transport.Reset(); } } } diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 75fc9f9ee..cc038e722 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -68,8 +68,6 @@ public: PassengerSet const& GetStaticPassengers() const { return _staticPassengers; } void UnloadStaticPassengers(); void UnloadNonStaticPassengers(); - void SetPassengersLoaded(bool loaded) { _passengersLoaded = loaded; } - bool PassengersLoaded() const { return _passengersLoaded; } KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; } void EnableMovement(bool enabled); @@ -104,7 +102,6 @@ private: PassengerSet _staticPassengers; mutable std::mutex Lock; - bool _passengersLoaded; bool _delayedTeleport; }; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b308603bc..be8dc1941 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -32,7 +32,6 @@ #include "CreatureAIImpl.h" #include "CreatureGroups.h" #include "DisableMgr.h" -#include "DynamicVisibility.h" #include "Formulas.h" #include "GameObjectAI.h" #include "GameTime.h" @@ -44,6 +43,7 @@ #include "MoveSpline.h" #include "MoveSplineInit.h" #include "MovementGenerator.h" +#include "MovementPacketBuilder.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -567,11 +567,19 @@ void Unit::UpdateSplineMovement(uint32 t_diff) // this code cant be placed inside EscortMovementGenerator, because we cant delete active MoveGen while it is updated SplineHandler handler(this); movespline->updateState(t_diff, handler); - // Xinef: Spline was cleared by StopMoving, return - if (!movespline->Initialized()) + + if (movespline->isCyclic()) { - DisableSpline(); - return; + m_splineSyncTimer.Update(t_diff); + if (m_splineSyncTimer.Passed()) + { + m_splineSyncTimer.Reset(5000); // Retail value, do not change + + WorldPacket data(SMSG_FLIGHT_SPLINE_SYNC, 4 + GetPackGUID().size()); + Movement::PacketBuilder::WriteSplineSync(*movespline, data); + data.appendPackGUID(GetGUID()); + SendMessageToSet(&data, true); + } } bool arrived = movespline->Finalized(); @@ -584,17 +592,11 @@ void Unit::UpdateSplineMovement(uint32 t_diff) SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, movespline->GetAnimationType()); } - // pussywizard: update always! not every 400ms, because movement generators need the actual position - //m_movesplineTimer.Update(t_diff); - //if (m_movesplineTimer.Passed() || arrived) UpdateSplinePosition(); } void Unit::UpdateSplinePosition() { - //static uint32 const positionUpdateDelay = 400; - - //m_movesplineTimer.Reset(positionUpdateDelay); Movement::Location loc = movespline->ComputePosition(); if (movespline->onTransport) @@ -607,16 +609,14 @@ void Unit::UpdateSplinePosition() if (TransportBase* transport = GetDirectTransport()) transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation); + else + return; } - // Xinef: if we had spline running update orientation along with position - //if (HasUnitState(UNIT_STATE_CANNOT_TURN)) - // loc.orientation = GetOrientation(); + if (HasUnitState(UNIT_STATE_CANNOT_TURN)) + loc.orientation = GetOrientation(); - if (GetTypeId() == TYPEID_PLAYER) - UpdatePosition(loc.x, loc.y, loc.z, loc.orientation); - else - ToCreature()->SetPosition(loc.x, loc.y, loc.z, loc.orientation); + UpdatePosition(loc.x, loc.y, loc.z, loc.orientation); } void Unit::DisableSpline() @@ -15709,15 +15709,9 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) void Unit::CleanupsBeforeDelete(bool finalCleanup) { - if (GetTransport()) - { - GetTransport()->RemovePassenger(this); - SetTransport(nullptr); - m_movementInfo.transport.Reset(); - m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - } - CleanupBeforeRemoveFromMap(finalCleanup); + + WorldObject::CleanupsBeforeDelete(finalCleanup); } void Unit::UpdateCharmAI() @@ -20253,10 +20247,14 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel if (!Acore::IsValidMapCoord(x, y, z, orientation)) return false; - float old_orientation = GetOrientation(); - float current_z = GetPositionZ(); - bool turn = (old_orientation != orientation); - bool relocated = (teleport || GetPositionX() != x || GetPositionY() != y || current_z != z); + // Check if angular distance changed + bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f); + + // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal + bool const relocated = (teleport || + std::fabs(GetPositionX() - x) > 0.001f || + std::fabs(GetPositionY() - y) > 0.001f || + std::fabs(GetPositionZ() - z) > 0.001f); if (!GetVehicle()) { @@ -20282,6 +20280,8 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel UpdateObjectVisibility(false); } + UpdatePositionData(); + return (relocated || turn); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5fe385fb7..bdd2a0891 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2575,7 +2575,7 @@ private: uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; uint32 m_lastManaUse; // msecs - //TimeTrackerSmall m_movesplineTimer; + TimeTrackerSmall m_splineSyncTimer; Diminishing m_Diminishing; // Manage all Units that are threatened by us diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index b33502da2..de264e947 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -545,7 +545,8 @@ bool Vehicle::IsVehicleInUse() void Vehicle::TeleportVehicle(float x, float y, float z, float ang) { - _me->GetMap()->LoadGrid(x, y); + if (!_me->GetMap()->IsGridLoaded(x, y)) + _me->GetMap()->LoadGrid(x, y); _me->NearTeleportTo(x, y, z, ang, true); for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr) diff --git a/src/server/game/Grids/NGrid.cpp b/src/server/game/Grids/NGrid.cpp index c20bf5558..337d7dded 100644 --- a/src/server/game/Grids/NGrid.cpp +++ b/src/server/game/Grids/NGrid.cpp @@ -23,7 +23,7 @@ i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(f { } -GridInfo::GridInfo(std::chrono::seconds expiry, bool unload /*= true */) : i_timer(expiry.count()), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)), +GridInfo::GridInfo(time_t expiry, bool unload /*= true */) : i_timer(expiry), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), i_unloadReferenceLock(false) { } diff --git a/src/server/game/Grids/NGrid.h b/src/server/game/Grids/NGrid.h index a49a29919..9a8f64fdb 100644 --- a/src/server/game/Grids/NGrid.h +++ b/src/server/game/Grids/NGrid.h @@ -32,7 +32,7 @@ class AC_GAME_API GridInfo { public: GridInfo(); - GridInfo(std::chrono::seconds expiry, bool unload = true); + GridInfo(time_t expiry, bool unload = true); TimeTracker const& getTimeTracker() const { return i_timer; } bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; } void setUnloadExplicitLock(bool on) { i_unloadExplicitLock = on; } @@ -73,7 +73,7 @@ class NGrid { public: typedef Grid GridType; - NGrid(uint32 id, int32 x, int32 y, std::chrono::seconds expiry, bool unload = true) : + NGrid(uint32 id, int32 x, int32 y, time_t expiry, bool unload = true) : i_gridId(id), i_GridInfo(GridInfo(expiry, unload)), i_x(x), i_y(y), i_cellstate(GRID_STATE_INVALID), i_GridObjectDataLoaded(false) { } @@ -111,8 +111,8 @@ public: void setUnloadReferenceLock(bool on) { i_GridInfo.setUnloadReferenceLock(on); } void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); } void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); } - void ResetTimeTracker(std::chrono::seconds interval) { i_GridInfo.ResetTimeTracker(interval.count()); } - void UpdateTimeTracker(std::chrono::seconds diff) { i_GridInfo.UpdateTimeTracker(diff.count()); } + void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); } + void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); } /* template void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index c9e9bd735..9b8ae064f 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -86,7 +86,7 @@ void VisibleNotifier::SendToSelf() i_data.BuildPacket(&packet); i_player.GetSession()->SendPacket(&packet); - for (std::vector::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) + for (std::set::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) { i_player.GetInitialVisiblePackets(*it); } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index c634fe9e3..86fbfe44d 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -42,16 +42,10 @@ namespace Acore { Player& i_player; GuidUnorderedSet vis_guids; - std::vector& i_visibleNow; - bool i_gobjOnly; + std::set i_visibleNow; UpdateData i_data; - VisibleNotifier(Player& player, bool gobjOnly) : - i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly) - { - i_visibleNow.clear(); - } - + VisibleNotifier(Player& player) : i_player(player), vis_guids(player.m_clientGUIDs) {} template void Visit(GridRefMgr& m); void SendToSelf(void); }; @@ -69,7 +63,7 @@ namespace Acore struct PlayerRelocationNotifier : public VisibleNotifier { - PlayerRelocationNotifier(Player& player) : VisibleNotifier(player, false) { } + PlayerRelocationNotifier(Player& player) : VisibleNotifier(player) { } template void Visit(GridRefMgr& m) { VisibleNotifier::Visit(m); } void Visit(CreatureMapType&); diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 00d967880..8741828ea 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -32,10 +32,6 @@ template inline void Acore::VisibleNotifier::Visit(GridRefMgr& m) { - // Xinef: Update gameobjects only - if (i_gobjOnly) - return; - for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ++iter) { vis_guids.erase(iter->GetSource()->GetGUID()); diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index c0d9e78c0..09e66bc96 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -25,6 +25,7 @@ #include "ObjectMgr.h" #include "Transport.h" #include "Vehicle.h" +#include "GameTime.h" void ObjectGridEvacuator::Visit(CreatureMapType& m) { @@ -113,18 +114,6 @@ void AddObjectHelper(CellCoord& cell, CreatureMapType& m, uint32& count, Map* ma ++count; } -template <> -void AddObjectHelper(CellCoord& cell, GameObjectMapType& m, uint32& count, Map* map, GameObject* obj) -{ - obj->AddToGrid(m); - ObjectGridLoader::SetObjectCell(obj, cell); - obj->AddToWorld(); - if (obj->isActiveObject()) - map->AddToActive(obj); - - ++count; -} - template void LoadHelper(CellGuidSet const& /*guid_set*/, CellCoord& /*cell*/, GridRefMgr& /*m*/, uint32& /*count*/, Map* /*map*/) { @@ -135,8 +124,13 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgrGetCreatureRespawnTime(guid) > now) + continue; + + Creature* obj = new Creature(); if (!obj->LoadFromDB(guid, map)) { delete obj; @@ -162,7 +156,12 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgrGetGORespawnTime(guid) > now) + continue; + GameObjectData const* data = sObjectMgr->GetGameObjectData(guid); GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject(); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index f0889150b..551fea862 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -49,19 +49,20 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& /*recvData*/) void WorldSession::HandleMoveWorldportAck() { + Player* player = GetPlayer(); // ignore unexpected far teleports - if (!GetPlayer()->IsBeingTeleportedFar()) + if (!player->IsBeingTeleportedFar()) return; - GetPlayer()->SetSemaphoreTeleportFar(0); + player->SetSemaphoreTeleportFar(0); // get the teleport destination - WorldLocation const& loc = GetPlayer()->GetTeleportDest(); + WorldLocation const& loc = player->GetTeleportDest(); // possible errors in the coordinate validity check if (!MapMgr::IsValidMapCoord(loc)) { - KickPlayer("!MapMgr::IsValidMapCoord(loc)"); + LogoutPlayer(false); return; } @@ -69,198 +70,202 @@ void WorldSession::HandleMoveWorldportAck() MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId()); - Map* oldMap = GetPlayer()->GetMap(); - if (GetPlayer()->IsInWorld()) + Map* oldMap = player->GetMap(); + if (player->IsInWorld()) { - LOG_ERROR("network.opcode", "Player (Name {}) is still in world when teleported from map {} to new map {}", GetPlayer()->GetName(), oldMap->GetId(), loc.GetMapId()); - oldMap->RemovePlayerFromMap(GetPlayer(), false); + LOG_ERROR("network.opcode", "Player (Name {}) is still in world when teleported from map {} to new map {}", player->GetName(), oldMap->GetId(), loc.GetMapId()); + oldMap->RemovePlayerFromMap(player, false); } // reset instance validity, except if going to an instance inside an instance - if (!GetPlayer()->m_InstanceValid && !mInstance) + if (!player->m_InstanceValid && !mInstance) { - GetPlayer()->m_InstanceValid = true; + player->m_InstanceValid = true; // pussywizard: m_InstanceValid can be false only by leaving a group in an instance => so remove temp binds that could not be removed because player was still on the map! - if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty())) - sInstanceSaveMgr->PlayerUnbindInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true); + if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty())) + sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true); } // relocate the player to the teleport destination - Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer()); + Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), player); // the CanEnter checks are done in TeleporTo but conditions may change // while the player is in transit, for example the map may get full - if (!newMap || newMap->CannotEnter(GetPlayer(), false)) + if (!newMap || newMap->CannotEnter(player, false)) { - LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString()); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO); + LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), player->GetGUID().ToString()); + player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO); return; } - float z = loc.GetPositionZ() + GetPlayer()->GetHoverHeight(); - GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); + float z = loc.GetPositionZ() + player->GetHoverHeight(); + player->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(newMap); + player->ResetMap(); + player->SetMap(newMap); - GetPlayer()->UpdatePositionData(); + player->UpdatePositionData(); - GetPlayer()->SendInitialPacketsBeforeAddToMap(); - if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) + player->SendInitialPacketsBeforeAddToMap(); + if (!player->GetMap()->AddPlayerToMap(player)) { LOG_ERROR("network.opcode", "WORLD: failed to teleport player {} ({}) to map {} because of unknown reason!", - GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString(), loc.GetMapId()); - GetPlayer()->ResetMap(); - GetPlayer()->SetMap(oldMap); - GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO); + player->GetName(), player->GetGUID().ToString(), loc.GetMapId()); + player->ResetMap(); + player->SetMap(oldMap); + player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO); return; } oldMap->AfterPlayerUnlinkFromMap(); // pussywizard: transport teleport couldn't teleport us to the same map (some other teleport pending, reqs not met, etc.), but we still have transport set until player moves! clear it if map differs (crashfix) - if (Transport* t = _player->GetTransport()) - if (!t->IsInMap(_player)) + if (Transport* t = player->GetTransport()) + if (!t->IsInMap(player)) { - t->RemovePassenger(_player); - _player->m_transport = nullptr; - _player->m_movementInfo.transport.Reset(); - _player->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + t->RemovePassenger(player); + player->m_transport = nullptr; + player->m_movementInfo.transport.Reset(); + player->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); } - if (!_player->getHostileRefMgr().IsEmpty()) - _player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix + if (!player->getHostileRefMgr().IsEmpty()) + player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix - CellCoord pair(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY())); + CellCoord pair(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY())); Cell cell(pair); if (!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid()) { - KickPlayer("!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid()"); + LogoutPlayer(false); return; } - newMap->LoadGrid(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); + + if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY())) + newMap->LoadGrid(player->GetPositionX(), player->GetPositionY()); // pussywizard: player supposed to enter bg map - if (_player->InBattleground()) + if (player->InBattleground()) { // but landed on another map, cleanup data if (!mEntry->IsBattlegroundOrArena()) - _player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL); + player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL); // everything ok - else if (Battleground* bg = _player->GetBattleground()) + else if (Battleground* bg = player->GetBattleground()) { - if (_player->IsInvitedForBattlegroundInstance()) // GMs are not invited, so they are not added to participants - bg->AddPlayer(_player); + if (player->IsInvitedForBattlegroundInstance()) // GMs are not invited, so they are not added to participants + bg->AddPlayer(player); } } // pussywizard: arena spectator stuff { - if (newMap->IsBattleArena() && ((BattlegroundMap*)newMap)->GetBG() && _player->HasPendingSpectatorForBG(((BattlegroundMap*)newMap)->GetInstanceId())) + if (newMap->IsBattleArena() && ((BattlegroundMap*)newMap)->GetBG() && player->HasPendingSpectatorForBG(((BattlegroundMap*)newMap)->GetInstanceId())) { - _player->ClearReceivedSpectatorResetFor(); - _player->SetIsSpectator(true); - ArenaSpectator::SendCommand(_player, "%sENABLE", SPECTATOR_ADDON_PREFIX); - ((BattlegroundMap*)newMap)->GetBG()->AddSpectator(_player); - ArenaSpectator::HandleResetCommand(_player); + player->ClearReceivedSpectatorResetFor(); + player->SetIsSpectator(true); + ArenaSpectator::SendCommand(player, "%sENABLE", SPECTATOR_ADDON_PREFIX); + ((BattlegroundMap*)newMap)->GetBG()->AddSpectator(player); + ArenaSpectator::HandleResetCommand(player); } else - _player->SetIsSpectator(false); + player->SetIsSpectator(false); - GetPlayer()->SetPendingSpectatorForBG(0); + player->SetPendingSpectatorForBG(0); - if (uint32 inviteInstanceId = _player->GetPendingSpectatorInviteInstanceId()) + if (uint32 inviteInstanceId = player->GetPendingSpectatorInviteInstanceId()) { if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE)) - tbg->RemoveToBeTeleported(_player->GetGUID()); - _player->SetPendingSpectatorInviteInstanceId(0); + tbg->RemoveToBeTeleported(player->GetGUID()); + player->SetPendingSpectatorInviteInstanceId(0); } } - // xinef: do this again, player can be teleported inside bg->AddPlayer(_player)!!!! - CellCoord pair2(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY())); + // xinef: do this again, player can be teleported inside bg->AddPlayer(player)!!!! + CellCoord pair2(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY())); Cell cell2(pair2); if (!GridCoord(cell2.GridX(), cell2.GridY()).IsCoordValid()) { KickPlayer("!GridCoord(cell2.GridX(), cell2.GridY()).IsCoordValid()"); return; } - newMap->LoadGrid(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); - GetPlayer()->SendInitialPacketsAfterAddToMap(); + if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY())) + newMap->LoadGrid(player->GetPositionX(), player->GetPositionY()); + + player->SendInitialPacketsAfterAddToMap(); // flight fast teleport case - if (GetPlayer()->IsInFlight()) + if (player->IsInFlight()) { - if (!GetPlayer()->InBattleground()) + if (!player->InBattleground()) { // short preparations to continue flight - MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top(); - movementGenerator->Initialize(GetPlayer()); + MovementGenerator* movementGenerator = player->GetMotionMaster()->top(); + movementGenerator->Initialize(player); return; } // battleground state prepare, stop flight - GetPlayer()->GetMotionMaster()->MovementExpired(); - GetPlayer()->CleanupAfterTaxiFlight(); + player->GetMotionMaster()->MovementExpired(); + player->CleanupAfterTaxiFlight(); } // resurrect character at enter into instance where his corpse exist after add to map - Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID()); + Corpse* corpse = player->GetMap()->GetCorpseByPlayer(player->GetGUID()); if (corpse && corpse->GetType() != CORPSE_BONES) { if (mEntry->IsDungeon()) { - GetPlayer()->ResurrectPlayer(0.5f); - GetPlayer()->SpawnCorpseBones(); + player->ResurrectPlayer(0.5f); + player->SpawnCorpseBones(); } } if (!corpse && mEntry->IsDungeon()) { // resurrect character upon entering instance when the corpse is not available anymore - if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->MapID) + if (player->GetCorpseLocation().GetMapId() == mEntry->MapID) { - GetPlayer()->ResurrectPlayer(0.5f); - GetPlayer()->RemoveCorpse(); + player->ResurrectPlayer(0.5f); + player->RemoveCorpse(); } } bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena(); if (mInstance) { - Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); + Difficulty diff = player->GetDifficulty(mEntry->IsRaid()); if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff)) if (mapDiff->resetTime) if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff)) { uint32 timeleft = uint32(timeReset - GameTime::GetGameTime().count()); - GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true); + player->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true); } allowMount = mInstance->AllowMount; } // mount allow check if (!allowMount) - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); + player->RemoveAurasByType(SPELL_AURA_MOUNTED); // update zone immediately, otherwise leave channel will cause crash in mtmap uint32 newzone, newarea; - GetPlayer()->GetZoneAndAreaId(newzone, newarea); - GetPlayer()->UpdateZone(newzone, newarea); + player->GetZoneAndAreaId(newzone, newarea); + player->UpdateZone(newzone, newarea); // honorless target - if (GetPlayer()->pvpInfo.IsHostile) - GetPlayer()->CastSpell(GetPlayer(), 2479, true); + if (player->pvpInfo.IsHostile) + player->CastSpell(player, 2479, true); // in friendly area - else if (GetPlayer()->IsPvP() && !GetPlayer()->HasPlayerFlag(PLAYER_FLAGS_IN_PVP)) - GetPlayer()->UpdatePvP(false, false); + else if (player->IsPvP() && !player->HasPlayerFlag(PLAYER_FLAGS_IN_PVP)) + player->UpdatePvP(false, false); // resummon pet - GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); + player->ResummonPetTemporaryUnSummonedIfAny(); //lets process all delayed operations on successful teleport - GetPlayer()->ProcessDelayedOperations(); + player->ProcessDelayedOperations(); } void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index e66ef5c9b..643c884d1 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -69,6 +69,11 @@ Map::~Map() sScriptMgr->OnDestroyMap(this); + // Delete all waiting spawns, else there will be a memory leak + // This doesn't delete from database. + _creatureRespawnTimes.clear(); + _goRespawnTimes.clear(); + while (!i_worldObjects.empty()) { WorldObject* obj = *i_worldObjects.begin(); @@ -237,7 +242,7 @@ void Map::LoadMapAndVMap(int gx, int gy) } } -Map::Map(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : +Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : _creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0), @@ -440,6 +445,9 @@ void Map::DeleteFromWorld(Player* player) void Map::EnsureGridCreated(const GridCoord& p) { + if (getNGrid(p.x_coord, p.y_coord)) + return; + std::lock_guard guard(GridLock); EnsureGridCreated_i(p); } @@ -493,13 +501,13 @@ bool Map::EnsureGridLoaded(const Cell& cell) NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); ASSERT(grid); - if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) + if (!grid->isGridObjectDataLoaded()) { //if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) //{ LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); - setGridObjectDataLoaded(true, cell.GridX(), cell.GridY()); + grid->setGridObjectDataLoaded(true); ObjectGridLoader loader(*grid, this, cell); loader.LoadN(); @@ -685,15 +693,7 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/) return false; //Should delete object } - Cell cell(cellCoord); - if (obj->isActiveObject()) - EnsureGridLoaded(cell); - obj->AddToWorld(); - - if (obj->isActiveObject()) - AddToActive(obj); - _transports.insert(obj); // Broadcast creation to players @@ -717,7 +717,8 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/) bool Map::IsGridLoaded(const GridCoord& p) const { - return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); + NGridType* grid = getNGrid(p.x_coord, p.y_coord); + return grid && grid->isGridObjectDataLoaded(); } void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor& gridVisitor, @@ -746,7 +747,7 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor updateList; updateList.reserve(10); - // non-player active objects, increasing iterator in the loop in case of object removal - for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) - { - WorldObject* obj = *m_activeNonPlayersIter; - ++m_activeNonPlayersIter; - - if (!obj || !obj->IsInWorld()) - continue; - - VisitNearbyCellsOf(obj, grid_object_update, world_object_update); - } - // the player iterator is stored in the map object // to make sure calls to Map::Remove don't invalidate it for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter) @@ -836,6 +825,18 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) } } + // non-player active objects, increasing iterator in the loop in case of object removal + for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) + { + WorldObject* obj = *m_activeNonPlayersIter; + ++m_activeNonPlayersIter; + + if (!obj || !obj->IsInWorld()) + continue; + + VisitNearbyCellsOf(obj, grid_object_update, world_object_update); + } + for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) // pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok { MotionTransport* transport = *_transportsUpdateIter; @@ -1015,8 +1016,6 @@ template<> void Map::RemoveFromMap(MotionTransport* obj, bool remove) { obj->RemoveFromWorld(); - if (obj->isActiveObject()) - RemoveFromActive(obj); Map::PlayerList const& players = GetPlayers(); if (!players.IsEmpty()) @@ -1060,6 +1059,10 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o) Cell old_cell(player->GetPositionX(), player->GetPositionY()); Cell new_cell(x, y); + player->Relocate(x, y, z, o); + if (player->IsVehicle()) + player->GetVehicleKit()->RelocatePassengers(); + if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) { LOG_DEBUG("maps", "Player {} relocation grid[{}, {}]cell[{}, {}]->grid[{}, {}]cell[{}, {}]", player->GetName().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); @@ -1072,64 +1075,63 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o) AddToGrid(player, new_cell); } - player->Relocate(x, y, z, o); - if (player->IsVehicle()) - player->GetVehicleKit()->RelocatePassengers(); player->UpdatePositionData(); player->UpdateObjectVisibility(false); } -void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float o) +void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float o, bool respawnRelocationOnFail) { Cell old_cell = creature->GetCurrentCell(); Cell new_cell(x, y); + if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY())) + return; + + // delay creature move for grid/cell to grid/cell moves if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) { - if (old_cell.DiffGrid(new_cell)) - EnsureGridLoaded(new_cell); - #ifdef ACORE_DEBUG LOG_DEBUG("maps", "Creature {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", creature->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); #endif AddCreatureToMoveList(creature, x, y, z, o); + // in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList } else { + creature->Relocate(x, y, z, o); + if (creature->IsVehicle()) + creature->GetVehicleKit()->RelocatePassengers(); + creature->UpdateObjectVisibility(false); + creature->UpdatePositionData(); RemoveCreatureFromMoveList(creature); } - - creature->Relocate(x, y, z, o); - if (creature->IsVehicle()) - creature->GetVehicleKit()->RelocatePassengers(); - creature->UpdatePositionData(); - creature->UpdateObjectVisibility(false); } -void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float o) +void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float o, bool respawnRelocationOnFail) { Cell old_cell = go->GetCurrentCell(); Cell new_cell(x, y); + if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY())) + return; + + // delay creature move for grid/cell to grid/cell moves if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) { - if (old_cell.DiffGrid(new_cell)) - EnsureGridLoaded(new_cell); - #ifdef ACORE_DEBUG LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); #endif AddGameObjectToMoveList(go, x, y, z, o); + // in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList } else { + go->Relocate(x, y, z, o); + go->UpdateModelPosition(); + go->SetPositionDataUpdate(); + go->UpdateObjectVisibility(false); RemoveGameObjectFromMoveList(go); } - - go->Relocate(x, y, z, o); - go->UpdateModelPosition(); - go->SetPositionDataUpdate(); - go->UpdateObjectVisibility(false); } void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float z, float o) @@ -1137,24 +1139,25 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float Cell old_cell = dynObj->GetCurrentCell(); Cell new_cell(x, y); + if (!getNGrid(new_cell.GridX(), new_cell.GridY())) + return; + + // delay creature move for grid/cell to grid/cell moves if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell)) { - if (old_cell.DiffGrid(new_cell)) - EnsureGridLoaded(new_cell); - #ifdef ACORE_DEBUG LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", dynObj->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); #endif AddDynamicObjectToMoveList(dynObj, x, y, z, o); + // in diffcell/diffgrid case notifiers called at finishing move dynObj in Map::MoveAllGameObjectsInMoveList } else { + dynObj->Relocate(x, y, z, o); + dynObj->SetPositionDataUpdate(); + dynObj->UpdateObjectVisibility(false); RemoveDynamicObjectFromMoveList(dynObj); } - - dynObj->Relocate(x, y, z, o); - dynObj->SetPositionDataUpdate(); - dynObj->UpdateObjectVisibility(false); } void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang) @@ -3150,11 +3153,14 @@ void Map::RemoveAllObjectsInRemoveList() RemoveFromMap((DynamicObject*)obj, true); break; case TYPEID_GAMEOBJECT: - if (MotionTransport* transport = obj->ToGameObject()->ToMotionTransport()) + { + GameObject* go = obj->ToGameObject(); + if (MotionTransport* transport = go->ToMotionTransport()) RemoveFromMap(transport, true); else - RemoveFromMap(obj->ToGameObject(), true); + RemoveFromMap(go, true); break; + } case TYPEID_UNIT: // in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call // make sure that like sources auras/etc removed before destructor start @@ -3258,12 +3264,6 @@ void Map::AddToActive(DynamicObject* d) AddToActiveHelper(d); } -template<> -void Map::AddToActive(GameObject* d) -{ - AddToActiveHelper(d); -} - template void Map::RemoveFromActive(T* obj) { @@ -3298,12 +3298,6 @@ void Map::RemoveFromActive(DynamicObject* obj) RemoveFromActiveHelper(obj); } -template<> -void Map::RemoveFromActive(GameObject* obj) -{ - RemoveFromActiveHelper(obj); -} - template bool Map::AddToMap(Corpse*, bool); template bool Map::AddToMap(Creature*, bool); template bool Map::AddToMap(GameObject*, bool); @@ -3316,7 +3310,7 @@ template void Map::RemoveFromMap(DynamicObject*, bool); /* ******* Dungeon Instance Maps ******* */ -InstanceMap::InstanceMap(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) +InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : Map(id, expiry, InstanceId, SpawnMode, _parent), m_resetAfterUnload(false), m_unloadWhenEmpty(false), instance_data(nullptr), i_script_id(0) @@ -3726,7 +3720,7 @@ uint32 InstanceMap::GetMaxResetDelay() const /* ******* Battleground Instance Maps ******* */ -BattlegroundMap::BattlegroundMap(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) +BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) : Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr) { //lets initialize visibility distance for BG/Arenas diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 9b607a1af..fff1c5785 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -311,7 +311,7 @@ class Map : public GridRefMgr { friend class MapReference; public: - Map(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr); + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr); ~Map() override; [[nodiscard]] MapEntry const* GetEntry() const { return i_mapEntry; } @@ -346,12 +346,18 @@ public: virtual void InitVisibilityDistance(); void PlayerRelocation(Player*, float x, float y, float z, float o); - void CreatureRelocation(Creature* creature, float x, float y, float z, float o); - void GameObjectRelocation(GameObject* go, float x, float y, float z, float o); + void CreatureRelocation(Creature* creature, float x, float y, float z, float o, bool respawnRelocationOnFail = true); + void GameObjectRelocation(GameObject* go, float x, float y, float z, float o, bool respawnRelocationOnFail = true); void DynamicObjectRelocation(DynamicObject* go, float x, float y, float z, float o); template void Visit(const Cell& cell, TypeContainerVisitor& visitor); + [[nodiscard]] bool IsActiveGrid(float x, float y) const + { + GridCoord p = Acore::ComputeGridCoord(x, y); + return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_ACTIVE; + } + [[nodiscard]] bool IsRemovalGrid(float x, float y) const { GridCoord p = Acore::ComputeGridCoord(x, y); @@ -374,10 +380,10 @@ public: void ResetGridExpiry(NGridType& grid, float factor = 1) const { - grid.ResetTimeTracker(std::chrono::duration_cast(i_gridExpiry * factor)); + grid.ResetTimeTracker(time_t(float(i_gridExpiry) * factor)); } - [[nodiscard]] std::chrono::seconds GetGridExpiry(void) const { return i_gridExpiry; } + [[nodiscard]] time_t GetGridExpiry(void) const { return i_gridExpiry; } [[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; } static void InitStateMachine(); @@ -702,9 +708,6 @@ private: } bool EnsureGridLoaded(Cell const&); - [[nodiscard]] bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x, y)->isGridObjectDataLoaded(); } - void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x, y)->setGridObjectDataLoaded(pLoaded); } - void setNGrid(NGridType* grid, uint32 x, uint32 y); void ScriptsProcess(); @@ -750,7 +753,7 @@ private: void _ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const; GameObject* _FindGameObject(WorldObject* pWorldObject, ObjectGuid::LowType guid) const; - std::chrono::seconds i_gridExpiry; + time_t i_gridExpiry; //used for fast base_map (e.g. MapInstanced class object) search for //InstanceMaps and BattlegroundMaps... @@ -839,7 +842,7 @@ enum InstanceResetMethod class InstanceMap : public Map { public: - InstanceMap(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent); + InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); ~InstanceMap() override; bool AddPlayerToMap(Player*) override; void RemovePlayerFromMap(Player*, bool) override; @@ -873,7 +876,7 @@ private: class BattlegroundMap : public Map { public: - BattlegroundMap(uint32 id, std::chrono::seconds, uint32 InstanceId, Map* _parent, uint8 spawnMode); + BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); ~BattlegroundMap() override; bool AddPlayerToMap(Player*) override; @@ -898,11 +901,12 @@ inline void Map::Visit(Cell const& cell, TypeContainerVisitor& vis const uint32 cell_x = cell.CellX(); const uint32 cell_y = cell.CellY(); - if (!cell.NoCreate() || IsGridLoaded(GridCoord(x, y))) - { + if (!cell.NoCreate()) EnsureGridLoaded(cell); - getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor); - } + + NGridType* grid = getNGrid(x, y); + if (grid && grid->isGridObjectDataLoaded()) + grid->VisitGrid(cell_x, cell_y, visitor); } #endif diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 2ce5bbfbc..36b593010 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -25,8 +25,9 @@ #include "Player.h" #include "ScriptMgr.h" #include "VMapFactory.h" +#include "VMapMgr2.h" -MapInstanced::MapInstanced(uint32 id, std::chrono::seconds expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) +MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) { // fill with zero memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS * sizeof(uint16)); @@ -260,6 +261,15 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator& itr) sScriptMgr->OnDestroyInstance(this, itr->second); itr->second->UnloadAll(); + // should only unload VMaps if this is the last instance + if (m_InstancedMaps.size() <= 1) + { + VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(itr->second->GetId()); + MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(itr->second->GetId()); + // in that case, unload grids of the base map, too + // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded + Map::UnloadAll(); + } // erase map delete itr->second; diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index fd86b8fa6..e2deef157 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -28,7 +28,7 @@ class MapInstanced : public Map public: using InstancedMaps = std::unordered_map; - MapInstanced(uint32 id, std::chrono::seconds expiry); + MapInstanced(uint32 id, time_t expiry); ~MapInstanced() override {} // functions overwrite Map versions diff --git a/src/server/game/Maps/MapMgr.cpp b/src/server/game/Maps/MapMgr.cpp index 980b7898f..5c95475fb 100644 --- a/src/server/game/Maps/MapMgr.cpp +++ b/src/server/game/Maps/MapMgr.cpp @@ -84,10 +84,10 @@ Map* MapMgr::CreateBaseMap(uint32 id) ASSERT(entry); if (entry->Instanceable()) - map = new MapInstanced(id, std::chrono::seconds(i_gridCleanUpDelay)); + map = new MapInstanced(id, i_gridCleanUpDelay); else { - map = new Map(id, std::chrono::seconds(i_gridCleanUpDelay), 0, REGULAR_DIFFICULTY); + map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); map->LoadRespawnTimes(); map->LoadCorpseData(); } diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index e6ad171d3..5d7a65f64 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -411,8 +411,6 @@ MotionTransport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType if (map && map->IsDungeon()) trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript(); - // xinef: transports are active so passengers can be relocated (grids must be loaded) - trans->setActive(true); HashMapHolder::Insert(trans); trans->GetMap()->AddToMap(trans); return trans; diff --git a/src/server/game/Misc/DynamicVisibility.cpp b/src/server/game/Misc/DynamicVisibility.cpp deleted file mode 100644 index 60889c4bc..000000000 --- a/src/server/game/Misc/DynamicVisibility.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "DynamicVisibility.h" - -uint8 DynamicVisibilityMgr::visibilitySettingsIndex = 0; - -void DynamicVisibilityMgr::Update(uint32 sessionCount) -{ - if (sessionCount >= (visibilitySettingsIndex + 1) * ((uint32)VISIBILITY_SETTINGS_PLAYER_INTERVAL) && visibilitySettingsIndex < VISIBILITY_SETTINGS_MAX_INTERVAL_NUM - 1) - ++visibilitySettingsIndex; - else if (visibilitySettingsIndex && sessionCount < visibilitySettingsIndex * ((uint32)VISIBILITY_SETTINGS_PLAYER_INTERVAL) - 100) - --visibilitySettingsIndex; -} diff --git a/src/server/game/Misc/DynamicVisibility.h b/src/server/game/Misc/DynamicVisibility.h deleted file mode 100644 index cf38bfa50..000000000 --- a/src/server/game/Misc/DynamicVisibility.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by the - * Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef __DYNAMICVISIBILITY_H -#define __DYNAMICVISIBILITY_H - -#include "Common.h" - -struct VisibilitySettingData -{ - uint32 visibilityNotifyDelay; - uint32 aiNotifyDelay; - float requiredMoveDistanceSq; -}; - -// pussywizard: dynamic visibility settings -// 7 player intervals: 0-499, 500-999, 1000-1499, 1500-1999, 2000-2499, 2500-2999, 3000+ -// 5 map types: common, instance, raid, bg, arena -// feel free to add more intervals, change existing ones or move to conf file :P -#define VISIBILITY_SETTINGS_PLAYER_INTERVAL 500 -#define VISIBILITY_SETTINGS_MAX_INTERVAL_NUM 7 -const VisibilitySettingData VisibilitySettings[VISIBILITY_SETTINGS_MAX_INTERVAL_NUM][5] = -{ - { {300, 150, 1.0f}, {300, 150, 1.0f}, {300, 150, 1.0f}, {300, 150, 1.0f}, {300, 150, 1.0f} }, // 0-499 - { {400, 200, 2.25f}, {400, 200, 2.25f}, {400, 200, 2.25f}, {300, 150, 1.0f}, {300, 150, 1.0f} }, // 500-999 - { {500, 250, 4.0f}, {500, 250, 4.0f}, {500, 250, 4.0f}, {400, 200, 2.25f}, {300, 150, 1.0f} }, // 1000-1499 - { {700, 350, 6.25f}, {700, 350, 6.25f}, {700, 350, 6.25f}, {600, 300, 6.25f}, {300, 200, 1.0f} }, // 1500-1999 - { {1000, 500, 16.0f}, {1000, 500, 16.0f}, {1000, 500, 16.0f}, {1000, 500, 16.0f}, {300, 250, 1.0f} }, // 2000-2499 - { {1000, 500, 16.0f}, {1000, 500, 16.0f}, {1000, 500, 16.0f}, {1000, 500, 16.0f}, {300, 350, 1.0f} }, // 2500-2999 - { {1200, 550, 20.0f}, {1200, 550, 25.0f}, {1200, 550, 25.0f}, {1100, 550, 16.0f}, {300, 350, 1.0f} } // 3000+ -}; - -class DynamicVisibilityMgr -{ -public: - static void Update(uint32 sessionCount); - static uint32 GetVisibilityNotifyDelay(uint32 map_type) { return VisibilitySettings[visibilitySettingsIndex][map_type].visibilityNotifyDelay; } - static uint32 GetAINotifyDelay(uint32 map_type) { return VisibilitySettings[visibilitySettingsIndex][map_type].aiNotifyDelay; } - static float GetReqMoveDistSq(uint32 map_type) { return VisibilitySettings[visibilitySettingsIndex][map_type].requiredMoveDistanceSq; } -protected: - static uint8 visibilitySettingsIndex; -}; - -#endif diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 3d3be3769..0d230ee1a 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -125,14 +125,13 @@ namespace Movement if (args.flags.cyclic) { uint32 cyclic_point = 0; - // MoveSplineFlag::Enter_Cycle support dropped - //if (splineflags & SPLINEFLAG_ENTER_CYCLE) - //cyclic_point = 1; // shouldn't be modified, came from client - spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point); + if (splineflags.enter_cycle) + cyclic_point = 1; // shouldn't be modified, came from client + spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point, args.initialOrientation); } else { - spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]); + spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation); } // init spline timestamps @@ -204,7 +203,7 @@ namespace Movement if (!(exp)) \ { \ if (unit) \ - LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for {}", #exp, unit->GetGUID().ToString()); \ + LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for GUID: {} Entry: {}", #exp, unit->GetGUID().ToString().c_str(), unit->GetEntry());\ else \ LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for cyclic spline continuation", #exp); \ return false;\ @@ -273,6 +272,41 @@ namespace Movement point_Idx = spline.first(); time_passed = time_passed % Duration(); result = Movement::MoveSpline::UpdateResult(Result_NextCycle | Result_JustArrived); + + // Remove first point from the path after one full cycle. + // That point was the position of the unit prior to entering the cycle and it shouldn't be repeated with continuous cycles. + if (splineflags.enter_cycle) + { + splineflags.enter_cycle = false; + + MoveSplineInitArgs args{ (size_t)spline.getPointCount() }; + args.path.assign(spline.getPoints().begin() + spline.first() + 1, spline.getPoints().begin() + spline.last()); + args.facing = facing; + args.flags = splineflags; + args.path_Idx_offset = point_Idx_offset; + // MoveSplineFlag::Parabolic | MoveSplineFlag::Animation not supported currently + //args.parabolic_amplitude = ?; + //args.time_perc = ?; + args.splineId = m_Id; + args.initialOrientation = initialOrientation; + args.velocity = 1.0f; // Calculated below + args.HasVelocity = true; + args.TransformForTransport = onTransport; + if (args.Validate(nullptr)) + { + // New cycle should preserve previous cycle's duration for some weird reason, even though + // the path is really different now. Blizzard is weird. Or this was just a simple oversight. + // Since our splines precalculate length with velocity in mind, if we want to find the desired + // velocity, we have to make a fake spline, calculate its duration and then compare it to the + // desired duration, thus finding out how much the velocity has to be increased for them to match. + MoveSpline tempSpline; + tempSpline.Initialize(args); + args.velocity = (float)tempSpline.Duration() / Duration(); + + if (args.Validate(nullptr)) + init_spline(args); + } + } } else { diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index faf6cd203..0696a2449 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -87,6 +87,7 @@ namespace Movement // corrent first vertex args.path[0] = real_position; args.initialOrientation = real_position.orientation; + args.flags.enter_cycle = args.flags.cyclic; move_spline.onTransport = transport; uint32 moveFlags = unit->m_movementInfo.GetMovementFlags(); diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index b360c6b3d..d9e31d5e7 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -67,10 +67,6 @@ namespace Movement break; } - // add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done) - // Xinef: this flag breaks cycle for ground movement, client teleports npc between last and first point instead of using smooth movement - if (splineflags & MoveSplineFlag::Flying) - splineflags.enter_cycle = move_spline.isCyclic(); data << uint32(splineflags & uint32(~MoveSplineFlag::Mask_No_Monster_Move)); if (splineflags.animation) @@ -123,20 +119,11 @@ namespace Movement data.append(&spline.getPoint(2), count); } - void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data, bool flying) + void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data) { - uint32 count = spline.getPointCount() - 3; - data << uint32(count + 1); - if (flying) - { - data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done - data.append(&spline.getPoint(2), count); - } - else - { - data.append(&spline.getPoint(2), count); - data << Vector3::zero(); //Xinef: fake point - } + uint32 count = spline.getPointCount() - 4; + data << count; + data.append(&spline.getPoint(2), count); } void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, ByteBuffer& data) @@ -148,7 +135,7 @@ namespace Movement if (splineflags & MoveSplineFlag::Mask_CatmullRom) { if (splineflags.cyclic) - WriteCatmullRomCyclicPath(spline, data, splineflags & MoveSplineFlag::Flying); + WriteCatmullRomCyclicPath(spline, data); else WriteCatmullRomPath(spline, data); } @@ -199,4 +186,8 @@ namespace Movement data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination()); } } + void PacketBuilder::WriteSplineSync(MoveSpline const& move_spline, ByteBuffer& data) + { + data << (float)move_spline.timePassed() / move_spline.Duration(); + } } diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h index 711eccc33..2c577a492 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.h +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -38,6 +38,7 @@ namespace Movement static void WriteMonsterMove(const MoveSpline& mov, ByteBuffer& data); static void WriteStopMovement(Vector3 const& loc, uint32 splineId, ByteBuffer& data); static void WriteCreate(const MoveSpline& mov, ByteBuffer& data); + static void WriteSplineSync(MoveSpline const& mov, ByteBuffer& data); }; } #endif // AC_PACKET_BUILDER_H diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp index 601951a20..31bf6a6cb 100644 --- a/src/server/game/Movement/Spline/Spline.cpp +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -199,23 +199,25 @@ namespace Movement return length; } - void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m) + void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation) { m_mode = m; cyclic = false; + initialOrientation = orientation; - (this->*initializers[m_mode])(controls, count, cyclic, 0); + (this->*initializers[m_mode])(controls, count, 0); } - void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) + void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation) { m_mode = m; cyclic = true; + initialOrientation = orientation; - (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point); + (this->*initializers[m_mode])(controls, count, cyclic_point); } - void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) + void SplineBase::InitLinear(const Vector3* controls, index_type count, index_type cyclic_point) { ASSERT(count >= 2); const int real_size = count + 1; @@ -235,7 +237,7 @@ namespace Movement index_hi = cyclic ? count : (count - 1); } - void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) + void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, index_type cyclic_point) { const int real_size = count + (cyclic ? (1 + 2) : (1 + 1)); @@ -253,14 +255,14 @@ namespace Movement if (cyclic_point == 0) points[0] = controls[count - 1]; else - points[0] = controls[0].lerp(controls[1], -1); + points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; points[high_index + 1] = controls[cyclic_point]; points[high_index + 2] = controls[cyclic_point + 1]; } else { - points[0] = controls[0].lerp(controls[1], -1); + points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; points[high_index + 1] = controls[count - 1]; } @@ -268,7 +270,7 @@ namespace Movement index_hi = high_index + (cyclic ? 1 : 0); } - void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/) + void SplineBase::InitBezier3(const Vector3* controls, index_type count, index_type /*cyclic_point*/) { index_type c = count / 3u * 3u; index_type t = c / 3u; diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index d9d255f0a..afefffe62 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -48,6 +48,7 @@ namespace Movement uint8 m_mode{UninitializedMode}; bool cyclic{false}; + float initialOrientation; enum { @@ -77,15 +78,15 @@ namespace Movement typedef float (SplineBase::*SegLenghtMethtod)(index_type) const; static SegLenghtMethtod seglengths[ModesEnd]; - void InitLinear(const Vector3*, index_type, bool, index_type); - void InitCatmullRom(const Vector3*, index_type, bool, index_type); - void InitBezier3(const Vector3*, index_type, bool, index_type); - typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type); + void InitLinear(const Vector3*, index_type, index_type); + void InitCatmullRom(const Vector3*, index_type, index_type); + void InitBezier3(const Vector3*, index_type, index_type); + typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, index_type); static InitMethtod initializers[ModesEnd]; void UninitializedSplineEvaluationMethod(index_type, float, Vector3&) const { ABORT(); } - [[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); } - void UninitializedSplineInitMethod(Vector3 const*, index_type, bool, index_type) { ABORT(); } + [[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); return 0.0f; } + void UninitializedSplineInitMethod(Vector3 const*, index_type, index_type) { ABORT(); } public: explicit SplineBase() = default; @@ -116,8 +117,8 @@ namespace Movement [[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];} /** Initializes spline. Don't call other methods while spline not initialized. */ - void init_spline(const Vector3* controls, index_type count, EvaluationMode m); - void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point); + void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation); + void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation); /** As i can see there are a lot of ways how spline can be initialized would be no harm to have some custom initializers. */ @@ -170,8 +171,8 @@ namespace Movement void computeIndex(float t, index_type& out_idx, float& out_u) const; /** Initializes spline. Don't call other methods while spline not initialized. */ - void init_spline(const Vector3* controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);} - void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point);} + void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation = 0) { SplineBase::init_spline(controls, count, m, orientation);} + void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation = 0) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point, orientation);} /** Initializes lengths with SplineBase::SegLength method. */ void initLengths(); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 431897eeb..f8749091f 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2435,7 +2435,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo */ UnitList targets; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange()); Acore::UnitListSearcher searcher(target, targets, u_check); Cell::VisitAllObjects(target, searcher, target->GetMap()->GetVisibilityRange()); for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 7080b5c8f..da94ce4ed 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4048,7 +4048,7 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/) } UnitList targets; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, unitTarget->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, unitTarget->GetVisibilityRange()); Acore::UnitListSearcher searcher(unitTarget, targets, u_check); Cell::VisitAllObjects(unitTarget, searcher, unitTarget->GetVisibilityRange()); for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) @@ -4787,7 +4787,7 @@ void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/) WorldPacket data(SMSG_CLEAR_TARGET, 8); data << m_caster->GetGUID(); - float dist = m_caster->GetVisibilityRange() + VISIBILITY_COMPENSATION; + float dist = m_caster->GetVisibilityRange(); Acore::MessageDistDelivererToHostile notifier(m_caster, &data, dist); Cell::VisitWorldObjects(m_caster, notifier, dist); @@ -4812,7 +4812,7 @@ void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/) return; UnitList targets; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, m_caster->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, m_caster->GetVisibilityRange()); Acore::UnitListSearcher searcher(m_caster, targets, u_check); Cell::VisitAllObjects(m_caster, searcher, m_caster->GetVisibilityRange()); for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index f41e523b8..d301a1d26 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -44,7 +44,6 @@ #include "DBCStores.h" #include "DatabaseEnv.h" #include "DisableMgr.h" -#include "DynamicVisibility.h" #include "GameEventMgr.h" #include "GameGraveyard.h" #include "GameTime.h" @@ -2255,8 +2254,6 @@ void World::Update(uint32 diff) // Record update if recording set in log and diff is greater then minimum set in log sWorldUpdateTime.RecordUpdateTime(GameTime::GetGameTimeMS(), diff, GetActiveSessionCount()); - DynamicVisibilityMgr::Update(GetActiveSessionCount()); - ///- Update the different timers for (int i = 0; i < WUPDATE_COUNT; ++i) { diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp index 8ebc9569b..f52225e76 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp @@ -327,6 +327,7 @@ public: if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn)) { nefarian->setActive(true); + nefarian->SetFarVisible(true); nefarian->SetCanFly(true); nefarian->SetDisableGravity(true); nefarian->GetMotionMaster()->MovePath(NEFARIAN_PATH, false); diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp index a8aac9757..faddef617 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -425,6 +425,7 @@ public: { nefarius->SetPhaseMask(1, true); nefarius->setActive(true); + nefarius->SetFarVisible(true); nefarius->Respawn(); nefarius->GetMotionMaster()->MoveTargetedHome(); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 72ef3e5dd..71fd06450 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -105,6 +105,7 @@ struct boss_nightbane : public BossAI me->SetDisableGravity(_intro); me->SetWalk(false); me->setActive(true); + me->SetFarVisible(true); if (instance) { diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index 8d48baefa..cc26b66c8 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -55,6 +55,7 @@ public: void Reset() override { me->setActive(true); + me->SetFarVisible(true); me->SetVisible(false); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->SetCanFly(true); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp index 42817e795..a309d4bc3 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp @@ -347,6 +347,7 @@ void hyjalAI::Reset() { IsDummy = false; me->setActive(true); + me->SetFarVisible(true); // GUIDs PlayerGUID.Clear(); BossGUID[0].Clear(); @@ -493,6 +494,7 @@ void hyjalAI::SummonCreature(uint32 entry, float Base[4][3]) creature->SetWalk(false); creature->setActive(true); + creature->SetFarVisible(true); switch (entry) { case NECROMANCER: @@ -1021,6 +1023,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } for (uint8 i = 0; i < 3; ++i)//summon 3 abominations @@ -1033,6 +1036,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } for (uint8 i = 0; i < 5; ++i)//summon 5 gargoyles @@ -1045,6 +1049,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } break; @@ -1062,6 +1067,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } for (uint8 i = 0; i < 25; ++i)//summon 25 ghouls @@ -1074,6 +1080,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } for (uint8 i = 0; i < 5; ++i)//summon 5 abominations @@ -1086,6 +1093,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff) CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true; CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i; unit->setActive(true); + unit->SetFarVisible(true); } } break; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp index ec4498925..8297d8904 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp @@ -389,6 +389,7 @@ public: if (action == ACTION_BALTHARUS_DEATH) { me->setActive(true); + me->SetFarVisible(true); _isIntro = false; _events.ScheduleEvent(EVENT_XERESTRASZA_EVENT_0, 6s); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 968fcba47..d03ad2745 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -339,6 +339,7 @@ public: events.ScheduleEvent(EVENT_ICY_GRIP, 33s + 500ms, EVENT_GROUP_LAND_PHASE); me->setActive(true); + me->SetFarVisible(true); me->SetInCombatWithZone(); instance->SetBossState(DATA_SINDRAGOSA, IN_PROGRESS); @@ -377,6 +378,7 @@ public: return; me->setActive(true); + me->SetFarVisible(true); me->SetDisableGravity(true); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->SetSpeed(MOVE_RUN, 4.28571f); @@ -1407,6 +1409,7 @@ public: return; me->setActive(true); + me->SetFarVisible(true); me->SetImmuneToPC(true); float moveTime = me->GetExactDist(&SpinestalkerFlyPos) / (me->GetSpeed(MOVE_RUN) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, SpinestalkerLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); @@ -1423,6 +1426,7 @@ public: return; me->setActive(false); + me->SetFarVisible(false); me->SetDisableGravity(false); me->SetHomePosition(SpinestalkerLandPos); me->SetFacingTo(SpinestalkerLandPos.GetOrientation()); @@ -1538,6 +1542,7 @@ public: return; me->setActive(true); + me->SetFarVisible(true); me->SetImmuneToPC(true); float moveTime = me->GetExactDist(&RimefangFlyPos) / (me->GetSpeed(MOVE_RUN) * 0.001f); me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, RimefangLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250)); @@ -1556,6 +1561,8 @@ public: if (point == POINT_FROSTWYRM_LAND) { me->setActive(false); + me->SetFarVisible(false); + me->SetFarVisible(false); me->SetDisableGravity(false); me->SetHomePosition(RimefangLandPos); me->SetFacingTo(RimefangLandPos.GetOrientation()); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 1f90c584a..a8f48f95e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -484,6 +484,7 @@ public: uint32 introDelay = 0; me->setActive(true); + me->SetFarVisible(true); me->SetInCombatWithZone(); me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->SetImmuneToNPC(true); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 1ab35a6a1..745676de0 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -175,6 +175,7 @@ public: { me->SetDisableGravity(true); me->setActive(true); + me->SetFarVisible(true); Reset(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index 1803f4dcc..b85c19216 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -517,6 +517,7 @@ public: if (m_pInstance && !_encounterFinished) m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS); me->setActive(true); + me->SetFarVisible(true); DisableThorim(true); me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true); //me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true); From 31621c029fcfde81d8b6adc77fd6add6e0830faf Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:48:28 +0300 Subject: [PATCH 05/16] fix(DB/Gameobject): Shadow Labyrinth Enterance Lever (#17568) --- data/sql/updates/pending_db_world/rev_1698073663894629500.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1698073663894629500.sql diff --git a/data/sql/updates/pending_db_world/rev_1698073663894629500.sql b/data/sql/updates/pending_db_world/rev_1698073663894629500.sql new file mode 100644 index 000000000..95fdda6ed --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1698073663894629500.sql @@ -0,0 +1,2 @@ +-- Shadow Labyrinth Enterance Door +UPDATE `gameobject_template_addon` SET `flags` = 0 WHERE (`entry` = 183518); From badd877e7249dfa880528271fe4d1afa2ea77ad8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 24 Oct 2023 10:49:55 +0000 Subject: [PATCH 06/16] chore(DB): import pending files Referenced commit(s): 31621c029fcfde81d8b6adc77fd6add6e0830faf --- .../rev_1698073663894629500.sql => db_world/2023_10_24_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1698073663894629500.sql => db_world/2023_10_24_00.sql} (71%) diff --git a/data/sql/updates/pending_db_world/rev_1698073663894629500.sql b/data/sql/updates/db_world/2023_10_24_00.sql similarity index 71% rename from data/sql/updates/pending_db_world/rev_1698073663894629500.sql rename to data/sql/updates/db_world/2023_10_24_00.sql index 95fdda6ed..17d5cd1cd 100644 --- a/data/sql/updates/pending_db_world/rev_1698073663894629500.sql +++ b/data/sql/updates/db_world/2023_10_24_00.sql @@ -1,2 +1,3 @@ +-- DB update 2023_10_22_09 -> 2023_10_24_00 -- Shadow Labyrinth Enterance Door UPDATE `gameobject_template_addon` SET `flags` = 0 WHERE (`entry` = 183518); From d2a3683210a1c3242df2b582022375d95c65aba6 Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Wed, 25 Oct 2023 03:53:05 +0300 Subject: [PATCH 07/16] fix(DB/SAI): Wanton Hostess not removing all auras (#17567) --- .../rev_1698041126559012500.sql | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1698041126559012500.sql diff --git a/data/sql/updates/pending_db_world/rev_1698041126559012500.sql b/data/sql/updates/pending_db_world/rev_1698041126559012500.sql new file mode 100644 index 000000000..383643cc3 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1698041126559012500.sql @@ -0,0 +1,23 @@ +-- Wanton Hostess +UPDATE `smart_scripts` SET `action_param1`=0, `comment`='Wanton Hostess - Between 0-50% Health - Remove All Auras' WHERE `entryorguid`=16459 AND `source_type`=0 AND `id`=4; + +-- Wanton Hostess Transform (Still doesn't fix it for some reason, core issue?) +DELETE FROM `creature_text` WHERE `CreatureID`=17063; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(17063, 0, 0, 'So I said, "Yeah, but that\'ll cost you extra."', 12, 0, 100, 0, 0, 0, 13883, 0, 'Wanton Hostess Transform - Out of Combat'), +(17063, 0, 1, 'Five seconds. I\'m not kidding!', 12, 0, 100, 0, 0, 0, 13884, 0, 'Wanton Hostess Transform - Out of Combat'), +(17063, 0, 2, 'He asked if the imp could join in--can you believe it? Actually, it wasn\'t half bad....', 12, 0, 100, 0, 0, 0, 13885, 0, 'Wanton Hostess Transform - Out of Combat'), +(17063, 0, 3, 'They fall asleep after. Me, I fall asleep during....', 12, 0, 100, 0, 0, 0, 13886, 0, 'Wanton Hostess Transform - Out of Combat'), +(17063, 1, 0, 'Come play with me!', 12, 0, 100, 0, 0, 0, 13880, 0, 'Wanton Hostess Transform - On Aggro'), +(17063, 1, 1, 'You WILL be mine.', 12, 0, 100, 0, 0, 0, 13881, 0, 'Wanton Hostess Transform - On Aggro'), +(17063, 1, 2, 'Come here, pretty. You have what I need!', 12, 0, 100, 0, 0, 0, 13882, 0, 'Wanton Hostess Transform - On Aggro'), +(17063, 2, 0, 'It was fun while it lasted....', 12, 0, 100, 0, 0, 0, 13889, 0, 'Wanton Hostess Transform - On Death'), +(17063, 2, 1, ' It\'s always over too soon.', 12, 0, 100, 0, 0, 0, 13890, 0, 'Wanton Hostess Transform - On Death'), +(17063, 2, 2, 'Just when things were getting interesting.', 12, 0, 100, 0, 0, 0, 13897, 0, 'Wanton Hostess Transform - On Death'), +(17063, 2, 3, 'We could have had so much fun!', 12, 0, 100, 0, 0, 0, 13898, 0, 'Wanton Hostess Transform - On Death'), +(17063, 3, 0, 'Come any closer, and I\'ll scream.', 12, 0, 100, 0, 0, 0, 13887, 0, 'Wanton Hostess Transform - On Transform'), +(17063, 3, 1, 'I want to show you a different side of me....', 12, 0, 100, 0, 0, 0, 13888, 0, 'Wanton Hostess Transform - On Transform'), +(17063, 3, 2, 'I want you to be with me... forever and ever.', 12, 0, 100, 0, 0, 0, 13891, 0, 'Wanton Hostess Transform - On Transform'), +(17063, 3, 3, 'Shhh... I have a little secret I\'ve been keeping.\n', 12, 0, 100, 0, 0, 0, 13892, 0, 'Wanton Hostess Transform - On Transform'), +(17063, 3, 4, 'I\'ve been very, very naughty....', 12, 0, 100, 0, 0, 0, 13895, 0, 'Wanton Hostess Transform - On Transform'), +(17063, 3, 5, 'Enough foreplay. Let\'s get down to business.', 12, 0, 100, 0, 0, 0, 13896, 0, 'Wanton Hostess Transform - On Transform'); From b3bc89214776f29401f66e5e4fc4a38db2433295 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 25 Oct 2023 00:54:17 +0000 Subject: [PATCH 08/16] chore(DB): import pending files Referenced commit(s): d2a3683210a1c3242df2b582022375d95c65aba6 --- .../rev_1698041126559012500.sql => db_world/2023_10_25_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1698041126559012500.sql => db_world/2023_10_25_00.sql} (98%) diff --git a/data/sql/updates/pending_db_world/rev_1698041126559012500.sql b/data/sql/updates/db_world/2023_10_25_00.sql similarity index 98% rename from data/sql/updates/pending_db_world/rev_1698041126559012500.sql rename to data/sql/updates/db_world/2023_10_25_00.sql index 383643cc3..9c97d7151 100644 --- a/data/sql/updates/pending_db_world/rev_1698041126559012500.sql +++ b/data/sql/updates/db_world/2023_10_25_00.sql @@ -1,3 +1,4 @@ +-- DB update 2023_10_24_00 -> 2023_10_25_00 -- Wanton Hostess UPDATE `smart_scripts` SET `action_param1`=0, `comment`='Wanton Hostess - Between 0-50% Health - Remove All Auras' WHERE `entryorguid`=16459 AND `source_type`=0 AND `id`=4; From e1464ed44229237ce492212852c4e6faf0a0c3a4 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 25 Oct 2023 06:10:02 -0300 Subject: [PATCH 09/16] fix(DB/CreatureText): Medivh cheat emote should be a boss emote (#17572) --- data/sql/updates/pending_db_world/rev_1698165360651526600.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1698165360651526600.sql diff --git a/data/sql/updates/pending_db_world/rev_1698165360651526600.sql b/data/sql/updates/pending_db_world/rev_1698165360651526600.sql new file mode 100644 index 000000000..6468020b6 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1698165360651526600.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_text` SET `Type` = 41 WHERE `CreatureId` = 16816 AND `GroupId` = 2 AND `ID` = 0; From d569f91604f4a584dd002324054e580d50e805cf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 25 Oct 2023 09:11:16 +0000 Subject: [PATCH 10/16] chore(DB): import pending files Referenced commit(s): e1464ed44229237ce492212852c4e6faf0a0c3a4 --- .../rev_1698165360651526600.sql => db_world/2023_10_25_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1698165360651526600.sql => db_world/2023_10_25_01.sql} (69%) diff --git a/data/sql/updates/pending_db_world/rev_1698165360651526600.sql b/data/sql/updates/db_world/2023_10_25_01.sql similarity index 69% rename from data/sql/updates/pending_db_world/rev_1698165360651526600.sql rename to data/sql/updates/db_world/2023_10_25_01.sql index 6468020b6..5c59c4353 100644 --- a/data/sql/updates/pending_db_world/rev_1698165360651526600.sql +++ b/data/sql/updates/db_world/2023_10_25_01.sql @@ -1,2 +1,3 @@ +-- DB update 2023_10_25_00 -> 2023_10_25_01 -- UPDATE `creature_text` SET `Type` = 41 WHERE `CreatureId` = 16816 AND `GroupId` = 2 AND `ID` = 0; From 41dba1affbb5a24457a894bf3d503f4aa6303a1b Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 25 Oct 2023 06:14:09 -0300 Subject: [PATCH 11/16] fix(Scripts/ObsidianSanctum): Fix Tenebron respawning (#17576) fix(Scripts/ObsidianSanctum): Fix Shadron respawning --- .../ObsidianSanctum/boss_sartharion.cpp | 2 +- .../instance_obsidian_sanctum.cpp | 25 ------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index 405a4953f..4ced79a81 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -874,7 +874,7 @@ struct boss_sartharion_dragonAI : public BossAI Talk(SAY_TENEBRON_DEATH); if (!isCalledBySartharion || instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS) { - instance->SetBossState(DATA_SHADRON, DONE); + instance->SetBossState(DATA_TENEBRON, DONE); } break; } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp index 401179a6a..59880642b 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp @@ -46,17 +46,6 @@ public: LoadBossBoundaries(boundaries); } - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTERS; ++i) - { - if (GetBossState(i) == IN_PROGRESS) - return true; - } - - return false; - } - void OnCreatureCreate(Creature* pCreature) override { switch(pCreature->GetEntry()) @@ -150,20 +139,6 @@ public: return false; } - bool SetBossState(uint32 type, EncounterState state) override - { - if (InstanceScript::SetBossState(type, state)) - { - return false; - } - - if (state == DONE) - { - SaveToDB(); - } - return true; - } - void DoAction(int32 action) override { switch (action) From 632b55faa5598ea0770b2ffeae8e007a44769d90 Mon Sep 17 00:00:00 2001 From: KJack Date: Wed, 25 Oct 2023 17:53:00 -0400 Subject: [PATCH 12/16] fix (Scripts/ICC): Make Valithria starting health dynamic, fix broken channeling spell (#17586) * Make Valithria starting health dynamic based on actual max health * Fix Risen Archmage broken spell channel and combat log spam --- .../IcecrownCitadel/boss_valithria_dreamwalker.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 3b73e10ba..2cf62db2b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -293,16 +293,12 @@ public: _instance(creature->GetInstanceScript()), _portalCount(RAID_MODE(3, 8, 3, 8)) { me->SetReactState(REACT_PASSIVE); - _spawnHealth = 1; // just in case if not set below - if (CreatureData const* data = sObjectMgr->GetCreatureData(me->GetSpawnId())) - if (data->curhealth) - _spawnHealth = data->curhealth; } void Reset() override { _events.Reset(); - me->SetHealth(_spawnHealth); + me->SetHealth(me->GetMaxHealth() * 0.5f); // starts at 50% health me->LoadCreaturesAddon(true); // immune to percent heals me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_OBS_MOD_HEALTH, true); @@ -440,8 +436,9 @@ public: // does not enter combat if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == NOT_STARTED) { - if (me->GetHealth() != _spawnHealth) // healing when boss cannot be engaged (lower spire not finished, cheating) doesn't start the fight, prevent winning this way - me->SetHealth(_spawnHealth); + uint32 startingHealth = me->GetMaxHealth() * 0.5f; + if (me->GetHealth() != startingHealth) // healing when boss cannot be engaged (lower spire not finished, cheating) doesn't start the fight, prevent winning this way + me->SetHealth(startingHealth); return; } @@ -484,7 +481,6 @@ public: private: EventMap _events; InstanceScript* _instance; - uint32 _spawnHealth; uint32 const _portalCount; uint32 _missedPortals; bool _under25PercentTalkDone; @@ -756,7 +752,7 @@ public: if (!me->IsInCombat()) if (me->GetSpawnId()) if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - me->CastSpell(me, SPELL_CORRUPTION, false); + me->CastSpell(me, SPELL_CORRUPTION, true); if (!UpdateVictim()) return; From 3dcbe649ddd0d5fe891ef6614ce07c63cb5060aa Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 25 Oct 2023 19:01:15 -0300 Subject: [PATCH 13/16] fix(Scripts/Karazhan): Fix Flame Wreath affecting pets (#17581) --- .../EasternKingdoms/Karazhan/boss_shade_of_aran.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index 55929ee77..f0509fafe 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -503,12 +503,15 @@ class spell_flamewreath_aura : public AuraScript { if (Unit* target = GetTarget()) { - target->CastSpell(target, SPELL_FLAME_WREATH_RAN_THRU, true); + if (target->IsPlayer()) + { + target->CastSpell(target, SPELL_FLAME_WREATH_RAN_THRU, true); - target->m_Events.AddEventAtOffset([target] { - target->RemoveAurasDueToSpell(SPELL_FLAME_WREATH_RAN_THRU); - target->CastSpell(target, SPELL_FLAME_WREATH_EXPLOSION, true); - }, 1s); + target->m_Events.AddEventAtOffset([target] { + target->RemoveAurasDueToSpell(SPELL_FLAME_WREATH_RAN_THRU); + target->CastSpell(target, SPELL_FLAME_WREATH_EXPLOSION, true); + }, 1s); + } } } } From ee4a9efdf2dc15d6b19538db9e620070002c5501 Mon Sep 17 00:00:00 2001 From: avarishd <46330494+avarishd@users.noreply.github.com> Date: Thu, 26 Oct 2023 01:01:42 +0300 Subject: [PATCH 14/16] fix(DB/SAI): Dark Portal mages missing animation (#17585) --- data/sql/updates/pending_db_world/rev_1698258147355013600.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data/sql/updates/pending_db_world/rev_1698258147355013600.sql diff --git a/data/sql/updates/pending_db_world/rev_1698258147355013600.sql b/data/sql/updates/pending_db_world/rev_1698258147355013600.sql new file mode 100644 index 000000000..141b1b617 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1698258147355013600.sql @@ -0,0 +1,2 @@ +-- +UPDATE`smart_scripts` SET `action_param2` = 2 WHERE `source_type` = 0 AND `id` = 0 AND `entryorguid` IN (19007,19006); From 23a620007b38c03368bac441e4fd91c585935c01 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 25 Oct 2023 22:02:19 +0000 Subject: [PATCH 15/16] chore(DB): import pending files Referenced commit(s): 3dcbe649ddd0d5fe891ef6614ce07c63cb5060aa --- .../rev_1698258147355013600.sql => db_world/2023_10_25_02.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1698258147355013600.sql => db_world/2023_10_25_02.sql} (73%) diff --git a/data/sql/updates/pending_db_world/rev_1698258147355013600.sql b/data/sql/updates/db_world/2023_10_25_02.sql similarity index 73% rename from data/sql/updates/pending_db_world/rev_1698258147355013600.sql rename to data/sql/updates/db_world/2023_10_25_02.sql index 141b1b617..c9e38ccc1 100644 --- a/data/sql/updates/pending_db_world/rev_1698258147355013600.sql +++ b/data/sql/updates/db_world/2023_10_25_02.sql @@ -1,2 +1,3 @@ +-- DB update 2023_10_25_01 -> 2023_10_25_02 -- UPDATE`smart_scripts` SET `action_param2` = 2 WHERE `source_type` = 0 AND `id` = 0 AND `entryorguid` IN (19007,19006); From 79b39f9655111088a741185c4dabd31dae7d85ea Mon Sep 17 00:00:00 2001 From: AG <43139552+AGandrup@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:32:15 +0200 Subject: [PATCH 16/16] fix(Core/Grid): Implement missing GridUnload setting (#17569) * Implement GridUnload setting * Minor fixes - Use GetOption instead of deprecated GetBoolDefault. - Added a missing check for instances in LoadMap - Replaced some numbers with global defines * Possible crashfix + minor improvements - Initialized initialOrientation which I had forgotten (likely cause of crash) - Readded a previous check in UpdateSplineMovement - Made i_objectsToRemove and i_worldObjects tos sets as they were previously, instead of unordered_set. * Update worldserver.conf.dist * Fix high CPU usage with preload grid enabled. This should be it. --- .../apps/worldserver/worldserver.conf.dist | 19 ++++++++++++----- src/server/game/Entities/Unit/Unit.cpp | 9 ++++++-- src/server/game/Maps/Map.cpp | 14 +++++++------ src/server/game/Maps/Map.h | 4 ++-- src/server/game/Maps/MapMgr.cpp | 4 ++-- src/server/game/Movement/Spline/Spline.h | 9 ++++++-- src/server/game/World/IWorld.h | 1 + src/server/game/World/World.cpp | 21 ++++++++++--------- 8 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index 8e728460b..01e9fa84b 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -1372,13 +1372,22 @@ DetectPosCollision = 1 CheckGameObjectLoS = 1 +# +# GridUnload +# Description: Unload grids to save memory. Can be disabled if enough memory is available +# to speed up moving players to new grids. +# Default: 1 - (enable, Unload grids) +# 0 - (disable, Do not unload grids) + +GridUnload = 1 + # # PreloadAllNonInstancedMapGrids -# Description: Preload all grids on all non-instanced maps. This will take a great amount -# of additional RAM (ca. 9 GB) and causes the server to take longer to start, -# but can increase performance if used on a server with a high amount of players. -# It will also activate all creatures which are set active (e.g. the Fel Reavers -# in Hellfire Peninsula) on server start. +# Description: Preload all grids on all non-instanced maps. Requires GridUnload to be disabled. +# This will take a great amount of additional RAM (ca. 9 GB) and causes the server +# to take longer to start, but can increase performance if used on a server with a +# high amount of players. It will also activate all creatures which are set active +# (e.g. the Fel Reavers in Hellfire Peninsula) on server start. # Default: 0 - (Disabled) # 1 - (Enabled) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index be8dc1941..06ef9593b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -567,6 +567,13 @@ void Unit::UpdateSplineMovement(uint32 t_diff) // this code cant be placed inside EscortMovementGenerator, because we cant delete active MoveGen while it is updated SplineHandler handler(this); movespline->updateState(t_diff, handler); + // Xinef: Spline was cleared by StopMoving, return + if (!movespline->Initialized()) { + DisableSpline(); + return; + } + + bool arrived = movespline->Finalized(); if (movespline->isCyclic()) { @@ -582,8 +589,6 @@ void Unit::UpdateSplineMovement(uint32 t_diff) } } - bool arrived = movespline->Finalized(); - if (arrived) { DisableSpline(); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 643c884d1..68e54d3ea 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -195,7 +195,8 @@ void Map::LoadMap(int gx, int gy, bool reload) return; // load grid map for base map - m_parentMap->EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); + if (!m_parentMap->GridMaps[gx][gy]) + m_parentMap->EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy)); ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridCoord(gx, gy)); GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; @@ -460,7 +461,8 @@ void Map::EnsureGridCreated_i(const GridCoord& p) { LOG_DEBUG("maps", "Creating grid[{}, {}] for map {} instance {}", p.x_coord, p.y_coord, GetId(), i_InstanceId); - setNGrid(new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry), p.x_coord, p.y_coord); + NGridType* ngrid = new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld->getBoolConfig(CONFIG_GRID_UNLOAD)); + setNGrid(ngrid, p.x_coord, p.y_coord); // build a linkage between this map and NGridType buildNGridLinkage(getNGrid(p.x_coord, p.y_coord)); @@ -2403,11 +2405,11 @@ inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float GridMap* Map::GetGrid(float x, float y) { // half opt method - int gx = (int)(32 - x / SIZE_OF_GRIDS); //grid x - int gy = (int)(32 - y / SIZE_OF_GRIDS); //grid y + int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS); //grid x + int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); //grid y // ensure GridMap is loaded - EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); + EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy)); return GridMaps[gx][gy]; } @@ -3135,7 +3137,7 @@ void Map::RemoveAllObjectsInRemoveList() //LOG_DEBUG("maps", "Object remover 1 check."); while (!i_objectsToRemove.empty()) { - std::unordered_set::iterator itr = i_objectsToRemove.begin(); + std::set::iterator itr = i_objectsToRemove.begin(); WorldObject* obj = *itr; switch (obj->GetTypeId()) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index fff1c5785..c3b64f01a 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -768,9 +768,9 @@ private: void ProcessRelocationNotifies(uint32 diff); bool i_scriptLock; - std::unordered_set i_objectsToRemove; + std::set i_objectsToRemove; std::map i_objectsToSwitch; - std::unordered_set i_worldObjects; + std::set i_worldObjects; typedef std::multimap ScriptScheduleMap; ScriptScheduleMap m_scriptSchedule; diff --git a/src/server/game/Maps/MapMgr.cpp b/src/server/game/Maps/MapMgr.cpp index 5c95475fb..96368486a 100644 --- a/src/server/game/Maps/MapMgr.cpp +++ b/src/server/game/Maps/MapMgr.cpp @@ -303,8 +303,8 @@ bool MapMgr::ExistMapAndVMap(uint32 mapid, float x, float y) { GridCoord p = Acore::ComputeGridCoord(x, y); - int gx = 63 - p.x_coord; - int gy = 63 - p.y_coord; + int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; + int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; return Map::ExistMap(mapid, gx, gy) && Map::ExistVMap(mapid, gx, gy); } diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index afefffe62..38dcd9293 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -48,7 +48,7 @@ namespace Movement uint8 m_mode{UninitializedMode}; bool cyclic{false}; - float initialOrientation; + float initialOrientation{0.f}; enum { @@ -198,7 +198,12 @@ namespace Movement } /** Returns length of the whole spline. */ - [[nodiscard]] length_type length() const { return lengths[index_hi];} + [[nodiscard]] length_type length() const + { + if (lengths.empty()) + return 0; + return lengths[index_hi]; + } /** Returns length between given nodes. */ [[nodiscard]] length_type length(index_type first, index_type last) const { return lengths[last] - lengths[first];} [[nodiscard]] length_type length(index_type Idx) const { return lengths[Idx];} diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index f2ed3289b..394875058 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -72,6 +72,7 @@ enum WorldBoolConfigs CONFIG_ADDON_CHANNEL, CONFIG_ALLOW_PLAYER_COMMANDS, CONFIG_CLEAN_CHARACTER_DB, + CONFIG_GRID_UNLOAD, CONFIG_STATS_SAVE_ONLY_ON_LOGOUT, CONFIG_ALLOW_TWO_SIDE_ACCOUNTS, CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index d301a1d26..79f56d46a 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1420,8 +1420,16 @@ void World::LoadConfigSettings(bool reload) // Prevent players AFK from being logged out _int_configs[CONFIG_AFK_PREVENT_LOGOUT] = sConfigMgr->GetOption("PreventAFKLogout", 0); + // Unload grids to save memory. Can be disabled if enough memory is available to speed up moving players to new grids. + _bool_configs[CONFIG_GRID_UNLOAD] = sConfigMgr->GetOption("GridUnload", true); + // Preload all grids of all non-instanced maps _bool_configs[CONFIG_PRELOAD_ALL_NON_INSTANCED_MAP_GRIDS] = sConfigMgr->GetOption("PreloadAllNonInstancedMapGrids", false); + if (_bool_configs[CONFIG_PRELOAD_ALL_NON_INSTANCED_MAP_GRIDS] && _bool_configs[CONFIG_GRID_UNLOAD]) + { + LOG_ERROR("server.loading", "PreloadAllNonInstancedMapGrids enabled, but GridUnload also enabled. GridUnload must be disabled to enable base map pre-loading. Base map pre-loading disabled"); + _bool_configs[CONFIG_PRELOAD_ALL_NON_INSTANCED_MAP_GRIDS] = false; + } // ICC buff override _int_configs[CONFIG_ICC_BUFF_HORDE] = sConfigMgr->GetOption("ICC.Buff.Horde", 73822); @@ -2164,21 +2172,14 @@ void World::SetInitialWorldSettings() { LOG_INFO("server.loading", "Loading All Grids For All Non-Instanced Maps..."); - for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) - { - MapEntry const* mapEntry = sMapStore.LookupEntry(i); - - if (mapEntry && !mapEntry->Instanceable()) + sMapMgr->DoForAllMaps([](Map* map) { - Map* map = sMapMgr->CreateBaseMap(mapEntry->MapID); - - if (map) + if (!map->Instanceable()) { LOG_INFO("server.loading", ">> Loading All Grids For Map {}", map->GetId()); map->LoadAllCells(); } - } - } + }); } uint32 startupDuration = GetMSTimeDiffToNow(startupBegin);