From bbadc32bea2ad8b60ea591b8bb7b7387babef458 Mon Sep 17 00:00:00 2001 From: Kitzunu <24550914+Kitzunu@users.noreply.github.com> Date: Sun, 12 Nov 2023 00:48:49 +0100 Subject: [PATCH] Revert Visibility Notifier changes (#17682) * Revert "fix(Core/Grid): Implement missing GridUnload setting (#17569)" This reverts commit 79b39f9655111088a741185c4dabd31dae7d85ea. * Revert "fix(Core/Grid): Address bugs and performance issues introduced by visibility notifier implementation (#17480)" This reverts commit 60e27511c530b0949fee361a89d3eb9d9f9125af. * Revert "fix(Core): GridCleanUpDelay Log (#17436)" This reverts commit 90b16ca065a4881b94438575502c2441f435d53b. * Revert "feat(Core/Grids): Implement visibility notifier (#15919)" This reverts commit 2779833768bbe9967006d6d16888dace05b4bcb6. --- .../apps/worldserver/worldserver.conf.dist | 44 +- src/server/game/Battlefield/Battlefield.cpp | 4 +- .../game/Battlefield/Zones/BattlefieldWG.h | 9 - .../Battlegrounds/Zones/BattlegroundAB.cpp | 2 +- .../game/Entities/Creature/Creature.cpp | 46 +- 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 | 134 ++- src/server/game/Entities/Object/Object.h | 26 +- .../game/Entities/Object/ObjectDefines.h | 9 +- src/server/game/Entities/Object/ObjectGuid.h | 1 - src/server/game/Entities/Player/Player.cpp | 22 +- src/server/game/Entities/Player/Player.h | 15 +- .../game/Entities/Player/PlayerUpdates.cpp | 68 +- .../game/Entities/Transport/Transport.cpp | 65 +- .../game/Entities/Transport/Transport.h | 3 + src/server/game/Entities/Unit/Unit.cpp | 230 +++- src/server/game/Entities/Unit/Unit.h | 12 +- src/server/game/Entities/Vehicle/Vehicle.cpp | 3 +- src/server/game/Grids/Grid.h | 6 - src/server/game/Grids/GridStates.cpp | 65 -- src/server/game/Grids/GridStates.h | 56 - src/server/game/Grids/NGrid.h | 69 +- .../game/Grids/Notifiers/GridNotifiers.cpp | 112 +- .../game/Grids/Notifiers/GridNotifiers.h | 51 +- .../game/Grids/Notifiers/GridNotifiersImpl.h | 7 + src/server/game/Grids/ObjectGridLoader.cpp | 65 +- src/server/game/Grids/ObjectGridLoader.h | 17 - src/server/game/Handlers/MovementHandler.cpp | 167 ++- src/server/game/Instances/InstanceSaveMgr.cpp | 1 - src/server/game/Maps/Map.cpp | 1004 ++++------------- src/server/game/Maps/Map.h | 93 +- src/server/game/Maps/MapInstanced.cpp | 20 +- src/server/game/Maps/MapInstanced.h | 17 +- src/server/game/Maps/MapMgr.cpp | 13 +- src/server/game/Maps/MapMgr.h | 10 - src/server/game/Maps/TransportMgr.cpp | 2 + .../NGrid.cpp => Misc/DynamicVisibility.cpp} | 15 +- 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 | 28 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 11 +- src/server/game/Spells/SpellEffects.cpp | 6 +- src/server/game/World/IWorld.h | 2 - src/server/game/World/World.cpp | 40 +- src/server/game/World/World.h | 8 - .../BlackwingLair/boss_nefarian.cpp | 1 - .../BlackwingLair/instance_blackwing_lair.cpp | 1 - .../Karazhan/boss_nightbane.cpp | 1 - .../zone_the_scarlet_enclave.cpp | 1 - src/server/scripts/Events/midsummer.cpp | 2 + .../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 - .../Outland/TempestKeep/Eye/boss_alar.cpp | 2 + 64 files changed, 1074 insertions(+), 1764 deletions(-) delete mode 100644 src/server/game/Grids/GridStates.cpp delete mode 100644 src/server/game/Grids/GridStates.h rename src/server/game/{Grids/NGrid.cpp => Misc/DynamicVisibility.cpp} (59%) create mode 100644 src/server/game/Misc/DynamicVisibility.h diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index 01e9fa84b..d8d5746df 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -939,13 +939,6 @@ ClientCacheVersion = 0 SessionAddDelay = 10000 -# -# GridCleanUpDelay -# Description: Time (in milliseconds) grid clean up delay. -# Default: 300000 - (5 minutes) - -GridCleanUpDelay = 300000 - # # CloseIdleConnections # Description: Automatically close idle connections. @@ -1251,17 +1244,17 @@ Visibility.GroupMode = 1 # Visibility.Distance.Instances # Visibility.Distance.BGArenas # Description: Visibility distance to see other players or gameobjects. -# Visibility on continents on retail ~100 yards. In BG/Arenas ~533. -# For instances default ~170. -# Max limited by grid size: 533.33333 +# Visibility on continents on retail ~90 yards. In BG/Arenas ~180. +# For instances default ~120. +# Max limited by active player zone: ~ 333 # Min limit is max aggro radius (45) * Rate.Creature.Aggro -# Default: 100 - (Visibility.Distance.Continents) -# 170 - (Visibility.Distance.Instances) -# 533 - (Visibility.Distance.BGArenas) +# Default: 90 - (Visibility.Distance.Continents) +# 120 - (Visibility.Distance.Instances) +# 180 - (Visibility.Distance.BGArenas) -Visibility.Distance.Continents = 100 -Visibility.Distance.Instances = 170 -Visibility.Distance.BGArenas = 533 +Visibility.Distance.Continents = 90 +Visibility.Distance.Instances = 120 +Visibility.Distance.BGArenas = 180 # # Visibility.Notify.Period.OnContinents @@ -1372,22 +1365,13 @@ 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. 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. +# 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. # Default: 0 - (Disabled) # 1 - (Enabled) diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 675010655..fe609ea1f 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->SetFarVisible(true); + creature->setActive(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->SetFarVisible(true); + go->setActive(true); return go; } diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index c0652d878..1c4cb586d 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -1159,7 +1159,6 @@ 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 @@ -1171,10 +1170,6 @@ 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); @@ -1198,10 +1193,6 @@ 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/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 0360ea47b..4cc94a60d 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -551,6 +551,6 @@ void BattlegroundAB::ApplyPhaseMask() for (auto const& itr : bgPlayerMap) { itr.second->SetPhaseMask(phaseMask, false); - itr.second->UpdateObjectVisibility(true); + itr.second->UpdateObjectVisibility(true, false); } } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 36cb2c154..44334b830 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -301,6 +301,9 @@ void Creature::RemoveFromWorld() if (m_formation) sFormationMgr->RemoveCreatureFromGroup(m_formation, this); + if (Transport* transport = GetTransport()) + transport->RemovePassenger(this, true); + Unit::RemoveFromWorld(); if (m_spawnId) @@ -362,15 +365,17 @@ void Creature::RemoveCorpse(bool setSpawnTime, bool skipVisibility) //SaveRespawnTime(); } + float x, y, z, o; + GetRespawnPosition(x, y, z, &o); + SetHomePosition(x, y, z, o); + SetPosition(x, y, z, o); + + // xinef: relocate notifier + m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f); + // pussywizard: if corpse was removed during falling then the falling will continue after respawn, so stop falling is such case if (IsFalling()) StopMoving(); - - float x, y, z, o; - GetRespawnPosition(x, y, z, &o); - UpdateAllowedPositionZ(x, y, z); - SetHomePosition(x, y, z, o); - GetMap()->CreatureRelocation(this, x, y, z, o); } /** @@ -1823,25 +1828,7 @@ void Creature::DeleteFromDB() return; } - 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); - } - ); - + GetMap()->RemoveCreatureRespawnTime(m_spawnId); sObjectMgr->DeleteCreatureData(m_spawnId); WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction(); @@ -2093,7 +2080,9 @@ void Creature::Respawn(bool force) m_respawnedTime = GameTime::GetGameTime().count(); } m_respawnedTime = GameTime::GetGameTime().count(); - UpdateObjectVisibility(); + // xinef: relocate notifier, fixes npc appearing in corpse position after forced respawn (instead of spawn) + m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f); + UpdateObjectVisibility(false); } void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer) @@ -3075,7 +3064,10 @@ std::string const& Creature::GetNameForLocaleIdx(LocaleConstant loc_idx) const void Creature::SetPosition(float x, float y, float z, float o) { - UpdatePosition(x, y, z, o, false); + if (!Acore::IsValidMapCoord(x, y, z, o)) + return; + + GetMap()->CreatureRelocation(this, x, y, z, o); } bool Creature::IsDungeonBoss() const diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 126b7b099..ede229ff7 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -68,7 +68,6 @@ 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 8346d74e8..779e44312 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -47,6 +47,14 @@ 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); } @@ -80,6 +88,9 @@ void DynamicObject::RemoveFromWorld() UnbindFromCaster(); + if (Transport* transport = GetTransport()) + transport->RemovePassenger(this, true); + WorldObject::RemoveFromWorld(); GetMap()->GetObjectsStore().Remove(GetGUID()); @@ -114,15 +125,17 @@ 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 68b215377..aa164d4f7 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -27,7 +27,6 @@ #include "GridNotifiersImpl.h" #include "Group.h" #include "GroupMgr.h" -#include "MapMgr.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" #include "PoolMgr.h" @@ -103,9 +102,18 @@ std::string const& GameObject::GetAIName() const return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName; } -void GameObject::CleanupsBeforeDelete(bool finalCleanup) +void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/) { - WorldObject::CleanupsBeforeDelete(finalCleanup); + if (GetTransport() && !ToTransport()) + { + GetTransport()->RemovePassenger(this); + SetTransport(nullptr); + m_movementInfo.transport.Reset(); + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + } + + if (IsInWorld()) + RemoveFromWorld(); if (m_uint32Values) // field array can be not exist if GameOBject not loaded RemoveFromOwner(); @@ -174,6 +182,9 @@ 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()) { @@ -877,11 +888,7 @@ void GameObject::Update(uint32 diff) if (!m_spawnedByDefault) { m_respawnTime = 0; - if (m_spawnId) - DestroyForNearbyPlayers(); // xinef: old UpdateObjectVisibility(); - else - Delete(); - + DestroyForNearbyPlayers(); // xinef: old UpdateObjectVisibility(); return; } @@ -1177,31 +1184,7 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo void GameObject::DeleteFromDB() { - 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); - } - ); - + GetMap()->RemoveGORespawnTime(m_spawnId); sObjectMgr->DeleteGOData(m_spawnId); WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); @@ -2190,6 +2173,15 @@ 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 945c648e0..61962e75d 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -289,6 +289,8 @@ 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 97f90bddd..fef69d6ef 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -21,6 +21,7 @@ #include "CellImpl.h" #include "Chat.h" #include "Creature.h" +#include "DynamicVisibility.h" #include "GameObjectAI.h" #include "GameTime.h" #include "GridNotifiers.h" @@ -64,7 +65,7 @@ constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max VISIBILITY_DISTANCE_SMALL, VISIBILITY_DISTANCE_LARGE, VISIBILITY_DISTANCE_GIGANTIC, - MAX_VISIBILITY_DISTANCE + VISIBILITY_DISTANCE_INFINITE }; Object::Object() : m_PackGUID(sizeof(uint64) + 1) @@ -248,10 +249,7 @@ void Object::SendUpdateToPlayer(Player* player) UpdateData upd; WorldPacket packet; - if (player->HaveAtClient(this)) - BuildValuesUpdateBlockForPlayer(&upd, player); - else - BuildCreateUpdateBlockForPlayer(&upd, player); + BuildCreateUpdateBlockForPlayer(&upd, player); upd.BuildPacket(&packet); player->GetSession()->SendPacket(&packet); } @@ -1050,7 +1048,7 @@ void MovementInfo::OutDebug() } WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), - LastUsedScriptID(0), m_name(""), m_isActive(false), m_isFarVisible(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), + LastUsedScriptID(0), m_name(""), m_isActive(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) { @@ -1107,6 +1105,8 @@ 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,17 +1114,11 @@ 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); @@ -1140,9 +1134,6 @@ 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) @@ -1635,9 +1626,9 @@ float WorldObject::GetGridActivationRange() const { if (ToPlayer()->GetCinematicMgr()->IsOnCinematic()) { - return std::max(DEFAULT_VISIBILITY_INSTANCE, GetMap()->GetVisibilityRange()); + return DEFAULT_VISIBILITY_INSTANCE; } - return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange(); + return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); } else if (ToCreature()) { @@ -1653,12 +1644,29 @@ float WorldObject::GetGridActivationRange() const float WorldObject::GetVisibilityRange() const { - if (IsVisibilityOverridden() && !ToPlayer()) + if (IsVisibilityOverridden() && GetTypeId() == TYPEID_UNIT) + { return *m_visibilityDistanceOverride; - else if (IsFarVisible() && !ToPlayer()) - return MAX_VISIBILITY_DISTANCE; + } + 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 - return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange(); + return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange(); } float WorldObject::GetSightRange(WorldObject const* target) const @@ -1667,19 +1675,44 @@ float WorldObject::GetSightRange(WorldObject const* target) const { if (ToPlayer()) { - 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(); + 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(); } else if (ToCreature()) + { return ToCreature()->m_SightDistance; + } else + { return SIGHT_RANGE_UNIT; + } } if (ToDynObject() && isActiveObject()) @@ -2044,8 +2077,11 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const BuildMovementPacket(data); } -void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, Player const* skipped_rcvr) const +void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, 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); } @@ -2192,8 +2228,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert return nullptr; } - if (!IsGridLoaded(pos.GetPositionX(), pos.GetPositionY())) - EnsureGridLoaded(Cell(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; @@ -2866,8 +2901,8 @@ void WorldObject::DestroyForNearbyPlayers() return; std::list targets; - Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange(), false); - Acore::PlayerListSearcher searcher(this, targets, check); + Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange() + VISIBILITY_COMPENSATION, false); + Acore::PlayerListSearcherWithSharedVision searcher(this, targets, check); Cell::VisitWorldObjects(this, searcher, GetVisibilityRange()); for (std::list::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) { @@ -2887,7 +2922,7 @@ void WorldObject::DestroyForNearbyPlayers() } } -void WorldObject::UpdateObjectVisibility(bool /*forced*/) +void WorldObject::UpdateObjectVisibility(bool /*forced*/, bool /*fromUpdate*/) { //updates object's visibility for nearby players Acore::VisibleChangesNotifier notifier(*this); @@ -2896,7 +2931,28 @@ void WorldObject::UpdateObjectVisibility(bool /*forced*/) void WorldObject::AddToNotify(uint16 f) { - m_notifyflags |= f; + if (!(m_notifyflags & f)) + if (Unit* u = ToUnit()) + { + if (f & NOTIFY_VISIBILITY_CHANGED) + { + uint32 EVENT_VISIBILITY_DELAY = u->FindMap() ? DynamicVisibilityMgr::GetVisibilityNotifyDelay(u->FindMap()->GetEntry()->map_type) : 1000; + + uint32 diff = getMSTimeDiff(u->m_last_notify_mstime, GameTime::GetGameTimeMS().count()); + if (diff >= EVENT_VISIBILITY_DELAY / 2) + EVENT_VISIBILITY_DELAY /= 2; + else + EVENT_VISIBILITY_DELAY -= diff; + u->m_delayed_unit_relocation_timer = EVENT_VISIBILITY_DELAY; + u->m_last_notify_mstime = GameTime::GetGameTimeMS().count() + EVENT_VISIBILITY_DELAY - 1; + } + else if (f & NOTIFY_AI_RELOCATION) + { + u->m_delayed_unit_ai_notify_timer = u->FindMap() ? DynamicVisibilityMgr::GetAINotifyDelay(u->FindMap()->GetEntry()->map_type) : 500; + } + + m_notifyflags |= f; + } } struct WorldObjectChangeAccumulator @@ -2949,7 +3005,7 @@ struct WorldObjectChangeAccumulator source = iter->GetSource(); ObjectGuid guid = source->GetCasterGUID(); - if (guid.IsPlayer()) + if (guid) { //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 5ee201e8e..8a75f3d87 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -379,23 +379,14 @@ class MovableMapObject template friend class RandomMovementGenerator; protected: - MovableMapObject() : _moveState(MAP_OBJECT_CELL_MOVE_NONE) - { - _newPosition.Relocate(0.0f, 0.0f, 0.0f, 0.0f); - } + MovableMapObject() = default; private: - Cell _currentCell; [[nodiscard]] Cell const& GetCurrentCell() const { return _currentCell; } void SetCurrentCell(Cell const& cell) { _currentCell = cell; } - MapObjectCellMoveState _moveState; - Position _newPosition; - void SetNewCellPosition(float x, float y, float z, float o) - { - _moveState = MAP_OBJECT_CELL_MOVE_ACTIVE; - _newPosition.Relocate(x, y, z, o); - } + Cell _currentCell; + MapObjectCellMoveState _moveState{MAP_OBJECT_CELL_MOVE_NONE}; }; class WorldObject : public Object, public WorldLocation @@ -488,9 +479,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); } // 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 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 uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; } @@ -547,7 +538,7 @@ public: void GetDeadCreatureListInGrid(std::list& lList, float maxSearchRange, bool alive = false) const; void DestroyForNearbyPlayers(); - virtual void UpdateObjectVisibility(bool forced = true); + virtual void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false); void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override; void GetCreaturesWithEntryInRange(std::list& creatureList, float radius, uint32 entry); @@ -569,7 +560,6 @@ 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); @@ -578,7 +568,7 @@ public: [[nodiscard]] bool IsInWintergrasp() const { - return GetMapId() == 571 && GetZoneId() == 4197; + return GetMapId() == 571 && GetPositionX() > 3733.33331f && GetPositionX() < 5866.66663f && GetPositionY() > 1599.99999f && GetPositionY() < 4799.99997f; } #ifdef MAP_BASED_RAND_GEN diff --git a/src/server/game/Entities/Object/ObjectDefines.h b/src/server/game/Entities/Object/ObjectDefines.h index 0dfb5a705..55c482633 100644 --- a/src/server/game/Entities/Object/ObjectDefines.h +++ b/src/server/game/Entities/Object/ObjectDefines.h @@ -23,18 +23,23 @@ #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 MAX_VISIBILITY_DISTANCE 250.0f // max distance for visible objects, experimental #define SIGHT_RANGE_UNIT 50.0f #define MAX_SEARCHER_DISTANCE 150.0f // pussywizard: replace the use of MAX_VISIBILITY_DISTANCE in searchers, because MAX_VISIBILITY_DISTANCE is quite too big for this purpose +#define VISIBILITY_DISTANCE_INFINITE 533.0f #define VISIBILITY_DISTANCE_GIGANTIC 400.0f #define VISIBILITY_DISTANCE_LARGE 200.0f #define VISIBILITY_DISTANCE_NORMAL 100.0f #define VISIBILITY_DISTANCE_SMALL 50.0f #define VISIBILITY_DISTANCE_TINY 25.0f -#define DEFAULT_VISIBILITY_DISTANCE VISIBILITY_DISTANCE_NORMAL // default visible distance, 100 yards on continents +#define DEFAULT_VISIBILITY_DISTANCE 100.0f // 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 3f626c780..bb8029048 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -134,7 +134,6 @@ 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 8bb1efa4d..ce39c9e7f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1353,7 +1353,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (GetTransport()) { - m_transport->RemovePassenger(this, true); + m_transport->RemovePassenger(this); + m_transport = nullptr; + m_movementInfo.transport.Reset(); + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } @@ -1395,7 +1398,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); else { - m_transport->RemovePassenger(this, true); + m_transport->RemovePassenger(this); + m_transport = nullptr; + m_movementInfo.transport.Reset(); + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); } } @@ -5575,11 +5581,14 @@ void Player::SaveRecallPosition() m_recallO = GetOrientation(); } -void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, Player const* skipped_rcvr) const +void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, 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); } @@ -11313,7 +11322,7 @@ WorldLocation Player::GetStartPosition() const return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); } -bool Player::HaveAtClient(Object const* u) const +bool Player::HaveAtClient(WorldObject const* u) const { if (u == this) { @@ -13087,11 +13096,14 @@ void Player::SetViewpoint(WorldObject* target, bool apply) UpdateVisibilityOf(target); if (target->isType(TYPEMASK_UNIT) && !GetVehicle()) - static_cast(target)->AddPlayerToVision(this); + ((Unit*)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 c36fec295..18300e2db 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); } // 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 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 SendTeleportAckPacket(); @@ -2342,8 +2342,9 @@ public: // currently visible objects at player client GuidUnorderedSet m_clientGUIDs; + std::vector m_newVisible; // pussywizard - [[nodiscard]] bool HaveAtClient(Object const* u) const; + [[nodiscard]] bool HaveAtClient(WorldObject const* u) const; [[nodiscard]] bool HaveAtClient(ObjectGuid guid) const; [[nodiscard]] bool IsNeverVisible() const override; @@ -2351,13 +2352,13 @@ public: bool IsVisibleGloballyFor(Player const* player) const; void GetInitialVisiblePackets(Unit* target); - void UpdateObjectVisibility(bool forced = true) override; + void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false) override; void UpdateVisibilityForPlayer(bool mapChange = false); void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); template - void UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow); + void UpdateVisibilityOf(T* target, UpdateData& data, std::vector& 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 4c8ad5ac0..716a46030 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -412,6 +412,14 @@ void Player::Update(uint32 p_time) SetHasDelayedTeleport(false); TeleportTo(teleportStore_dest, teleportStore_options); } + + if (!IsBeingTeleported() && bRequestForcedVisibilityUpdate) + { + bRequestForcedVisibilityUpdate = false; + UpdateObjectVisibility(true, true); + m_delayed_unit_relocation_timer = 0; + RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED); + } } void Player::UpdateMirrorTimers() @@ -1521,11 +1529,17 @@ void Player::UpdatePotionCooldown(Spell* spell) SetLastPotionId(0); } -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); +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); void Player::UpdateVisibilityForPlayer(bool mapChange) { @@ -1536,13 +1550,23 @@ void Player::UpdateVisibilityForPlayer(bool mapChange) m_seer = this; } - // updates visibility of all objects around point of view for current player - Acore::VisibleNotifier notifier(*this); - Cell::VisitAllObjects(m_seer, notifier, GetSightRange()); - notifier.SendToSelf(); // send gathered data + Acore::VisibleNotifier notifierNoLarge( + *this, mapChange, + false); // visit only objects which are not large; default distance + Cell::VisitAllObjects(m_seer, notifierNoLarge, + GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS); + notifierNoLarge.SendToSelf(); + + Acore::VisibleNotifier notifierLarge( + *this, mapChange, true); // visit only large objects; maximum distance + Cell::VisitAllObjects(m_seer, notifierLarge, GetSightRange()); + notifierLarge.SendToSelf(); + + if (mapChange) + m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f); } -void Player::UpdateObjectVisibility(bool forced) +void Player::UpdateObjectVisibility(bool forced, bool fromUpdate) { // Prevent updating visibility if player is not in world (example: LoadFromDB sets drunkstate which updates invisibility while player is not in map) if (!IsInWorld()) @@ -1552,19 +1576,26 @@ void Player::UpdateObjectVisibility(bool forced) AddToNotify(NOTIFY_VISIBILITY_CHANGED); else if (!isBeingLoaded()) { + if (!fromUpdate) // pussywizard: + { + bRequestForcedVisibilityUpdate = true; + return; + } Unit::UpdateObjectVisibility(true); UpdateVisibilityForPlayer(); } } template -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set& /*v*/) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, + std::vector& /*v*/) { s64.insert(target->GetGUID()); } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set& /*v*/) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, + std::vector& /*v*/) { // @HACK: This is to prevent objects like deeprun tram from disappearing // when player moves far from its spawn point while riding it @@ -1573,17 +1604,19 @@ inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set& v) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, + std::vector& v) { s64.insert(target->GetGUID()); - v.insert(target); + v.push_back(target); } template <> -inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, std::set& v) +inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, + std::vector& v) { s64.insert(target->GetGUID()); - v.insert(target); + v.push_back(target); } template @@ -1599,7 +1632,8 @@ inline void BeforeVisibilityDestroy(Creature* t, Player* p) } template -void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow) +void Player::UpdateVisibilityOf(T* target, UpdateData& data, + std::vector& visibleNow) { if (HaveAtClient(target)) { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 3fb3e3b82..3dc023eb4 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), _delayedTeleport(false) +MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -230,14 +230,8 @@ void MotionTransport::Update(uint32 diff) 3. transport moves from active to inactive grid 4. the grid that transport is currently in unloads */ - bool gridActive = GetMap()->IsGridLoaded(GetPositionX(), GetPositionY()); - - if (_staticPassengers.empty() && gridActive) // 2. + if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 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(); } } @@ -254,27 +248,18 @@ void MotionTransport::DelayedUpdate(uint32 /*diff*/) void MotionTransport::UpdatePosition(float x, float y, float z, float o) { - bool newActive = GetMap()->IsGridLoaded(x, y); - Cell oldCell(GetPositionX(), GetPositionY()); + if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case + GetMap()->LoadGrid(x, y); Relocate(x, y, z, o); UpdateModelPosition(); UpdatePassengerPositions(_passengers); - /* 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. + if (_staticPassengers.empty()) 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) @@ -321,7 +306,8 @@ void MotionTransport::RemovePassenger(WorldObject* passenger, bool withAll) { passenger->SetTransport(nullptr); passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - passenger->m_movementInfo.transport.Reset(); + passenger->m_movementInfo.transport.guid.Clear(); + passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); if (passenger->ToUnit()) { passenger->ToUnit()->ClearUnitState(UNIT_STATE_IGNORE_PATHFINDING); @@ -421,6 +407,9 @@ 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()); @@ -442,6 +431,7 @@ void MotionTransport::LoadStaticPassengers() void MotionTransport::UnloadStaticPassengers() { + SetPassengersLoaded(false); while (!_staticPassengers.empty()) { WorldObject* obj = *_staticPassengers.begin(); @@ -552,19 +542,11 @@ 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(); ) { @@ -610,8 +592,15 @@ 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) @@ -642,7 +631,7 @@ void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers) case TYPEID_UNIT: { Creature* creature = passenger->ToCreature(); - GetMap()->CreatureRelocation(creature, x, y, z, o, false); + GetMap()->CreatureRelocation(creature, x, y, z, o); creature->GetTransportHomePosition(x, y, z, o); CalculatePassengerPosition(x, y, z, &o); @@ -654,7 +643,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, false); + GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o); break; case TYPEID_DYNAMICOBJECT: GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o); @@ -791,6 +780,7 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m LastUsedScriptID = GetGOInfo()->ScriptId; AIM_Initialize(); + this->setActive(true); return true; } @@ -925,8 +915,7 @@ 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); - Relocate(x, y, z, o); - UpdateModelPosition(); + GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model UpdatePassengerPositions(); } @@ -953,14 +942,17 @@ void StaticTransport::UpdatePassengerPositions() switch (passenger->GetTypeId()) { case TYPEID_UNIT: - GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o, false); + GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o); 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, false); + GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o); break; case TYPEID_DYNAMICOBJECT: GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o); @@ -1009,7 +1001,8 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll) { passenger->SetTransport(nullptr); passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; - passenger->m_movementInfo.transport.Reset(); + passenger->m_movementInfo.transport.guid.Clear(); + passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); } } } diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index cc038e722..75fc9f9ee 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -68,6 +68,8 @@ 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); @@ -102,6 +104,7 @@ 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 61f1953c8..ae20ad666 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -32,6 +32,7 @@ #include "CreatureAIImpl.h" #include "CreatureGroups.h" #include "DisableMgr.h" +#include "DynamicVisibility.h" #include "Formulas.h" #include "GameObjectAI.h" #include "GameTime.h" @@ -43,7 +44,6 @@ #include "MoveSpline.h" #include "MoveSplineInit.h" #include "MovementGenerator.h" -#include "MovementPacketBuilder.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -317,6 +317,12 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f); + m_last_notify_mstime = 0; + m_delayed_unit_relocation_timer = 0; + m_delayed_unit_ai_notify_timer = 0; + bRequestForcedVisibilityUpdate = false; + m_applyResilience = false; _instantCast = false; @@ -405,6 +411,32 @@ void Unit::Update(uint32 p_time) if (!IsInWorld()) return; + // pussywizard: + if (GetTypeId() != TYPEID_PLAYER || (!ToPlayer()->IsBeingTeleported() && !bRequestForcedVisibilityUpdate)) + { + if (m_delayed_unit_relocation_timer) + { + if (m_delayed_unit_relocation_timer <= p_time) + { + m_delayed_unit_relocation_timer = 0; + //ExecuteDelayedUnitRelocationEvent(); + FindMap()->i_objectsForDelayedVisibility.insert(this); + } + else + m_delayed_unit_relocation_timer -= p_time; + } + if (m_delayed_unit_ai_notify_timer) + { + if (m_delayed_unit_ai_notify_timer <= p_time) + { + m_delayed_unit_ai_notify_timer = 0; + ExecuteDelayedUnitAINotifyEvent(); + } + else + m_delayed_unit_ai_notify_timer -= p_time; + } + } + _UpdateSpells( p_time ); if (CanHaveThreatList() && GetThreatMgr().isNeedUpdateToClient(p_time)) @@ -568,27 +600,14 @@ void Unit::UpdateSplineMovement(uint32 t_diff) SplineHandler handler(this); movespline->updateState(t_diff, handler); // Xinef: Spline was cleared by StopMoving, return - if (!movespline->Initialized()) { + if (!movespline->Initialized()) + { DisableSpline(); return; } bool arrived = movespline->Finalized(); - if (movespline->isCyclic()) - { - 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); - } - } - if (arrived) { DisableSpline(); @@ -597,11 +616,17 @@ 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) @@ -614,14 +639,16 @@ void Unit::UpdateSplinePosition() if (TransportBase* transport = GetDirectTransport()) transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation); - else - return; } - if (HasUnitState(UNIT_STATE_CANNOT_TURN)) - loc.orientation = GetOrientation(); + // Xinef: if we had spline running update orientation along with position + //if (HasUnitState(UNIT_STATE_CANNOT_TURN)) + // loc.orientation = GetOrientation(); - UpdatePosition(loc.x, loc.y, loc.z, loc.orientation); + if (GetTypeId() == TYPEID_PLAYER) + UpdatePosition(loc.x, loc.y, loc.z, loc.orientation); + else + ToCreature()->SetPosition(loc.x, loc.y, loc.z, loc.orientation); } void Unit::DisableSpline() @@ -15714,9 +15741,15 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) void Unit::CleanupsBeforeDelete(bool finalCleanup) { - CleanupBeforeRemoveFromMap(finalCleanup); + if (GetTransport()) + { + GetTransport()->RemovePassenger(this); + SetTransport(nullptr); + m_movementInfo.transport.Reset(); + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + } - WorldObject::CleanupsBeforeDelete(finalCleanup); + CleanupBeforeRemoveFromMap(finalCleanup); } void Unit::UpdateCharmAI() @@ -17489,17 +17522,13 @@ void Unit::SetContestedPvP(Player* attackedPlayer, bool lookForNearContestedGuar player->AddUnitState(UNIT_STATE_ATTACK_PLAYER); player->SetPlayerFlag(PLAYER_FLAGS_CONTESTED_PVP); // call MoveInLineOfSight for nearby contested guards - Acore::AIRelocationNotifier notifier(*this); - Cell::VisitWorldObjects(this, notifier, GetVisibilityRange()); + AddToNotify(NOTIFY_AI_RELOCATION); } - for (Unit* unit : m_Controlled) + if (!HasUnitState(UNIT_STATE_ATTACK_PLAYER)) { - if (!unit->HasUnitState(UNIT_STATE_ATTACK_PLAYER)) - { - unit->AddUnitState(UNIT_STATE_ATTACK_PLAYER); - Acore::AIRelocationNotifier notifier(*unit); - Cell::VisitWorldObjects(this, notifier, GetVisibilityRange()); - } + AddUnitState(UNIT_STATE_ATTACK_PLAYER); + // call MoveInLineOfSight for nearby contested guards + AddToNotify(NOTIFY_AI_RELOCATION); } } @@ -19346,7 +19375,7 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update) } } -void Unit::UpdateObjectVisibility(bool forced) +void Unit::UpdateObjectVisibility(bool forced, bool /*fromUpdate*/) { if (!forced) AddToNotify(NOTIFY_VISIBILITY_CHANGED); @@ -19354,7 +19383,8 @@ void Unit::UpdateObjectVisibility(bool forced) { WorldObject::UpdateObjectVisibility(true); Acore::AIRelocationNotifier notifier(*this); - Cell::VisitAllObjects(this, notifier, GetVisibilityRange()); + float radius = 60.0f; + Cell::VisitAllObjects(this, notifier, radius); } } @@ -20252,14 +20282,10 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel if (!Acore::IsValidMapCoord(x, y, z, orientation)) return false; - // 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); + float old_orientation = GetOrientation(); + float current_z = GetPositionZ(); + bool turn = (old_orientation != orientation); + bool relocated = (teleport || GetPositionX() != x || GetPositionY() != y || current_z != z); if (!GetVehicle()) { @@ -20285,8 +20311,6 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel UpdateObjectVisibility(false); } - UpdatePositionData(); - return (relocated || turn); } @@ -20717,6 +20741,124 @@ bool ConflagrateAuraStateDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time return true; } +void Unit::ExecuteDelayedUnitRelocationEvent() +{ + this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED); + if (!this->IsInWorld() || this->IsDuringRemoveFromWorld()) + return; + + if (this->HasSharedVision()) + for (SharedVisionList::const_iterator itr = this->GetSharedVisionList().begin(); itr != this->GetSharedVisionList().end(); ++itr) + if (Player* player = (*itr)) + { + if (player->IsOnVehicle(this) || !player->IsInWorld() || player->IsDuringRemoveFromWorld()) // players on vehicles have their own event executed (due to passenger relocation) + continue; + WorldObject* viewPoint = player; + if (player->m_seer && player->m_seer->IsInWorld()) + viewPoint = player->m_seer; + if (!viewPoint->IsPositionValid() || !player->IsPositionValid()) + continue; + + if (Unit* active = viewPoint->ToUnit()) + { + //if (active->IsVehicle()) // always check original unit here, last notify position is not relocated + // active = player; + + float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX(); + float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY(); + float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; + float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type); + if (distsq < mindistsq) + continue; + + // this will be relocated below sharedvision! + //active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ()); + } + + Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance + Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS); + relocateNoLarge.SendToSelf(); + Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance + Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE); + relocateLarge.SendToSelf(); + } + + if (Player* player = this->ToPlayer()) + { + WorldObject* viewPoint = player; + if (player->m_seer && player->m_seer->IsInWorld()) + viewPoint = player->m_seer; + + if (viewPoint->GetMapId() != player->GetMapId() || !viewPoint->IsPositionValid() || !player->IsPositionValid()) + return; + + if (Unit* active = viewPoint->ToUnit()) + { + if (active->IsVehicle()) + active = player; + + if (!player->GetFarSightDistance()) + { + float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX(); + float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY(); + float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; + + float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type); + if (distsq < mindistsq) + return; + + active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ()); + } + } + + Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance + Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS); + relocateNoLarge.SendToSelf(); + + if (!player->GetFarSightDistance()) + { + Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance + Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE); + relocateLarge.SendToSelf(); + } + + this->AddToNotify(NOTIFY_AI_RELOCATION); + } + else if (Creature* unit = this->ToCreature()) + { + if (!unit->IsPositionValid()) + return; + + float dx = unit->m_last_notify_position.GetPositionX() - unit->GetPositionX(); + float dy = unit->m_last_notify_position.GetPositionY() - unit->GetPositionY(); + float dz = unit->m_last_notify_position.GetPositionZ() - unit->GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; + float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(unit->FindMap()->GetEntry()->map_type); + if (distsq < mindistsq) + return; + + unit->m_last_notify_position.Relocate(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ()); + + Acore::CreatureRelocationNotifier relocate(*unit); + Cell::VisitAllObjects(unit, relocate, unit->GetVisibilityRange() + VISIBILITY_COMPENSATION); + + this->AddToNotify(NOTIFY_AI_RELOCATION); + } +} + +void Unit::ExecuteDelayedUnitAINotifyEvent() +{ + this->RemoveFromNotify(NOTIFY_AI_RELOCATION); + if (!this->IsInWorld() || this->IsDuringRemoveFromWorld()) + return; + + Acore::AIRelocationNotifier notifier(*this); + float radius = 60.0f; + Cell::VisitAllObjects(this, notifier, radius); +} + void Unit::SetInFront(WorldObject const* target) { if (!HasUnitState(UNIT_STATE_CANNOT_TURN)) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 84d147742..d2948aa7b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2145,7 +2145,7 @@ public: // common function for visibility checks for player/creatures with detection code [[nodiscard]] uint32 GetPhaseByAuras() const; void SetPhaseMask(uint32 newPhaseMask, bool update) override;// overwrite WorldObject::SetPhaseMask - void UpdateObjectVisibility(bool forced = true) override; + void UpdateObjectVisibility(bool forced = true, bool fromUpdate = false) override; SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; uint32 m_lastSanctuaryTime; @@ -2419,6 +2419,14 @@ public: void AddPointedBy(SafeUnitPointer* sup) { SafeUnitPointerSet.insert(sup); } void RemovePointedBy(SafeUnitPointer* sup) { SafeUnitPointerSet.erase(sup); } static void HandleSafeUnitPointersOnDelete(Unit* thisUnit); + // Relocation Nofier optimization + Position m_last_notify_position; + uint32 m_last_notify_mstime; + uint16 m_delayed_unit_relocation_timer; + uint16 m_delayed_unit_ai_notify_timer; + bool bRequestForcedVisibilityUpdate; + void ExecuteDelayedUnitRelocationEvent(); + void ExecuteDelayedUnitAINotifyEvent(); // cooldowns [[nodiscard]] virtual bool HasSpellCooldown(uint32 /*spell_id*/) const { return false; } @@ -2577,7 +2585,7 @@ private: uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; uint32 m_lastManaUse; // msecs - TimeTrackerSmall m_splineSyncTimer; + //TimeTrackerSmall m_movesplineTimer; 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 de264e947..b33502da2 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -545,8 +545,7 @@ bool Vehicle::IsVehicleInUse() void Vehicle::TeleportVehicle(float x, float y, float z, float ang) { - if (!_me->GetMap()->IsGridLoaded(x, y)) - _me->GetMap()->LoadGrid(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/Grid.h b/src/server/game/Grids/Grid.h index d67b9ca31..b9cafdbe0 100644 --- a/src/server/game/Grids/Grid.h +++ b/src/server/game/Grids/Grid.h @@ -96,12 +96,6 @@ public: visitor.Visit(i_objects); } - template - uint32 GetWorldObjectCountInGrid() const - { - return i_objects.template Count(); - } - /** Inserts a container type object into the grid. */ template void AddGridObject(SPECIFIC_OBJECT* obj) diff --git a/src/server/game/Grids/GridStates.cpp b/src/server/game/Grids/GridStates.cpp deleted file mode 100644 index eb0183b78..000000000 --- a/src/server/game/Grids/GridStates.cpp +++ /dev/null @@ -1,65 +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 "GridStates.h" -#include "GridNotifiers.h" -#include "Log.h" -#include "Map.h" -#include "ObjectGridLoader.h" - -void InvalidState::Update(Map&, NGridType&, GridInfo&, uint32) const -{ -} - -void ActiveState::Update(Map& map, NGridType& grid, GridInfo& info, uint32 diff) const -{ - // Only check grid activity every (grid_expiry/10) ms, because it's really useless to do it every cycle - info.UpdateTimeTracker(diff); - if (info.getTimeTracker().Passed()) - { - if (!grid.GetWorldObjectCountInNGrid() && !map.ActiveObjectsNearGrid(grid)) - { - ObjectGridStoper worker; - TypeContainerVisitor visitor(worker); - grid.VisitAllGrids(visitor); - grid.SetGridState(GRID_STATE_IDLE); - LOG_DEBUG("maps", "Grid[{}, {}] on map {} moved to IDLE state", grid.getX(), grid.getY(), map.GetId()); - } - else - map.ResetGridExpiry(grid, 0.1f); - } -} - -void IdleState::Update(Map& map, NGridType& grid, GridInfo&, uint32) const -{ - map.ResetGridExpiry(grid); - grid.SetGridState(GRID_STATE_REMOVAL); - LOG_DEBUG("maps", "Grid[{}, {}] on map {} moved to REMOVAL state", grid.getX(), grid.getY(), map.GetId()); -} - -void RemovalState::Update(Map& map, NGridType& grid, GridInfo& info, uint32 diff) const -{ - if (!info.getUnloadLock()) - { - info.UpdateTimeTracker(diff); - if (info.getTimeTracker().Passed() && !map.UnloadGrid(grid, false)) - { - LOG_DEBUG("maps", "Grid[{}, {}] for map {} differed unloading due to players or active objects nearby", grid.getX(), grid.getY(), map.GetId()); - map.ResetGridExpiry(grid); - } - } -} diff --git a/src/server/game/Grids/GridStates.h b/src/server/game/Grids/GridStates.h deleted file mode 100644 index 5b0aec3d9..000000000 --- a/src/server/game/Grids/GridStates.h +++ /dev/null @@ -1,56 +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 ACORE_GRIDSTATES_H -#define ACORE_GRIDSTATES_H - -#include "GridDefines.h" -#include "NGrid.h" - -class Map; - -class AC_GAME_API GridState -{ - public: - virtual ~GridState() { }; - virtual void Update(Map &, NGridType&, GridInfo &, uint32 t_diff) const = 0; -}; - -class AC_GAME_API InvalidState : public GridState -{ - public: - void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; -}; - -class AC_GAME_API ActiveState : public GridState -{ - public: - void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; -}; - -class AC_GAME_API IdleState : public GridState -{ - public: - void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; -}; - -class AC_GAME_API RemovalState : public GridState -{ - public: - void Update(Map &, NGridType &, GridInfo &, uint32 t_diff) const override; -}; -#endif diff --git a/src/server/game/Grids/NGrid.h b/src/server/game/Grids/NGrid.h index 9a8f64fdb..ff1f1ed81 100644 --- a/src/server/game/Grids/NGrid.h +++ b/src/server/game/Grids/NGrid.h @@ -26,42 +26,6 @@ #include "Timer.h" #include "Util.h" -#define DEFAULT_VISIBILITY_NOTIFY_PERIOD 1000 - -class AC_GAME_API GridInfo -{ -public: - GridInfo(); - 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; } - void setUnloadReferenceLock(bool on) { i_unloadReferenceLock = on; } - void incUnloadActiveLock() { ++i_unloadActiveLockCount; } - void decUnloadActiveLock() { if (i_unloadActiveLockCount) --i_unloadActiveLockCount; } - - void setTimer(TimeTracker const& pTimer) { i_timer = pTimer; } - void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); } - void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); } - PeriodicTimer& getRelocationTimer() { return vis_Update; } -private: - TimeTracker i_timer; - PeriodicTimer vis_Update; - - uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading) - bool i_unloadExplicitLock : 1; // explicit manual lock or config setting - bool i_unloadReferenceLock : 1; // lock from instance map copy -}; - -typedef enum -{ - GRID_STATE_INVALID = 0, - GRID_STATE_ACTIVE = 1, - GRID_STATE_IDLE = 2, - GRID_STATE_REMOVAL = 3, - MAX_GRID_STATE = 4 -} grid_state_t; - template < uint32 N, @@ -73,10 +37,10 @@ class NGrid { public: typedef Grid GridType; - 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) - { } + NGrid(uint32 id, int32 x, int32 y) + : i_gridId(id), i_x(x), i_y(y), i_GridObjectDataLoaded(false) + { + } GridType& GetGridType(const uint32 x, const uint32 y) { @@ -91,9 +55,6 @@ public: } [[nodiscard]] uint32 GetGridId() const { return i_gridId; } - void SetGridId(uint32 id) { i_gridId = id; } - [[nodiscard]] grid_state_t GetGridState() const { return i_cellstate; } - void SetGridState(grid_state_t s) { i_cellstate = s; } [[nodiscard]] int32 getX() const { return i_x; } [[nodiscard]] int32 getY() const { return i_y; } @@ -104,16 +65,6 @@ public: [[nodiscard]] bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; } void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; } - GridInfo* getGridInfoRef() { return &i_GridInfo; } - TimeTracker const& getTimeTracker() const { return i_GridInfo.getTimeTracker(); } - bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); } - void setUnloadExplicitLock(bool on) { i_GridInfo.setUnloadExplicitLock(on); } - void setUnloadReferenceLock(bool on) { i_GridInfo.setUnloadReferenceLock(on); } - void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); } - void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); } - 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) { @@ -152,23 +103,11 @@ public: GetGridType(x, y).Visit(visitor); } - template - uint32 GetWorldObjectCountInNGrid() const - { - uint32 count = 0; - for (uint32 x = 0; x < N; ++x) - for (uint32 y = 0; y < N; ++y) - count += i_cells[x][y].template GetWorldObjectCountInGrid(); - return count; - } - private: uint32 i_gridId; - GridInfo i_GridInfo; GridReference > i_Reference; int32 i_x; int32 i_y; - grid_state_t i_cellstate; GridType i_cells[N][N]; bool i_GridObjectDataLoaded; }; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 9b8ae064f..7b25ab1bd 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -16,7 +16,6 @@ */ #include "GridNotifiers.h" -#include "GridNotifiersImpl.h" #include "Map.h" #include "ObjectAccessor.h" #include "SpellInfo.h" @@ -24,10 +23,22 @@ #include "Transport.h" #include "UpdateData.h" #include "WorldPacket.h" -#include "CellImpl.h" using namespace Acore; +void VisibleNotifier::Visit(GameObjectMapType& m) +{ + for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + GameObject* go = iter->GetSource(); + if (i_largeOnly != go->IsVisibilityOverridden()) + continue; + + vis_guids.erase(go->GetGUID()); + i_player.UpdateVisibilityOf(go, i_data, i_visibleNow); + } +} + void VisibleNotifier::SendToSelf() { // at this moment i_clientGUIDs have guids that not iterate at grid level checks @@ -35,6 +46,9 @@ void VisibleNotifier::SendToSelf() if (Transport* transport = i_player.GetTransport()) for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr) { + if (i_largeOnly != (*itr)->IsVisibilityOverridden()) + continue; + if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end()) { vis_guids.erase((*itr)->GetGUID()); @@ -51,9 +65,6 @@ void VisibleNotifier::SendToSelf() case TYPEID_UNIT: i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow); break; - case TYPEID_DYNAMICOBJECT: - i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow); - break; default: break; } @@ -62,6 +73,12 @@ void VisibleNotifier::SendToSelf() for (GuidUnorderedSet::const_iterator it = vis_guids.begin(); it != vis_guids.end(); ++it) { + if (WorldObject* obj = ObjectAccessor::GetWorldObject(i_player, *it)) + { + if (i_largeOnly != obj->IsVisibilityOverridden()) + continue; + } + // pussywizard: static transports are removed only in RemovePlayerFromMap and here if can no longer detect (eg. phase changed) if ((*it).IsTransport()) if (GameObject* staticTrans = i_player.GetMap()->GetGameObject(*it)) @@ -86,8 +103,11 @@ void VisibleNotifier::SendToSelf() i_data.BuildPacket(&packet); i_player.GetSession()->SendPacket(&packet); - for (std::set::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) + for (std::vector::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it) { + if (i_largeOnly != (*it)->IsVisibilityOverridden()) + continue; + i_player.GetInitialVisiblePackets(*it); } } @@ -158,23 +178,6 @@ void PlayerRelocationNotifier::Visit(PlayerMapType& m) } } -void PlayerRelocationNotifier::Visit(CreatureMapType& m) -{ - bool relocated_for_ai = (&i_player == i_player.m_seer); - - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Creature* c = iter->GetSource(); - - vis_guids.erase(c->GetGUID()); - - i_player.UpdateVisibilityOf(c, i_data, i_visibleNow); - - if (relocated_for_ai && !c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - CreatureUnitRelocationWorker(c, &i_player); - } -} - void CreatureRelocationNotifier::Visit(PlayerMapType& m) { for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) @@ -191,58 +194,6 @@ void CreatureRelocationNotifier::Visit(PlayerMapType& m) } } -void CreatureRelocationNotifier::Visit(CreatureMapType& m) -{ - if (!i_creature.IsAlive()) - return; - - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Creature* c = iter->GetSource(); - CreatureUnitRelocationWorker(&i_creature, c); - - if (!c->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - CreatureUnitRelocationWorker(c, &i_creature); - } -} - -void DelayedUnitRelocation::Visit(CreatureMapType& m) -{ - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Creature* unit = iter->GetSource(); - if (!unit->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - continue; - - CreatureRelocationNotifier relocate(*unit); - - TypeContainerVisitor c2world_relocation(relocate); - TypeContainerVisitor c2grid_relocation(relocate); - - cell.Visit(p, c2world_relocation, i_map, *unit, i_radius); - cell.Visit(p, c2grid_relocation, i_map, *unit, i_radius); - } -} - -void DelayedUnitRelocation::Visit(PlayerMapType& m) -{ - for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - Player* player = iter->GetSource(); - WorldObject const* viewPoint = player->m_seer; - - if (!viewPoint->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) - continue; - - if (player != viewPoint && !viewPoint->IsPositionValid()) - continue; - - PlayerRelocationNotifier relocate(*player); - Cell::VisitAllObjects(viewPoint, relocate, i_radius, false); - relocate.SendToSelf(); - } -} - void AIRelocationNotifier::Visit(CreatureMapType& m) { bool self = isCreature && !((Creature*)(&i_unit))->IsMoveInLineOfSightStrictlyDisabled(); @@ -390,9 +341,14 @@ void MessageDistDelivererToHostile::Visit(DynamicObjectMapType& m) template void ObjectUpdater::Visit(GridRefMgr& m) { - for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ++iter) - if (iter->GetSource()->IsInWorld()) - iter->GetSource()->Update(i_timeDiff); + T* obj; + for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ) + { + obj = iter->GetSource(); + ++iter; + if (obj->IsInWorld() && (i_largeOnly == obj->IsVisibilityOverridden())) + obj->Update(i_timeDiff); + } } bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 86fbfe44d..e06b9091f 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -42,10 +42,18 @@ namespace Acore { Player& i_player; GuidUnorderedSet vis_guids; - std::set i_visibleNow; + std::vector& i_visibleNow; + bool i_gobjOnly; + bool i_largeOnly; UpdateData i_data; - VisibleNotifier(Player& player) : i_player(player), vis_guids(player.m_clientGUIDs) {} + VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) : + i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly) + { + i_visibleNow.clear(); + } + + void Visit(GameObjectMapType&); template void Visit(GridRefMgr& m); void SendToSelf(void); }; @@ -63,10 +71,9 @@ namespace Acore struct PlayerRelocationNotifier : public VisibleNotifier { - PlayerRelocationNotifier(Player& player) : VisibleNotifier(player) { } + PlayerRelocationNotifier(Player& player, bool largeOnly): VisibleNotifier(player, false, largeOnly) { } template void Visit(GridRefMgr& m) { VisibleNotifier::Visit(m); } - void Visit(CreatureMapType&); void Visit(PlayerMapType&); }; @@ -75,20 +82,6 @@ namespace Acore Creature& i_creature; CreatureRelocationNotifier(Creature& c) : i_creature(c) {} template void Visit(GridRefMgr&) {} - void Visit(CreatureMapType&); - void Visit(PlayerMapType&); - }; - - struct DelayedUnitRelocation - { - Map& i_map; - Cell& cell; - CellCoord& p; - const float i_radius; - DelayedUnitRelocation(Cell& c, CellCoord& pair, Map& map, float radius) : - i_map(map), cell(c), p(pair), i_radius(radius) { } - template void Visit(GridRefMgr&) { } - void Visit(CreatureMapType&); void Visit(PlayerMapType&); }; @@ -101,25 +94,6 @@ namespace Acore void Visit(CreatureMapType&); }; - struct GridUpdater - { - GridType& i_grid; - uint32 i_timeDiff; - GridUpdater(GridType& grid, uint32 diff) : i_grid(grid), i_timeDiff(diff) { } - - template void updateObjects(GridRefMgr& m) - { - for (typename GridRefMgr::iterator iter = m.begin(); iter != m.end(); ++iter) - iter->GetSource()->Update(i_timeDiff); - } - - void Visit(PlayerMapType& m) { updateObjects(m); } - void Visit(CreatureMapType& m) { updateObjects(m); } - void Visit(GameObjectMapType& m) { updateObjects(m); } - void Visit(DynamicObjectMapType& m) { updateObjects(m); } - void Visit(CorpseMapType& m) { updateObjects(m); } - }; - struct MessageDistDeliverer { WorldObject const* i_source; @@ -180,7 +154,8 @@ namespace Acore struct ObjectUpdater { uint32 i_timeDiff; - explicit ObjectUpdater(const uint32 diff) : i_timeDiff(diff) {} + bool i_largeOnly; + explicit ObjectUpdater(const uint32 diff, bool largeOnly) : i_timeDiff(diff), i_largeOnly(largeOnly) {} template void Visit(GridRefMgr& m); void Visit(PlayerMapType&) {} void Visit(CorpseMapType&) {} diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 8741828ea..3cd1b77dc 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -32,8 +32,15 @@ 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) { + if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden()) + continue; + vis_guids.erase(iter->GetSource()->GetGUID()); i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow); } diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index 09e66bc96..628189ae4 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -25,36 +25,6 @@ #include "ObjectMgr.h" #include "Transport.h" #include "Vehicle.h" -#include "GameTime.h" - -void ObjectGridEvacuator::Visit(CreatureMapType& m) -{ - // creature in unloading grid can have respawn point in another grid - // if it will be unloaded then it will not respawn in original grid until unload/load original grid - // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn. - for (CreatureMapType::iterator iter = m.begin(); iter != m.end();) - { - Creature* c = iter->GetSource(); - ++iter; - - ASSERT(!c->IsPet() && "ObjectGridRespawnMover must not be called for pets"); - c->GetMap()->CreatureRespawnRelocation(c, true); - } -} - -void ObjectGridEvacuator::Visit(GameObjectMapType& m) -{ - // gameobject in unloading grid can have respawn point in another grid - // if it will be unloaded then it will not respawn in original grid until unload/load original grid - // move to respawn point to prevent this case. For player view in respawn grid this will be normal respawn. - for (GameObjectMapType::iterator iter = m.begin(); iter != m.end();) - { - GameObject* go = iter->GetSource(); - ++iter; - - go->GetMap()->GameObjectRespawnRelocation(go, true); - } -} // for loading world object at grid loading (Corpses) //TODO: to implement npc on transport, also need to load npcs at grid loading @@ -114,6 +84,18 @@ 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*/) { @@ -124,13 +106,8 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgrGetCreatureRespawnTime(guid) > now) - continue; - Creature* obj = new Creature(); + ObjectGuid::LowType guid = *i_guid; if (!obj->LoadFromDB(guid, map)) { delete obj; @@ -156,12 +133,7 @@ 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(); @@ -257,17 +229,6 @@ void ObjectGridUnloader::Visit(GridRefMgr& m) } } -void ObjectGridStoper::Visit(CreatureMapType& m) -{ - // stop any fights at grid de-activation and remove dynobjects created at cast by creatures - for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - { - iter->GetSource()->RemoveAllDynObjects(); - if (iter->GetSource()->IsInCombat()) - iter->GetSource()->CombatStop(); - } -} - template void ObjectGridCleaner::Visit(GridRefMgr& m) { diff --git a/src/server/game/Grids/ObjectGridLoader.h b/src/server/game/Grids/ObjectGridLoader.h index d16c3c5bc..863e5f15f 100644 --- a/src/server/game/Grids/ObjectGridLoader.h +++ b/src/server/game/Grids/ObjectGridLoader.h @@ -53,23 +53,6 @@ private: uint32 i_corpses; }; -//Stop the creatures before unloading the NGrid -class AC_GAME_API ObjectGridStoper -{ -public: - void Visit(CreatureMapType& m); - template void Visit(GridRefMgr&) { } -}; - -//Move the foreign creatures back to respawn positions before unloading the NGrid -class AC_GAME_API ObjectGridEvacuator -{ -public: - void Visit(CreatureMapType& m); - void Visit(GameObjectMapType& m); - template void Visit(GridRefMgr&) { } -}; - //Clean up and remove from world class ObjectGridCleaner { diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 551fea862..f0889150b 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -49,20 +49,19 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& /*recvData*/) void WorldSession::HandleMoveWorldportAck() { - Player* player = GetPlayer(); // ignore unexpected far teleports - if (!player->IsBeingTeleportedFar()) + if (!GetPlayer()->IsBeingTeleportedFar()) return; - player->SetSemaphoreTeleportFar(0); + GetPlayer()->SetSemaphoreTeleportFar(0); // get the teleport destination - WorldLocation const& loc = player->GetTeleportDest(); + WorldLocation const& loc = GetPlayer()->GetTeleportDest(); // possible errors in the coordinate validity check if (!MapMgr::IsValidMapCoord(loc)) { - LogoutPlayer(false); + KickPlayer("!MapMgr::IsValidMapCoord(loc)"); return; } @@ -70,202 +69,198 @@ void WorldSession::HandleMoveWorldportAck() MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId()); InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId()); - Map* oldMap = player->GetMap(); - if (player->IsInWorld()) + Map* oldMap = GetPlayer()->GetMap(); + if (GetPlayer()->IsInWorld()) { - 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); + 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); } // reset instance validity, except if going to an instance inside an instance - if (!player->m_InstanceValid && !mInstance) + if (!GetPlayer()->m_InstanceValid && !mInstance) { - player->m_InstanceValid = true; + GetPlayer()->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(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty())) - sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true); + if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty())) + sInstanceSaveMgr->PlayerUnbindInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true); } // relocate the player to the teleport destination - Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), player); + Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer()); // 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(player, false)) + if (!newMap || newMap->CannotEnter(GetPlayer(), false)) { - 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); + 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); return; } - float z = loc.GetPositionZ() + player->GetHoverHeight(); - player->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); + float z = loc.GetPositionZ() + GetPlayer()->GetHoverHeight(); + GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); - player->ResetMap(); - player->SetMap(newMap); + GetPlayer()->ResetMap(); + GetPlayer()->SetMap(newMap); - player->UpdatePositionData(); + GetPlayer()->UpdatePositionData(); - player->SendInitialPacketsBeforeAddToMap(); - if (!player->GetMap()->AddPlayerToMap(player)) + GetPlayer()->SendInitialPacketsBeforeAddToMap(); + if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) { LOG_ERROR("network.opcode", "WORLD: failed to teleport player {} ({}) to map {} because of unknown reason!", - 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); + 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); 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(player->GetPositionX(), player->GetPositionY())); + CellCoord pair(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY())); Cell cell(pair); if (!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid()) { - LogoutPlayer(false); + KickPlayer("!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid()"); return; } - - if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY())) - newMap->LoadGrid(player->GetPositionX(), player->GetPositionY()); + newMap->LoadGrid(GetPlayer()->GetPositionX(), GetPlayer()->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); - player->SetPendingSpectatorForBG(0); + GetPlayer()->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(player->GetPositionX(), player->GetPositionY())); + // xinef: do this again, player can be teleported inside bg->AddPlayer(_player)!!!! + CellCoord pair2(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->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()); - if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY())) - newMap->LoadGrid(player->GetPositionX(), player->GetPositionY()); - - player->SendInitialPacketsAfterAddToMap(); + GetPlayer()->SendInitialPacketsAfterAddToMap(); // flight fast teleport case - if (player->IsInFlight()) + if (GetPlayer()->IsInFlight()) { - if (!player->InBattleground()) + if (!GetPlayer()->InBattleground()) { // short preparations to continue flight - MovementGenerator* movementGenerator = player->GetMotionMaster()->top(); - movementGenerator->Initialize(player); + MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top(); + movementGenerator->Initialize(GetPlayer()); return; } // battleground state prepare, stop flight - player->GetMotionMaster()->MovementExpired(); - player->CleanupAfterTaxiFlight(); + GetPlayer()->GetMotionMaster()->MovementExpired(); + GetPlayer()->CleanupAfterTaxiFlight(); } // resurrect character at enter into instance where his corpse exist after add to map - Corpse* corpse = player->GetMap()->GetCorpseByPlayer(player->GetGUID()); + Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID()); if (corpse && corpse->GetType() != CORPSE_BONES) { if (mEntry->IsDungeon()) { - player->ResurrectPlayer(0.5f); - player->SpawnCorpseBones(); + GetPlayer()->ResurrectPlayer(0.5f); + GetPlayer()->SpawnCorpseBones(); } } if (!corpse && mEntry->IsDungeon()) { // resurrect character upon entering instance when the corpse is not available anymore - if (player->GetCorpseLocation().GetMapId() == mEntry->MapID) + if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->MapID) { - player->ResurrectPlayer(0.5f); - player->RemoveCorpse(); + GetPlayer()->ResurrectPlayer(0.5f); + GetPlayer()->RemoveCorpse(); } } bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena(); if (mInstance) { - Difficulty diff = player->GetDifficulty(mEntry->IsRaid()); + Difficulty diff = GetPlayer()->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()); - player->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true); + GetPlayer()->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; - player->GetZoneAndAreaId(newzone, newarea); - player->UpdateZone(newzone, newarea); + GetPlayer()->GetZoneAndAreaId(newzone, newarea); + GetPlayer()->UpdateZone(newzone, newarea); // honorless target - if (player->pvpInfo.IsHostile) - player->CastSpell(player, 2479, true); + if (GetPlayer()->pvpInfo.IsHostile) + GetPlayer()->CastSpell(GetPlayer(), 2479, true); // in friendly area - else if (player->IsPvP() && !player->HasPlayerFlag(PLAYER_FLAGS_IN_PVP)) - player->UpdatePvP(false, false); + else if (GetPlayer()->IsPvP() && !GetPlayer()->HasPlayerFlag(PLAYER_FLAGS_IN_PVP)) + GetPlayer()->UpdatePvP(false, false); // resummon pet - player->ResummonPetTemporaryUnSummonedIfAny(); + GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); //lets process all delayed operations on successful teleport - player->ProcessDelayedOperations(); + GetPlayer()->ProcessDelayedOperations(); } void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 66927f642..ec6854ede 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -20,7 +20,6 @@ #include "Config.h" #include "GameTime.h" #include "GridNotifiers.h" -#include "GridStates.h" #include "Group.h" #include "InstanceScript.h" #include "Log.h" diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 68e54d3ea..5f6a1418e 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -24,8 +24,6 @@ #include "GameTime.h" #include "Geometry.h" #include "GridNotifiers.h" -#include "GridNotifiersImpl.h" -#include "GridStates.h" #include "Group.h" #include "InstanceScript.h" #include "LFGMgr.h" @@ -58,8 +56,6 @@ u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} }; static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 }; static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 }; -GridState* si_GridStates[MAX_GRID_STATE]; - ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE), WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { } @@ -69,11 +65,6 @@ 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(); @@ -195,10 +186,8 @@ void Map::LoadMap(int gx, int gy, bool reload) return; // load grid map for base map - if (!m_parentMap->GridMaps[gx][gy]) - m_parentMap->EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy)); + m_parentMap->EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); - ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridCoord(gx, gy)); GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; return; } @@ -243,14 +232,11 @@ void Map::LoadMapAndVMap(int gx, int gy) } } -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : - _creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), +Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), - m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0), - m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD), - m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()), - i_gridExpiry(expiry), - i_scriptLock(false), _defaultLight(GetDefaultMapLight(id)) + m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), + _instanceResetPeriod(0), m_activeNonPlayersIter(m_activeNonPlayers.end()), + _transportsUpdateIter(_transports.end()), i_scriptLock(false), _defaultLight(GetDefaultMapLight(id)) { m_parentMap = (_parent ? _parent : this); for (unsigned int idx = 0; idx < MAX_NUMBER_OF_GRIDS; ++idx) @@ -273,7 +259,6 @@ void Map::InitVisibilityDistance() { //init visibility for continents m_VisibleDistance = World::GetMaxVisibleDistanceOnContinents(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodOnContinents(); switch (GetId()) { @@ -446,9 +431,8 @@ void Map::DeleteFromWorld(Player* player) void Map::EnsureGridCreated(const GridCoord& p) { - if (getNGrid(p.x_coord, p.y_coord)) + if (getNGrid(p.x_coord, p.y_coord)) // pussywizard return; - std::lock_guard guard(GridLock); EnsureGridCreated_i(p); } @@ -459,15 +443,11 @@ void Map::EnsureGridCreated_i(const GridCoord& p) { if (!getNGrid(p.x_coord, p.y_coord)) { - LOG_DEBUG("maps", "Creating grid[{}, {}] for map {} instance {}", p.x_coord, p.y_coord, GetId(), i_InstanceId); - - 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); + // pussywizard: moved setNGrid to the end of the function + NGridType* ngt = new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord); // build a linkage between this map and NGridType - buildNGridLinkage(getNGrid(p.x_coord, p.y_coord)); - - getNGrid(p.x_coord, p.y_coord)->SetGridState(GRID_STATE_IDLE); + buildNGridLinkage(ngt); // pussywizard: getNGrid(x, y) changed to: ngt //z coord int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; @@ -477,22 +457,9 @@ void Map::EnsureGridCreated_i(const GridCoord& p) { LoadMapAndVMap(gx, gy); } - } -} -//Load NGrid and make it active -void Map::EnsureGridLoadedForActiveObject(const Cell& cell, WorldObject* object) -{ - EnsureGridLoaded(cell); - NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - ASSERT(grid != nullptr); - - // refresh grid state & timer - if (grid->GetGridState() != GRID_STATE_ACTIVE) - { - LOG_DEBUG("maps", "Active object {} triggers loading of grid [{}, {}] on map {}", object->GetGUID().ToString().c_str(), cell.GridX(), cell.GridY(), GetId()); - ResetGridExpiry(*grid, 0.1f); - grid->SetGridState(GRID_STATE_ACTIVE); + // pussywizard: moved here + setNGrid(ngt, p.x_coord, p.y_coord); } } @@ -503,13 +470,13 @@ bool Map::EnsureGridLoaded(const Cell& cell) NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); ASSERT(grid); - if (!grid->isGridObjectDataLoaded()) + if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) { //if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY())) //{ LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId); - grid->setGridObjectDataLoaded(true); + setGridObjectDataLoaded(true, cell.GridX(), cell.GridY()); ObjectGridLoader loader(*grid, this, cell); loader.LoadN(); @@ -522,29 +489,6 @@ bool Map::EnsureGridLoaded(const Cell& cell) return false; } -void Map::GridMarkNoUnload(uint32 x, uint32 y) -{ - // First make sure this grid is loaded - float gX = ((float(x) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2); - float gY = ((float(y) - 0.5f - CENTER_GRID_ID) * SIZE_OF_GRIDS) + (CENTER_GRID_OFFSET * 2); - Cell cell = Cell(gX, gY); - EnsureGridLoaded(cell); - - // Mark as don't unload - NGridType* grid = getNGrid(x, y); - grid->setUnloadExplicitLock(true); -} - -void Map::GridUnmarkNoUnload(uint32 x, uint32 y) -{ - // If grid is loaded, clear unload lock - if (IsGridLoaded(GridCoord(x, y))) - { - NGridType* grid = getNGrid(x, y); - grid->setUnloadExplicitLock(false); - } -} - void Map::LoadGrid(float x, float y) { EnsureGridLoaded(Cell(x, y)); @@ -557,22 +501,6 @@ void Map::LoadAllCells() LoadGrid((cellX + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL, (cellY + 0.5f - CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL); } -void Map::InitStateMachine() -{ - si_GridStates[GRID_STATE_INVALID] = new InvalidState(); - si_GridStates[GRID_STATE_ACTIVE] = new ActiveState(); - si_GridStates[GRID_STATE_IDLE] = new IdleState(); - si_GridStates[GRID_STATE_REMOVAL] = new RemovalState(); -} - -void Map::DeleteStateMachine() -{ - delete si_GridStates[GRID_STATE_INVALID]; - delete si_GridStates[GRID_STATE_ACTIVE]; - delete si_GridStates[GRID_STATE_IDLE]; - delete si_GridStates[GRID_STATE_REMOVAL]; -} - bool Map::AddPlayerToMap(Player* player) { CellCoord cellCoord = Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()); @@ -584,7 +512,7 @@ bool Map::AddPlayerToMap(Player* player) } Cell cell(cellCoord); - EnsureGridLoadedForActiveObject(cell, player); + EnsureGridLoaded(cell); AddToGrid(player, cell); // Check if we are adding to correct map @@ -612,15 +540,15 @@ void Map::InitializeObject(T* /*obj*/) } template<> -void Map::InitializeObject(Creature* obj) +void Map::InitializeObject(Creature* /*obj*/) { - obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE; + //obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE; } template<> -void Map::InitializeObject(GameObject* obj) +void Map::InitializeObject(GameObject* /*obj*/) { - obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE; + //obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE; } template @@ -648,7 +576,7 @@ bool Map::AddToMap(T* obj, bool checkTransport) Cell cell(cellCoord); if (obj->isActiveObject()) - EnsureGridLoadedForActiveObject(cell, obj); + EnsureGridLoaded(cell); else EnsureGridCreated(GridCoord(cell.GridX(), cell.GridY())); @@ -695,7 +623,15 @@ 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 @@ -719,12 +655,48 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/) bool Map::IsGridLoaded(const GridCoord& p) const { - NGridType* grid = getNGrid(p.x_coord, p.y_coord); - return grid && grid->isGridObjectDataLoaded(); + return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); +} + +void Map::VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor& gridVisitor, + TypeContainerVisitor& worldVisitor, + TypeContainerVisitor& largeGridVisitor, + TypeContainerVisitor& largeWorldVisitor) +{ + // check for valid position + if (!player->IsPositionValid()) + return; + + // check normal grid activation range of the player + VisitNearbyCellsOf(player, gridVisitor, worldVisitor, largeGridVisitor, largeWorldVisitor); + + // check maximum visibility distance for large creatures + CellArea area = Cell::CalculateCellArea(player->GetPositionX(), player->GetPositionY(), MAX_VISIBILITY_DISTANCE); + + for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x) + { + for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (isCellMarkedLarge(cell_id)) + continue; + + markCellLarge(cell_id); + CellCoord pair(x, y); + Cell cell(pair); + + Visit(cell, largeGridVisitor); + Visit(cell, largeWorldVisitor); + } + } } void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor& gridVisitor, - TypeContainerVisitor& worldVisitor) + TypeContainerVisitor& worldVisitor, + TypeContainerVisitor& largeGridVisitor, + TypeContainerVisitor& largeWorldVisitor) { // Check for valid position if (!obj->IsPositionValid()) @@ -749,10 +721,17 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitorGetSource(); + + if (!player || !player->IsInWorld()) + continue; + + // update players at tick + player->Update(s_diff); + } + + HandleDelayedVisibility(); + return; + } + /// update active cells around players and active objects resetMarkedCells(); + resetMarkedCellsLarge(); - Acore::ObjectUpdater updater(t_diff); + Acore::ObjectUpdater updater(t_diff, false); // for creature TypeContainerVisitor grid_object_update(updater); // for pets TypeContainerVisitor world_object_update(updater); + // for large creatures + Acore::ObjectUpdater largeObjectUpdater(t_diff, true); + TypeContainerVisitor grid_large_object_update(largeObjectUpdater); + TypeContainerVisitor world_large_object_update(largeObjectUpdater); + // pussywizard: container for far creatures in combat with players std::vector 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, grid_large_object_update, world_large_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) @@ -801,11 +815,20 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) // update players at tick player->Update(s_diff); - VisitNearbyCellsOf(player, grid_object_update, world_object_update); + VisitNearbyCellsOfPlayer(player, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update); // If player is using far sight, visit that object too if (WorldObject* viewPoint = player->GetViewpoint()) - VisitNearbyCellsOf(viewPoint, grid_object_update, world_object_update); + { + if (Creature* viewCreature = viewPoint->ToCreature()) + { + VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update); + } + else if (DynamicObject* viewObject = viewPoint->ToDynObject()) + { + VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update); + } + } // handle updates for creatures in combat with player and are more than X yards away if (player->IsInCombat()) @@ -823,22 +846,10 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) ref = ref->next(); } for (std::vector::const_iterator itr = updateList.begin(); itr != updateList.end(); ++itr) - VisitNearbyCellsOf(*itr, grid_object_update, world_object_update); + VisitNearbyCellsOf(*itr, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update); } } - // 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; @@ -864,8 +875,7 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) MoveAllGameObjectsInMoveList(); MoveAllDynamicObjectsInMoveList(); - if (!m_mapRefMgr.IsEmpty() || !m_activeNonPlayers.empty()) - ProcessRelocationNotifies(t_diff); + HandleDelayedVisibility(); sScriptMgr->OnMapUpdate(this, t_diff); @@ -878,6 +888,15 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) METRIC_TAG("map_instanceid", std::to_string(GetInstanceId()))); } +void Map::HandleDelayedVisibility() +{ + if (i_objectsForDelayedVisibility.empty()) + return; + for (std::unordered_set::iterator itr = i_objectsForDelayedVisibility.begin(); itr != i_objectsForDelayedVisibility.end(); ++itr) + (*itr)->ExecuteDelayedUnitRelocationEvent(); + i_objectsForDelayedVisibility.clear(); +} + struct ResetNotifier { templateinline void resetNotify(GridRefMgr& m) @@ -890,83 +909,6 @@ struct ResetNotifier void Visit(PlayerMapType& m) { resetNotify(m);} }; -void Map::ProcessRelocationNotifies(uint32 diff) -{ - for (GridRefMgr::iterator i = GridRefMgr::begin(); i != GridRefMgr::end(); ++i) - { - NGridType* grid = i->GetSource(); - - if (grid->GetGridState() != GRID_STATE_ACTIVE) - continue; - - grid->getGridInfoRef()->getRelocationTimer().TUpdate(diff); - if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) - continue; - - uint32 gx = grid->getX(), gy = grid->getY(); - - CellCoord cell_min(gx * MAX_NUMBER_OF_CELLS, gy * MAX_NUMBER_OF_CELLS); - CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord + MAX_NUMBER_OF_CELLS); - - for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) - { - for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) - { - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - continue; - - CellCoord pair(x, y); - Cell cell(pair); - cell.SetNoCreate(); - - Acore::DelayedUnitRelocation cell_relocation(cell, pair, *this, MAX_VISIBILITY_DISTANCE); - TypeContainerVisitor grid_object_relocation(cell_relocation); - TypeContainerVisitor world_object_relocation(cell_relocation); - Visit(cell, grid_object_relocation); - Visit(cell, world_object_relocation); - } - } - } - - ResetNotifier reset; - TypeContainerVisitor grid_notifier(reset); - TypeContainerVisitor world_notifier(reset); - for (GridRefMgr::iterator i = GridRefMgr::begin(); i != GridRefMgr::end(); ++i) - { - NGridType* grid = i->GetSource(); - - if (grid->GetGridState() != GRID_STATE_ACTIVE) - continue; - - if (!grid->getGridInfoRef()->getRelocationTimer().TPassed()) - continue; - - grid->getGridInfoRef()->getRelocationTimer().TReset(diff, m_VisibilityNotifyPeriod); - - uint32 gx = grid->getX(), gy = grid->getY(); - - CellCoord cell_min(gx * MAX_NUMBER_OF_CELLS, gy * MAX_NUMBER_OF_CELLS); - CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord + MAX_NUMBER_OF_CELLS); - - for (uint32 x = cell_min.x_coord; x < cell_max.x_coord; ++x) - { - for (uint32 y = cell_min.y_coord; y < cell_max.y_coord; ++y) - { - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - continue; - - CellCoord pair(x, y); - Cell cell(pair); - cell.SetNoCreate(); - Visit(cell, grid_notifier); - Visit(cell, world_notifier); - } - } - } -} - void Map::RemovePlayerFromMap(Player* player, bool remove) { player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix @@ -1018,6 +960,8 @@ template<> void Map::RemoveFromMap(MotionTransport* obj, bool remove) { obj->RemoveFromWorld(); + if (obj->isActiveObject()) + RemoveFromActive(obj); Map::PlayerList const& players = GetPlayers(); if (!players.IsEmpty()) @@ -1056,84 +1000,67 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove) void Map::PlayerRelocation(Player* player, float x, float y, float z, float o) { - ASSERT(player); - 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()); - player->RemoveFromGrid(); if (old_cell.DiffGrid(new_cell)) - EnsureGridLoadedForActiveObject(new_cell, player); + EnsureGridLoaded(new_cell); 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, bool respawnRelocationOnFail) +void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float o) { 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)) { - #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 + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + + AddCreatureToMoveList(creature); } 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, bool respawnRelocationOnFail) +void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float o) { 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)) { - #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 + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + + AddGameObjectToMoveList(go); } 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) @@ -1141,91 +1068,66 @@ 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)) { - #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 + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + + AddDynamicObjectToMoveList(dynObj); } 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) +void Map::AddCreatureToMoveList(Creature* c) { - if (_creatureToMoveLock) //can this happen? - return; - if (c->_moveState == MAP_OBJECT_CELL_MOVE_NONE) _creaturesToMove.push_back(c); - c->SetNewCellPosition(x, y, z, ang); + c->_moveState = MAP_OBJECT_CELL_MOVE_ACTIVE; } void Map::RemoveCreatureFromMoveList(Creature* c) { - if (_creatureToMoveLock) //can this happen? - return; - if (c->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE) c->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE; } -void Map::AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang) +void Map::AddGameObjectToMoveList(GameObject* go) { - if (_gameObjectsToMoveLock) //can this happen? - return; - if (go->_moveState == MAP_OBJECT_CELL_MOVE_NONE) _gameObjectsToMove.push_back(go); - go->SetNewCellPosition(x, y, z, ang); + go->_moveState = MAP_OBJECT_CELL_MOVE_ACTIVE; } void Map::RemoveGameObjectFromMoveList(GameObject* go) { - if (_gameObjectsToMoveLock) //can this happen? - return; - if (go->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE) go->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE; } -void Map::AddDynamicObjectToMoveList(DynamicObject* dynObj, float x, float y, float z, float ang) +void Map::AddDynamicObjectToMoveList(DynamicObject* dynObj) { - if (_dynamicObjectsToMoveLock) //can this happen? - return; - if (dynObj->_moveState == MAP_OBJECT_CELL_MOVE_NONE) _dynamicObjectsToMove.push_back(dynObj); - dynObj->SetNewCellPosition(x, y, z, ang); + dynObj->_moveState = MAP_OBJECT_CELL_MOVE_ACTIVE; } void Map::RemoveDynamicObjectFromMoveList(DynamicObject* dynObj) { - if (_dynamicObjectsToMoveLock) //can this happen? - return; - if (dynObj->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE) dynObj->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE; } void Map::MoveAllCreaturesInMoveList() { - _creatureToMoveLock = true; for (std::vector::iterator itr = _creaturesToMove.begin(); itr != _creaturesToMove.end(); ++itr) { Creature* c = *itr; - if (c->FindMap() != this) //pet is teleported to another map + if (c->FindMap() != this) continue; if (c->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE) @@ -1238,51 +1140,23 @@ void Map::MoveAllCreaturesInMoveList() if (!c->IsInWorld()) continue; - // do move or do move to respawn or remove creature if previous all fail - if (CreatureCellRelocation(c, Cell(c->_newPosition.m_positionX, c->_newPosition.m_positionY))) - { - // update pos - c->Relocate(c->_newPosition); - if (c->IsVehicle()) - c->GetVehicleKit()->RelocatePassengers(); - //CreatureRelocationNotify(c, new_cell, new_cell.cellCoord()); - c->UpdatePositionData(); - c->UpdateObjectVisibility(false); - } - else - { - // if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid - // creature coordinates will be updated and notifiers send - if (!CreatureRespawnRelocation(c, false)) - { - // ... or unload (if respawn grid also not loaded) -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} cannot be move to unloaded respawn grid.", c->GetGUID().ToString().c_str()); -#endif - //AddObjectToRemoveList(Pet*) should only be called in Pet::Remove - //This may happen when a player just logs in and a pet moves to a nearby unloaded cell - //To avoid this, we can load nearby cells when player log in - //But this check is always needed to ensure safety - /// @todo pets will disappear if this is outside CreatureRespawnRelocation - //need to check why pet is frequently relocated to an unloaded cell - if (c->IsPet()) - ((Pet*)c)->Remove(PET_SAVE_NOT_IN_SLOT, true); - else - AddObjectToRemoveList(c); - } - } + Cell const& old_cell = c->GetCurrentCell(); + Cell new_cell(c->GetPositionX(), c->GetPositionY()); + + c->RemoveFromGrid(); + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + AddToGrid(c, new_cell); } _creaturesToMove.clear(); - _creatureToMoveLock = false; } void Map::MoveAllGameObjectsInMoveList() { - _gameObjectsToMoveLock = true; for (std::vector::iterator itr = _gameObjectsToMove.begin(); itr != _gameObjectsToMove.end(); ++itr) { GameObject* go = *itr; - if (go->FindMap() != this) //transport is teleported to another map + if (go->FindMap() != this) continue; if (go->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE) @@ -1295,40 +1169,23 @@ void Map::MoveAllGameObjectsInMoveList() if (!go->IsInWorld()) continue; - // do move or do move to respawn or remove creature if previous all fail - if (GameObjectCellRelocation(go, Cell(go->_newPosition.m_positionX, go->_newPosition.m_positionY))) - { - // update pos - go->Relocate(go->_newPosition); - go->UpdateModelPosition(); - go->UpdatePositionData(); - go->UpdateObjectVisibility(false); - } - else - { - // if GameObject can't be move in new cell/grid (not loaded) move it to repawn cell/grid - // GameObject coordinates will be updated and notifiers send - if (!GameObjectRespawnRelocation(go, false)) - { - // ... or unload (if respawn grid also not loaded) -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} cannot be move to unloaded respawn grid.", go->GetGUID().ToString().c_str()); -#endif - AddObjectToRemoveList(go); - } - } + Cell const& old_cell = go->GetCurrentCell(); + Cell new_cell(go->GetPositionX(), go->GetPositionY()); + + go->RemoveFromGrid(); + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + AddToGrid(go, new_cell); } _gameObjectsToMove.clear(); - _gameObjectsToMoveLock = false; } void Map::MoveAllDynamicObjectsInMoveList() { - _dynamicObjectsToMoveLock = true; for (std::vector::iterator itr = _dynamicObjectsToMove.begin(); itr != _dynamicObjectsToMove.end(); ++itr) { DynamicObject* dynObj = *itr; - if (dynObj->FindMap() != this) //transport is teleported to another map + if (dynObj->FindMap() != this) continue; if (dynObj->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE) @@ -1341,344 +1198,60 @@ void Map::MoveAllDynamicObjectsInMoveList() if (!dynObj->IsInWorld()) continue; - // do move or do move to respawn or remove creature if previous all fail - if (DynamicObjectCellRelocation(dynObj, Cell(dynObj->_newPosition.m_positionX, dynObj->_newPosition.m_positionY))) - { - // update pos - dynObj->Relocate(dynObj->_newPosition); - dynObj->UpdatePositionData(); - dynObj->UpdateObjectVisibility(false); - } - else - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "DynamicObject {} cannot be moved to unloaded grid.", dynObj->GetGUID().ToString().c_str()); -#endif - } - } + Cell const& old_cell = dynObj->GetCurrentCell(); + Cell new_cell(dynObj->GetPositionX(), dynObj->GetPositionY()); + dynObj->RemoveFromGrid(); + if (old_cell.DiffGrid(new_cell)) + EnsureGridLoaded(new_cell); + AddToGrid(dynObj, new_cell); + } _dynamicObjectsToMove.clear(); - _dynamicObjectsToMoveLock = false; } -bool Map::CreatureCellRelocation(Creature* c, Cell new_cell) +bool Map::UnloadGrid(NGridType& ngrid) { - Cell const& old_cell = c->GetCurrentCell(); - if (!old_cell.DiffGrid(new_cell)) // in same grid - { - // if in same cell then none do - if (old_cell.DiffCell(new_cell)) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", c->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); -#endif + // pussywizard: UnloadGrid only done when whole map is unloaded, no need to worry about moving npcs between grids, etc. - c->RemoveFromGrid(); - AddToGrid(c, new_cell); - } - else - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} moved in same grid[{}, {}]cell[{}, {}].", c->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); -#endif - } - - return true; - } - - // in diff. grids but active creature - if (c->isActiveObject()) - { - EnsureGridLoadedForActiveObject(new_cell, c); - -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Active creature {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", c->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 - - c->RemoveFromGrid(); - AddToGrid(c, new_cell); - - return true; - } - - if (c->GetCharmerOrOwnerGUID().IsPlayer()) - EnsureGridLoaded(new_cell); - - // in diff. loaded grid normal creature - if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY()))) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} moved from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", c->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 - - c->RemoveFromGrid(); - EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY())); - AddToGrid(c, new_cell); - - return true; - } - - // fail to move: normal creature attempt move to unloaded grid -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded grid[{}, {}]cell[{}, {}].", c->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 - return false; -} - -bool Map::GameObjectCellRelocation(GameObject* go, Cell new_cell) -{ - Cell const& old_cell = go->GetCurrentCell(); - if (!old_cell.DiffGrid(new_cell)) // in same grid - { - // if in same cell then none do - if (old_cell.DiffCell(new_cell)) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); -#endif - - go->RemoveFromGrid(); - AddToGrid(go, new_cell); - } - else - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} moved in same grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); -#endif - } - - return true; - } - - // in diff. grids but active GameObject - if (go->isActiveObject()) - { - EnsureGridLoadedForActiveObject(new_cell, go); - -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Active GameObject {} moved 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 - - go->RemoveFromGrid(); - AddToGrid(go, new_cell); - - return true; - } - - // in diff. loaded grid normal GameObject - if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY()))) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} moved 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 - - go->RemoveFromGrid(); - EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY())); - AddToGrid(go, new_cell); - - return true; - } - - // fail to move: normal GameObject attempt move to unloaded grid -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded 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 - return false; -} - -bool Map::DynamicObjectCellRelocation(DynamicObject* go, Cell new_cell) -{ - Cell const& old_cell = go->GetCurrentCell(); - if (!old_cell.DiffGrid(new_cell)) // in same grid - { - // if in same cell then none do - if (old_cell.DiffCell(new_cell)) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "DynamicObject {} moved in grid[{}, {}] from cell[{}, {}] to cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); -#endif - - go->RemoveFromGrid(); - AddToGrid(go, new_cell); - } - else - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "DynamicObject {} moved in same grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY()); -#endif - } - - return true; - } - - // in diff. grids but active GameObject - if (go->isActiveObject()) - { - EnsureGridLoadedForActiveObject(new_cell, go); - -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Active DynamicObject {} moved 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 - - go->RemoveFromGrid(); - AddToGrid(go, new_cell); - - return true; - } - - // in diff. loaded grid normal GameObject - if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY()))) - { -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "DynamicObject {} moved 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 - - go->RemoveFromGrid(); - EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY())); - AddToGrid(go, new_cell); - - return true; - } - - // fail to move: normal GameObject attempt move to unloaded grid -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "DynamicObject {} attempted to move from grid[{}, {}]cell[{}, {}] to unloaded 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 - return false; -} - -bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly) -{ - float resp_x, resp_y, resp_z, resp_o; - c->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o); - Cell resp_cell(resp_x, resp_y); - - //creature will be unloaded with grid - if (diffGridOnly && !c->GetCurrentCell().DiffGrid(resp_cell)) - return true; - - c->CombatStop(); - c->GetMotionMaster()->Clear(); - -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "Creature {} moved from grid[{}, {}]cell[{}, {}] to respawn grid[{}, {}]cell[{}, {}].", c->GetGUID().ToString().c_str(), c->GetCurrentCell().GridX(), c->GetCurrentCell().GridY(), c->GetCurrentCell().CellX(), c->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY()); -#endif - - // teleport it to respawn point (like normal respawn if player see) - if (CreatureCellRelocation(c, resp_cell)) - { - c->Relocate(resp_x, resp_y, resp_z, resp_o); - c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators - //CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord()); - c->UpdatePositionData(); - c->UpdateObjectVisibility(false); - return true; - } - - return false; -} - -bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly) -{ - float resp_x, resp_y, resp_z, resp_o; - go->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o); - Cell resp_cell(resp_x, resp_y); - - //GameObject will be unloaded with grid - if (diffGridOnly && !go->GetCurrentCell().DiffGrid(resp_cell)) - return true; - -#ifdef ACORE_DEBUG - LOG_DEBUG("maps", "GameObject {} moved from grid[{}, {}]cell[{}, {}] to respawn grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString().c_str(), go->GetCurrentCell().GridX(), go->GetCurrentCell().GridY(), go->GetCurrentCell().CellX(), go->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY()); -#endif - - // teleport it to respawn point (like normal respawn if player see) - if (GameObjectCellRelocation(go, resp_cell)) - { - go->Relocate(resp_x, resp_y, resp_z, resp_o); - go->UpdatePositionData(); - go->UpdateObjectVisibility(false); - return true; - } - - return false; -} - -bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll) -{ const uint32 x = ngrid.getX(); const uint32 y = ngrid.getY(); { - if (!unloadAll) - { - //pets, possessed creatures (must be active), transport passengers - if (ngrid.GetWorldObjectCountInNGrid()) - return false; - - if (ActiveObjectsNearGrid(ngrid)) - return false; - } - - LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {}", x, y, GetId()); - - if (!unloadAll) - { - // Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids - // Must know real mob position before move - MoveAllCreaturesInMoveList(); - MoveAllGameObjectsInMoveList(); - - // move creatures to respawn grids if this is diff.grid or to remove list - ObjectGridEvacuator worker; - TypeContainerVisitor visitor(worker); - ngrid.VisitAllGrids(visitor); - - // Finish creature moves, remove and delete all creatures with delayed remove before unload - MoveAllCreaturesInMoveList(); - MoveAllGameObjectsInMoveList(); - } - - { - ObjectGridCleaner worker; - TypeContainerVisitor visitor(worker); - ngrid.VisitAllGrids(visitor); - } - - RemoveAllObjectsInRemoveList(); - - { - ObjectGridUnloader worker; - TypeContainerVisitor visitor(worker); - ngrid.VisitAllGrids(visitor); - } - - ASSERT(i_objectsToRemove.empty()); - - delete& ngrid; - setNGrid(nullptr, x, y); + ObjectGridCleaner worker; + TypeContainerVisitor visitor(worker); + ngrid.VisitAllGrids(visitor); } + + RemoveAllObjectsInRemoveList(); + + { + ObjectGridUnloader worker; + TypeContainerVisitor visitor(worker); + ngrid.VisitAllGrids(visitor); + } + + ASSERT(i_objectsToRemove.empty()); + + delete &ngrid; + setNGrid(nullptr, x, y); + int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; - // delete grid map, but don't delete if it is from parent map (and thus only reference) - //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps + if (i_InstanceId == 0) { - if (i_InstanceId == 0) + if (GridMaps[gx][gy]) { - if (GridMaps[gx][gy]) - { - GridMaps[gx][gy]->unloadData(); - delete GridMaps[gx][gy]; - } - VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(GetId(), gx, gy); - MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(GetId(), gx, gy); + GridMaps[gx][gy]->unloadData(); + delete GridMaps[gx][gy]; } - else - ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy)); - - GridMaps[gx][gy] = nullptr; + // x and y are swapped + VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(GetId(), gx, gy); + MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(GetId(), gx, gy); } + + GridMaps[gx][gy] = nullptr; + LOG_DEBUG("maps", "Unloading grid[{}, {}] for map {} finished", x, y, GetId()); return true; } @@ -1710,7 +1283,7 @@ void Map::UnloadAll() { NGridType& grid(*i->GetSource()); ++i; - UnloadGrid(grid, true); // deletes the grid and removes it from the GridRefMgr + UnloadGrid(grid); // deletes the grid and removes it from the GridRefMgr } // pussywizard: crashfix, some npc can be left on transport (not a default passenger) @@ -2405,11 +1978,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)(CENTER_GRID_ID - x / SIZE_OF_GRIDS); //grid x - int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); //grid y + int gx = (int)(32 - x / SIZE_OF_GRIDS); //grid x + int gy = (int)(32 - y / SIZE_OF_GRIDS); //grid y // ensure GridMap is loaded - EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy)); + EnsureGridCreated(GridCoord(63 - gx, 63 - gy)); return GridMaps[gx][gy]; } @@ -3066,20 +2639,6 @@ void Map::DelayedUpdate(const uint32 t_diff) } RemoveAllObjectsInRemoveList(); - - // Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load ! - // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended - if (!IsBattlegroundOrArena()) - { - for (GridRefMgr::iterator i = GridRefMgr::begin(); i != GridRefMgr::end();) - { - NGridType* grid = i->GetSource(); - GridInfo* info = i->GetSource()->getGridInfoRef(); - ++i; // The update might delete the map and we need the next map before the iterator gets invalid - ASSERT(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE); - si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, t_diff); - } - } } void Map::AddObjectToRemoveList(WorldObject* obj) @@ -3137,8 +2696,9 @@ void Map::RemoveAllObjectsInRemoveList() //LOG_DEBUG("maps", "Object remover 1 check."); while (!i_objectsToRemove.empty()) { - std::set::iterator itr = i_objectsToRemove.begin(); + std::unordered_set::iterator itr = i_objectsToRemove.begin(); WorldObject* obj = *itr; + i_objectsToRemove.erase(itr); switch (obj->GetTypeId()) { @@ -3155,14 +2715,11 @@ void Map::RemoveAllObjectsInRemoveList() RemoveFromMap((DynamicObject*)obj, true); break; case TYPEID_GAMEOBJECT: - { - GameObject* go = obj->ToGameObject(); - if (MotionTransport* transport = go->ToMotionTransport()) + if (MotionTransport* transport = obj->ToGameObject()->ToMotionTransport()) RemoveFromMap(transport, true); else - RemoveFromMap(go, true); + RemoveFromMap(obj->ToGameObject(), 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 @@ -3173,8 +2730,6 @@ void Map::RemoveAllObjectsInRemoveList() LOG_ERROR("maps", "Non-grid object (TypeId: {}) is in grid object remove list, ignored.", obj->GetTypeId()); break; } - - i_objectsToRemove.erase(itr); } //LOG_DEBUG("maps", "Object remover 2 check."); @@ -3195,43 +2750,6 @@ void Map::SendToPlayers(WorldPacket const* data) const itr->GetSource()->GetSession()->SendPacket(data); } -bool Map::ActiveObjectsNearGrid(NGridType const& ngrid) const -{ - CellCoord cell_min(ngrid.getX() * MAX_NUMBER_OF_CELLS, ngrid.getY() * MAX_NUMBER_OF_CELLS); - CellCoord cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord + MAX_NUMBER_OF_CELLS); - - //we must find visible range in cells so we unload only non-visible cells... - float viewDist = GetVisibilityRange(); - int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1; - - cell_min.dec_x(cell_range); - cell_min.dec_y(cell_range); - cell_max.inc_x(cell_range); - cell_max.inc_y(cell_range); - - for (MapRefMgr::const_iterator iter = m_mapRefMgr.begin(); iter != m_mapRefMgr.end(); ++iter) - { - Player* player = iter->GetSource(); - - CellCoord p = Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()); - if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && - (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) - return true; - } - - for (ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter) - { - WorldObject* obj = *iter; - - CellCoord p = Acore::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY()); - if ((cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && - (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord)) - return true; - } - - return false; -} - template void Map::AddToActive(T* obj) { @@ -3242,22 +2760,6 @@ template <> void Map::AddToActive(Creature* c) { AddToActiveHelper(c); - - // also not allow unloading spawn grid to prevent creating creature clone at load - if (!c->IsPet() && c->GetSpawnId()) - { - float x, y, z; - c->GetRespawnPosition(x, y, z); - GridCoord p = Acore::ComputeGridCoord(x, y); - if (getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); - else - { - GridCoord p2 = Acore::ComputeGridCoord(c->GetPositionX(), c->GetPositionY()); - LOG_ERROR("maps", "Active creature {} added to grid[{}, {}] but spawn grid[{}, {}] was not loaded.", - c->GetGUID().ToString().c_str(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); - } - } } template<> @@ -3266,6 +2768,12 @@ void Map::AddToActive(DynamicObject* d) AddToActiveHelper(d); } +template<> +void Map::AddToActive(GameObject* d) +{ + AddToActiveHelper(d); +} + template void Map::RemoveFromActive(T* obj) { @@ -3276,22 +2784,6 @@ template <> void Map::RemoveFromActive(Creature* c) { RemoveFromActiveHelper(c); - - // also allow unloading spawn grid - if (!c->IsPet() && c->GetSpawnId()) - { - float x, y, z; - c->GetRespawnPosition(x, y, z); - GridCoord p = Acore::ComputeGridCoord(x, y); - if (getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); - else - { - GridCoord p2 = Acore::ComputeGridCoord(c->GetPositionX(), c->GetPositionY()); - LOG_ERROR("maps", "Active creature {} removed from grid[{}, {}] but spawn grid[{}, {}] was not loaded.", - c->GetGUID().ToString().c_str(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); - } - } } template<> @@ -3300,6 +2792,12 @@ 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); @@ -3312,8 +2810,8 @@ template void Map::RemoveFromMap(DynamicObject*, bool); /* ******* Dungeon Instance Maps ******* */ -InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) - : Map(id, expiry, InstanceId, SpawnMode, _parent), +InstanceMap::InstanceMap(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : Map(id, InstanceId, SpawnMode, _parent), m_resetAfterUnload(false), m_unloadWhenEmpty(false), instance_data(nullptr), i_script_id(0) { @@ -3342,7 +2840,6 @@ void InstanceMap::InitVisibilityDistance() { //init visibility distance for instances m_VisibleDistance = World::GetMaxVisibleDistanceInInstances(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInInstances(); // pussywizard: this CAN NOT exceed MAX_VISIBILITY_DISTANCE switch (GetId()) @@ -3722,8 +3219,8 @@ uint32 InstanceMap::GetMaxResetDelay() const /* ******* Battleground Instance Maps ******* */ -BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) - : Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr) +BattlegroundMap::BattlegroundMap(uint32 id, uint32 InstanceId, Map* _parent, uint8 spawnMode) + : Map(id, InstanceId, spawnMode, _parent), m_bg(nullptr) { //lets initialize visibility distance for BG/Arenas BattlegroundMap::InitVisibilityDistance(); @@ -3743,7 +3240,6 @@ void BattlegroundMap::InitVisibilityDistance() { //init visibility distance for BG/Arenas m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); - m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); if (IsBattleArena()) // pussywizard: start with 30yd visibility range on arenas to ensure players can't get informations about the opponents in any way m_VisibleDistance = 30.0f; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index c3b64f01a..0bf6b9c18 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -71,6 +71,7 @@ namespace VMAP namespace Acore { struct ObjectUpdater; + struct LargeObjectUpdater; } struct ScriptAction @@ -311,7 +312,7 @@ class Map : public GridRefMgr { friend class MapReference; public: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr); + Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr); ~Map() override; [[nodiscard]] MapEntry const* GetEntry() const { return i_mapEntry; } @@ -336,7 +337,13 @@ public: template void RemoveFromMap(T*, bool); void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor& gridVisitor, - TypeContainerVisitor& worldVisitor); + TypeContainerVisitor& worldVisitor, + TypeContainerVisitor& largeGridVisitor, + TypeContainerVisitor& largeWorldVisitor); + void VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor& gridVisitor, + TypeContainerVisitor& worldVisitor, + TypeContainerVisitor& largeGridVisitor, + TypeContainerVisitor& largeWorldVisitor); virtual void Update(const uint32, const uint32, bool thread = true); @@ -346,22 +353,16 @@ 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, bool respawnRelocationOnFail = true); - void GameObjectRelocation(GameObject* go, float x, float y, float z, float o, bool respawnRelocationOnFail = true); + 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 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); - return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL; + return !getNGrid(p.x_coord, p.y_coord); } [[nodiscard]] bool IsGridLoaded(float x, float y) const @@ -369,26 +370,13 @@ public: return IsGridLoaded(Acore::ComputeGridCoord(x, y)); } - bool GetUnloadLock(GridCoord const& p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } - void SetUnloadLock(GridCoord const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void LoadGrid(float x, float y); void LoadAllCells(); - bool UnloadGrid(NGridType& ngrid, bool pForce); - void GridMarkNoUnload(uint32 x, uint32 y); - void GridUnmarkNoUnload(uint32 x, uint32 y); + bool UnloadGrid(NGridType& ngrid); virtual void UnloadAll(); - void ResetGridExpiry(NGridType& grid, float factor = 1) const - { - grid.ResetTimeTracker(time_t(float(i_gridExpiry) * factor)); - } - - [[nodiscard]] time_t GetGridExpiry(void) const { return i_gridExpiry; } [[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; } - static void InitStateMachine(); - static void DeleteStateMachine(); - static bool ExistMap(uint32 mapid, int gx, int gy); static bool ExistVMap(uint32 mapid, int gx, int gy); @@ -427,10 +415,6 @@ public: void RemoveAllObjectsInRemoveList(); virtual void RemoveAllPlayers(); - // used only in MoveAllCreaturesInMoveList and ObjectGridUnloader - bool CreatureRespawnRelocation(Creature* c, bool diffGridOnly); - bool GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly); - [[nodiscard]] uint32 GetInstanceId() const { return i_InstanceId; } [[nodiscard]] uint8 GetSpawnMode() const { return (i_spawnMode); } @@ -484,10 +468,12 @@ public: void resetMarkedCells() { marked_cells.reset(); } bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } void markCell(uint32 pCellId) { marked_cells.set(pCellId); } + void resetMarkedCellsLarge() { marked_cells_large.reset(); } + bool isCellMarkedLarge(uint32 pCellId) { return marked_cells_large.test(pCellId); } + void markCellLarge(uint32 pCellId) { marked_cells_large.set(pCellId); } [[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); } [[nodiscard]] uint32 GetPlayersCountExceptGMs() const; - [[nodiscard]] bool ActiveObjectsNearGrid(NGridType const& ngrid) const; void AddWorldObject(WorldObject* obj) { i_worldObjects.insert(obj); } void RemoveWorldObject(WorldObject* obj) { i_worldObjects.erase(obj); } @@ -674,30 +660,20 @@ private: // Load MMap Data void LoadMMap(int gx, int gy); - bool CreatureCellRelocation(Creature* creature, Cell new_cell); - bool GameObjectCellRelocation(GameObject* go, Cell new_cell); - bool DynamicObjectCellRelocation(DynamicObject* go, Cell new_cell); - template void InitializeObject(T* obj); - void AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang); + void AddCreatureToMoveList(Creature* c); void RemoveCreatureFromMoveList(Creature* c); - void AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang); + void AddGameObjectToMoveList(GameObject* go); void RemoveGameObjectFromMoveList(GameObject* go); - void AddDynamicObjectToMoveList(DynamicObject* go, float x, float y, float z, float ang); + void AddDynamicObjectToMoveList(DynamicObject* go); void RemoveDynamicObjectFromMoveList(DynamicObject* go); - bool _creatureToMoveLock; std::vector _creaturesToMove; - - bool _gameObjectsToMoveLock; std::vector _gameObjectsToMove; - - bool _dynamicObjectsToMoveLock; std::vector _dynamicObjectsToMove; [[nodiscard]] bool IsGridLoaded(const GridCoord&) const; void EnsureGridCreated_i(const GridCoord&); - void EnsureGridLoadedForActiveObject(Cell const&, WorldObject* object); void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } @@ -708,6 +684,9 @@ 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(); @@ -716,8 +695,6 @@ private: void SendObjectUpdates(); protected: - void SetUnloadReferenceLock(GridCoord const& p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } - std::mutex Lock; std::mutex GridLock; std::shared_mutex MMapLock; @@ -733,8 +710,6 @@ protected: MapRefMgr m_mapRefMgr; MapRefMgr::iterator m_mapRefIter; - int32 m_VisibilityNotifyPeriod; - typedef std::set ActiveNonPlayers; ActiveNonPlayers m_activeNonPlayers; ActiveNonPlayers::iterator m_activeNonPlayersIter; @@ -753,8 +728,6 @@ private: void _ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const; GameObject* _FindGameObject(WorldObject* pWorldObject, ObjectGuid::LowType guid) const; - time_t i_gridExpiry; - //used for fast base_map (e.g. MapInstanced class object) search for //InstanceMaps and BattlegroundMaps... Map* m_parentMap; @@ -762,15 +735,12 @@ private: NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; std::bitset marked_cells; - - //these functions used to process player/mob aggro reactions and - //visibility calculations. Highly optimized for massive calculations - void ProcessRelocationNotifies(uint32 diff); + std::bitset marked_cells_large; bool i_scriptLock; - std::set i_objectsToRemove; + std::unordered_set i_objectsToRemove; std::map i_objectsToSwitch; - std::set i_worldObjects; + std::unordered_set i_worldObjects; typedef std::multimap ScriptScheduleMap; ScriptScheduleMap m_scriptSchedule; @@ -842,7 +812,7 @@ enum InstanceResetMethod class InstanceMap : public Map { public: - InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); + InstanceMap(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent); ~InstanceMap() override; bool AddPlayerToMap(Player*) override; void RemovePlayerFromMap(Player*, bool) override; @@ -876,7 +846,7 @@ private: class BattlegroundMap : public Map { public: - BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); + BattlegroundMap(uint32 id, uint32 InstanceId, Map* _parent, uint8 spawnMode); ~BattlegroundMap() override; bool AddPlayerToMap(Player*) override; @@ -901,12 +871,11 @@ inline void Map::Visit(Cell const& cell, TypeContainerVisitor& vis const uint32 cell_x = cell.CellX(); const uint32 cell_y = cell.CellY(); - if (!cell.NoCreate()) + if (!cell.NoCreate() || IsGridLoaded(GridCoord(x, y))) + { EnsureGridLoaded(cell); - - NGridType* grid = getNGrid(x, y); - if (grid && grid->isGridObjectDataLoaded()) - grid->VisitGrid(cell_x, cell_y, visitor); + getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor); + } } #endif diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 36b593010..12c6acf6b 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -25,12 +25,11 @@ #include "Player.h" #include "ScriptMgr.h" #include "VMapFactory.h" -#include "VMapMgr2.h" -MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) +MapInstanced::MapInstanced(uint32 id) : Map(id, 0, DUNGEON_DIFFICULTY_NORMAL) { - // fill with zero - memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS * sizeof(uint16)); + // initialize instanced maps list + m_InstancedMaps.clear(); } void MapInstanced::InitVisibilityDistance() @@ -204,7 +203,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, LOG_DEBUG("maps", "MapInstanced::CreateInstance: {} map instance {} for {} created with difficulty {}", save ? "" : "new ", InstanceId, GetId(), difficulty ? "heroic" : "normal"); - InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); + InstanceMap* map = new InstanceMap(GetId(), InstanceId, difficulty, this); ASSERT(map->IsDungeon()); map->LoadRespawnTimes(); @@ -238,7 +237,7 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun else spawnMode = REGULAR_DIFFICULTY; - BattlegroundMap* map = new BattlegroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode); + BattlegroundMap* map = new BattlegroundMap(GetId(), InstanceId, this, spawnMode); ASSERT(map->IsBattlegroundOrArena()); map->SetBG(bg); bg->SetBgMap(map); @@ -261,15 +260,6 @@ 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 e2deef157..f08c5687a 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, time_t expiry); + MapInstanced(uint32 id); ~MapInstanced() override {} // functions overwrite Map versions @@ -46,19 +46,6 @@ public: } bool DestroyInstance(InstancedMaps::iterator& itr); - void AddGridMapReference(GridCoord const& p) - { - ++GridMapReference[p.x_coord][p.y_coord]; - SetUnloadReferenceLock(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - p.x_coord, (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord), true); - } - - void RemoveGridMapReference(GridCoord const& p) - { - --GridMapReference[p.x_coord][p.y_coord]; - if (!GridMapReference[p.x_coord][p.y_coord]) - SetUnloadReferenceLock(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - p.x_coord, (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord), false); - } - InstancedMaps& GetInstancedMaps() { return m_InstancedMaps; } void InitVisibilityDistance() override; @@ -67,7 +54,5 @@ private: BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg); InstancedMaps m_InstancedMaps; - - uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; }; #endif diff --git a/src/server/game/Maps/MapMgr.cpp b/src/server/game/Maps/MapMgr.cpp index 96368486a..9e89d64e2 100644 --- a/src/server/game/Maps/MapMgr.cpp +++ b/src/server/game/Maps/MapMgr.cpp @@ -36,7 +36,6 @@ MapMgr::MapMgr() { - i_gridCleanUpDelay = sWorld->getIntConfig(CONFIG_INTERVAL_GRIDCLEAN); i_timer[3].SetInterval(sWorld->getIntConfig(CONFIG_INTERVAL_MAPUPDATE)); mapUpdateStep = 0; _nextInstanceId = 0; @@ -54,8 +53,6 @@ MapMgr* MapMgr::instance() void MapMgr::Initialize() { - Map::InitStateMachine(); - int num_threads(sWorld->getIntConfig(CONFIG_NUMTHREADS)); // Start mtmaps if needed @@ -84,10 +81,10 @@ Map* MapMgr::CreateBaseMap(uint32 id) ASSERT(entry); if (entry->Instanceable()) - map = new MapInstanced(id, i_gridCleanUpDelay); + map = new MapInstanced(id); else { - map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); + map = new Map(id, 0, REGULAR_DIFFICULTY); map->LoadRespawnTimes(); map->LoadCorpseData(); } @@ -303,8 +300,8 @@ bool MapMgr::ExistMapAndVMap(uint32 mapid, float x, float y) { GridCoord p = Acore::ComputeGridCoord(x, y); - int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; - int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; + int gx = 63 - p.x_coord; + int gy = 63 - p.y_coord; return Map::ExistMap(mapid, gx, gy) && Map::ExistVMap(mapid, gx, gy); } @@ -336,8 +333,6 @@ void MapMgr::UnloadAll() if (m_updater.activated()) m_updater.deactivate(); - - Map::DeleteStateMachine(); } void MapMgr::GetNumInstances(uint32& dungeons, uint32& battlegrounds, uint32& arenas) diff --git a/src/server/game/Maps/MapMgr.h b/src/server/game/Maps/MapMgr.h index f8f86e78e..828fe548e 100644 --- a/src/server/game/Maps/MapMgr.h +++ b/src/server/game/Maps/MapMgr.h @@ -24,7 +24,6 @@ #include "MapInstanced.h" #include "MapUpdater.h" #include "Object.h" -#include "GridStates.h" #include @@ -74,14 +73,6 @@ public: void Initialize(void); void Update(uint32); - void SetGridCleanUpDelay(uint32 t) - { - if (t < MIN_GRID_DELAY) - i_gridCleanUpDelay = MIN_GRID_DELAY; - else - i_gridCleanUpDelay = t; - } - void SetMapUpdateInterval(uint32 t) { if (t < MIN_MAP_UPDATE_DELAY) @@ -179,7 +170,6 @@ private: MapMgr& operator=(const MapMgr&); std::mutex Lock; - uint32 i_gridCleanUpDelay; MapMapType i_maps; IntervalTimer i_timer[4]; // continents, bgs/arenas, instances, total from the beginning uint8 mapUpdateStep; diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 5d7a65f64..e6ad171d3 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -411,6 +411,8 @@ 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/Grids/NGrid.cpp b/src/server/game/Misc/DynamicVisibility.cpp similarity index 59% rename from src/server/game/Grids/NGrid.cpp rename to src/server/game/Misc/DynamicVisibility.cpp index 337d7dded..60889c4bc 100644 --- a/src/server/game/Grids/NGrid.cpp +++ b/src/server/game/Misc/DynamicVisibility.cpp @@ -15,15 +15,14 @@ * with this program. If not, see . */ -#include "NGrid.h" -#include "Random.h" +#include "DynamicVisibility.h" -GridInfo::GridInfo() : i_timer(0), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)), -i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(false) -{ -} +uint8 DynamicVisibilityMgr::visibilitySettingsIndex = 0; -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) +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 new file mode 100644 index 000000000..cf38bfa50 --- /dev/null +++ b/src/server/game/Misc/DynamicVisibility.h @@ -0,0 +1,58 @@ +/* + * 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 0d230ee1a..3d3be3769 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -125,13 +125,14 @@ namespace Movement if (args.flags.cyclic) { uint32 cyclic_point = 0; - 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); + // 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); } else { - spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation); + spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]); } // init spline timestamps @@ -203,7 +204,7 @@ namespace Movement if (!(exp)) \ { \ if (unit) \ - LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for GUID: {} Entry: {}", #exp, unit->GetGUID().ToString().c_str(), unit->GetEntry());\ + LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for {}", #exp, unit->GetGUID().ToString()); \ else \ LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for cyclic spline continuation", #exp); \ return false;\ @@ -272,41 +273,6 @@ 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 0696a2449..faf6cd203 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -87,7 +87,6 @@ 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 d9e31d5e7..b360c6b3d 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -67,6 +67,10 @@ 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) @@ -119,11 +123,20 @@ namespace Movement data.append(&spline.getPoint(2), count); } - void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data) + void WriteCatmullRomCyclicPath(const Spline& spline, ByteBuffer& data, bool flying) { - uint32 count = spline.getPointCount() - 4; - data << count; - data.append(&spline.getPoint(2), count); + 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 + } } void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, ByteBuffer& data) @@ -135,7 +148,7 @@ namespace Movement if (splineflags & MoveSplineFlag::Mask_CatmullRom) { if (splineflags.cyclic) - WriteCatmullRomCyclicPath(spline, data); + WriteCatmullRomCyclicPath(spline, data, splineflags & MoveSplineFlag::Flying); else WriteCatmullRomPath(spline, data); } @@ -186,8 +199,4 @@ 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 2c577a492..711eccc33 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.h +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -38,7 +38,6 @@ 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 31bf6a6cb..601951a20 100644 --- a/src/server/game/Movement/Spline/Spline.cpp +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -199,25 +199,23 @@ namespace Movement return length; } - void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation) + void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m) { m_mode = m; cyclic = false; - initialOrientation = orientation; - (this->*initializers[m_mode])(controls, count, 0); + (this->*initializers[m_mode])(controls, count, cyclic, 0); } - void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation) + void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { m_mode = m; cyclic = true; - initialOrientation = orientation; - (this->*initializers[m_mode])(controls, count, cyclic_point); + (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point); } - void SplineBase::InitLinear(const Vector3* controls, index_type count, index_type cyclic_point) + void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) { ASSERT(count >= 2); const int real_size = count + 1; @@ -237,7 +235,7 @@ namespace Movement index_hi = cyclic ? count : (count - 1); } - void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, index_type cyclic_point) + void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point) { const int real_size = count + (cyclic ? (1 + 2) : (1 + 1)); @@ -255,14 +253,14 @@ namespace Movement if (cyclic_point == 0) points[0] = controls[count - 1]; else - points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; + points[0] = controls[0].lerp(controls[1], -1); points[high_index + 1] = controls[cyclic_point]; points[high_index + 2] = controls[cyclic_point + 1]; } else { - points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f }; + points[0] = controls[0].lerp(controls[1], -1); points[high_index + 1] = controls[count - 1]; } @@ -270,7 +268,7 @@ namespace Movement index_hi = high_index + (cyclic ? 1 : 0); } - void SplineBase::InitBezier3(const Vector3* controls, index_type count, index_type /*cyclic_point*/) + void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, 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 38dcd9293..d9d255f0a 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -48,7 +48,6 @@ namespace Movement uint8 m_mode{UninitializedMode}; bool cyclic{false}; - float initialOrientation{0.f}; enum { @@ -78,15 +77,15 @@ namespace Movement typedef float (SplineBase::*SegLenghtMethtod)(index_type) const; static SegLenghtMethtod seglengths[ModesEnd]; - 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); + 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); static InitMethtod initializers[ModesEnd]; void UninitializedSplineEvaluationMethod(index_type, float, Vector3&) const { ABORT(); } - [[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); return 0.0f; } - void UninitializedSplineInitMethod(Vector3 const*, index_type, index_type) { ABORT(); } + [[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); } + void UninitializedSplineInitMethod(Vector3 const*, index_type, bool, index_type) { ABORT(); } public: explicit SplineBase() = default; @@ -117,8 +116,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, float orientation); - void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation); + 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); /** As i can see there are a lot of ways how spline can be initialized would be no harm to have some custom initializers. */ @@ -171,8 +170,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, 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);} + 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);} /** Initializes lengths with SplineBase::SegLength method. */ void initLengths(); @@ -198,12 +197,7 @@ namespace Movement } /** Returns length of the whole spline. */ - [[nodiscard]] length_type length() const - { - if (lengths.empty()) - return 0; - return lengths[index_hi]; - } + [[nodiscard]] length_type length() const { 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/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index e321faa48..9fdbae85b 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1602,8 +1602,8 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } - if (target->IsInWorld()) - target->UpdateObjectVisibility(); + target->UpdateObjectVisibility(target->GetTypeId() == TYPEID_PLAYER || target->GetOwnerGUID().IsPlayer() || target->GetMap()->Instanceable(), true); + target->bRequestForcedVisibilityUpdate = false; } void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -1676,8 +1676,8 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } - if (target->IsInWorld()) - target->UpdateObjectVisibility(); + target->UpdateObjectVisibility(target->GetTypeId() == TYPEID_PLAYER || target->GetOwnerGUID().IsPlayer() || target->GetMap()->Instanceable(), true); + target->bRequestForcedVisibilityUpdate = false; } void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -1841,6 +1841,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app if (!target->GetMap()->Instanceable()) { target->UpdateObjectVisibility(false); + target->m_last_notify_position.Relocate(-5000.0f, -5000.0f, -5000.0f); } else target->UpdateObjectVisibility(); @@ -2821,7 +2822,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo */ UnitList targets; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange()); + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough 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 e26e296fc..8583f057c 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()); + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, unitTarget->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough 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(); + float dist = m_caster->GetVisibilityRange() + VISIBILITY_COMPENSATION; 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()); + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, m_caster->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough 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/IWorld.h b/src/server/game/World/IWorld.h index 394875058..2b2b103cf 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -72,7 +72,6 @@ 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, @@ -209,7 +208,6 @@ enum WorldFloatConfigs enum WorldIntConfigs { CONFIG_COMPRESSION = 0, - CONFIG_INTERVAL_GRIDCLEAN, CONFIG_INTERVAL_MAPUPDATE, CONFIG_INTERVAL_CHANGEWEATHER, CONFIG_INTERVAL_DISCONNECT_TOLERANCE, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 79f56d46a..45522266c 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -44,6 +44,7 @@ #include "DBCStores.h" #include "DatabaseEnv.h" #include "DisableMgr.h" +#include "DynamicVisibility.h" #include "GameEventMgr.h" #include "GameGraveyard.h" #include "GameTime.h" @@ -108,10 +109,6 @@ float World::_maxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; float World::_maxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE; float World::_maxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS; -int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD; -int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD; -int32 World::m_visibility_notify_periodInBGArenas = DEFAULT_VISIBILITY_NOTIFY_PERIOD; - Realm realm; /// World constructor @@ -657,14 +654,6 @@ void World::LoadConfigSettings(bool reload) LOG_ERROR("server.loading", "PlayerSave.Stats.MinLevel ({}) must be in range 0..80. Using default, do not save character stats (0).", _int_configs[CONFIG_MIN_LEVEL_STAT_SAVE]); _int_configs[CONFIG_MIN_LEVEL_STAT_SAVE] = 0; } - _int_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfigMgr->GetOption("GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS); - if (_int_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY) - { - LOG_ERROR("server.loading", "GridCleanUpDelay ({}) must be greater {}. Use this minimal value.", _int_configs[CONFIG_INTERVAL_GRIDCLEAN], MIN_GRID_DELAY); - _int_configs[CONFIG_INTERVAL_GRIDCLEAN] = MIN_GRID_DELAY; - } - if (reload) - sMapMgr->SetGridCleanUpDelay(_int_configs[CONFIG_INTERVAL_GRIDCLEAN]); _int_configs[CONFIG_INTERVAL_MAPUPDATE] = sConfigMgr->GetOption("MapUpdateInterval", 10); if (_int_configs[CONFIG_INTERVAL_MAPUPDATE] < MIN_MAP_UPDATE_DELAY) @@ -1259,10 +1248,6 @@ void World::LoadConfigSettings(bool reload) _maxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE; } - m_visibility_notify_periodOnContinents = sConfigMgr->GetOption("Visibility.Notify.Period.OnContinents", DEFAULT_VISIBILITY_NOTIFY_PERIOD); - m_visibility_notify_periodInInstances = sConfigMgr->GetOption("Visibility.Notify.Period.InInstances", DEFAULT_VISIBILITY_NOTIFY_PERIOD); - m_visibility_notify_periodInBGArenas = sConfigMgr->GetOption("Visibility.Notify.Period.InBGArenas", DEFAULT_VISIBILITY_NOTIFY_PERIOD); - ///- Load the CharDelete related config options _int_configs[CONFIG_CHARDELETE_METHOD] = sConfigMgr->GetOption("CharDelete.Method", 0); _int_configs[CONFIG_CHARDELETE_MIN_LEVEL] = sConfigMgr->GetOption("CharDelete.MinLevel", 0); @@ -1420,16 +1405,8 @@ 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); @@ -2172,14 +2149,21 @@ void World::SetInitialWorldSettings() { LOG_INFO("server.loading", "Loading All Grids For All Non-Instanced Maps..."); - sMapMgr->DoForAllMaps([](Map* map) + for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + { + MapEntry const* mapEntry = sMapStore.LookupEntry(i); + + if (mapEntry && !mapEntry->Instanceable()) { - if (!map->Instanceable()) + Map* map = sMapMgr->CreateBaseMap(mapEntry->MapID); + + if (map) { LOG_INFO("server.loading", ">> Loading All Grids For Map {}", map->GetId()); map->LoadAllCells(); } - }); + } + } } uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); @@ -2255,6 +2239,8 @@ 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/game/World/World.h b/src/server/game/World/World.h index 68a349969..de373358a 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -322,10 +322,6 @@ public: static float GetMaxVisibleDistanceInInstances() { return _maxVisibleDistanceInInstances; } static float GetMaxVisibleDistanceInBGArenas() { return _maxVisibleDistanceInBGArenas; } - static int32 GetVisibilityNotifyPeriodOnContinents() { return m_visibility_notify_periodOnContinents; } - static int32 GetVisibilityNotifyPeriodInInstances() { return m_visibility_notify_periodInInstances; } - static int32 GetVisibilityNotifyPeriodInBGArenas() { return m_visibility_notify_periodInBGArenas; } - // our: needed for arena spectator subscriptions uint32 GetNextWhoListUpdateDelaySecs() override; @@ -413,10 +409,6 @@ private: static float _maxVisibleDistanceInInstances; static float _maxVisibleDistanceInBGArenas; - static int32 m_visibility_notify_periodOnContinents; - static int32 m_visibility_notify_periodInInstances; - static int32 m_visibility_notify_periodInBGArenas; - std::string _realmName; // CLI command holder to be thread safe diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp index f52225e76..8ebc9569b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp @@ -327,7 +327,6 @@ 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 faddef617..a8aac9757 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp @@ -425,7 +425,6 @@ 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 71fd06450..72ef3e5dd 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -105,7 +105,6 @@ 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 cc26b66c8..8d48baefa 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -55,7 +55,6 @@ 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/Events/midsummer.cpp b/src/server/scripts/Events/midsummer.cpp index 6d347d2e2..913640131 100644 --- a/src/server/scripts/Events/midsummer.cpp +++ b/src/server/scripts/Events/midsummer.cpp @@ -159,6 +159,8 @@ struct npc_midsummer_torch_target : public ScriptedAI int8 num = urand(0, posVec.size() - 1); Position pos; pos.Relocate(posVec.at(num)); + me->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f); + me->m_last_notify_mstime = GameTime::GetGameTimeMS().count() + 10000; me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp index a309d4bc3..42817e795 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp @@ -347,7 +347,6 @@ void hyjalAI::Reset() { IsDummy = false; me->setActive(true); - me->SetFarVisible(true); // GUIDs PlayerGUID.Clear(); BossGUID[0].Clear(); @@ -494,7 +493,6 @@ void hyjalAI::SummonCreature(uint32 entry, float Base[4][3]) creature->SetWalk(false); creature->setActive(true); - creature->SetFarVisible(true); switch (entry) { case NECROMANCER: @@ -1023,7 +1021,6 @@ 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 @@ -1036,7 +1033,6 @@ 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 @@ -1049,7 +1045,6 @@ 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; @@ -1067,7 +1062,6 @@ 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 @@ -1080,7 +1074,6 @@ 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 @@ -1093,7 +1086,6 @@ 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 8297d8904..ec4498925 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,7 +389,6 @@ 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 d03ad2745..968fcba47 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -339,7 +339,6 @@ 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); @@ -378,7 +377,6 @@ public: return; me->setActive(true); - me->SetFarVisible(true); me->SetDisableGravity(true); me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->SetSpeed(MOVE_RUN, 4.28571f); @@ -1409,7 +1407,6 @@ 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)); @@ -1426,7 +1423,6 @@ public: return; me->setActive(false); - me->SetFarVisible(false); me->SetDisableGravity(false); me->SetHomePosition(SpinestalkerLandPos); me->SetFacingTo(SpinestalkerLandPos.GetOrientation()); @@ -1542,7 +1538,6 @@ 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)); @@ -1561,8 +1556,6 @@ 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 a8f48f95e..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 @@ -484,7 +484,6 @@ 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 745676de0..1ab35a6a1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -175,7 +175,6 @@ 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 b85c19216..1803f4dcc 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -517,7 +517,6 @@ 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); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index 4817b8d86..726e2523b 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -443,6 +443,8 @@ public: GetUnitOwner()->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); GetUnitOwner()->SetStandState(UNIT_STAND_STATE_DEAD); + GetUnitOwner()->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f); + GetUnitOwner()->m_delayed_unit_relocation_timer = 1000; } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)