fix(Core/Grid): Address bugs and performance issues introduced by visibility notifier implementation (#17480)

* Bug fixes

- Corrected std::chrono from seconds to milliseconds
- Got rid of leftover code that caused objects to not show up on time

* Removed logic to set gameobject as active

- More alignement with TC.
- Reduces CPU usage drastically

* Revert back to using time_t instead of std chrono

* Invoke SetNoCreate() method to reduce CPU usage drastically

* Remove setActive from static and motion transports

* Fix performance issues

* Added SetFarVisible to WG and some dungeon scripts

- Also removed setActive(true) from creatures in Wintergrasp. As for gameobjects they are set to active upon being damaged/destroyed and removed from active on rebuild (reset)

* Removed comments related to VISIBILITY_COMPENSATION

* Fix log

* Deleted unused files + corrected a check

* Added missing header

* Removed unused parameter

* Removed another unsued parameter

* Changed vector to set for i_visibleNow

- Changed vector to set for i_visibleNow in VisibleNotifer
- Adjusted HaveAtClient to accept Object*
- Adjusted SendUpdateToPlayer to send createobject packet only if not known to client
This commit is contained in:
AG
2023-10-23 10:37:11 +02:00
committed by GitHub
parent a56a224bd7
commit 60e27511c5
53 changed files with 509 additions and 586 deletions
+2 -2
View File
@@ -815,7 +815,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl
// Set creature in world
map->AddToMap(creature);
creature->setActive(true);
creature->SetFarVisible(true);
return creature;
}
@@ -840,7 +840,7 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z
// Add to world
map->AddToMap(go);
go->setActive(true);
go->SetFarVisible(true);
return go;
}
@@ -1159,6 +1159,7 @@ struct BfWGGameObjectBuilding
// Rebuild gameobject
go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true);
go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[m_Team]);
go->setActive(false); // Everything is reset, no need keep active at this point.
}
// Update worldstate
@@ -1170,6 +1171,10 @@ struct BfWGGameObjectBuilding
// Called when associated gameobject is damaged
void Damaged()
{
GameObject* go = m_WG->GetGameObject(m_Build);
if (go)
go->setActive(true);
// Update worldstate
m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE - (m_Team * 3);
m_WG->SendUpdateWorldState(m_WorldState, m_State);
@@ -1193,6 +1198,10 @@ struct BfWGGameObjectBuilding
// Called when associated gameobject is destroyed
void Destroyed()
{
GameObject* go = m_WG->GetGameObject(m_Build);
if (go)
go->setActive(true);
// Update worldstate
m_State = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY - (m_Team * 3);
m_WG->SendUpdateWorldState(m_WorldState, m_State);
+20 -8
View File
@@ -301,9 +301,6 @@ void Creature::RemoveFromWorld()
if (m_formation)
sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
if (Transport* transport = GetTransport())
transport->RemovePassenger(this, true);
Unit::RemoveFromWorld();
if (m_spawnId)
@@ -1826,7 +1823,25 @@ void Creature::DeleteFromDB()
return;
}
GetMap()->RemoveCreatureRespawnTime(m_spawnId);
CreatureData const* data = sObjectMgr->GetCreatureData(m_spawnId);
if (!data)
return;
CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction();
sMapMgr->DoForAllMapsWithMapId(data->mapid,
[this, charTrans](Map* map) -> void
{
// despawn all active creatures, and remove their respawns
std::vector<Creature*> toUnload;
for (auto const& pair : Acore::Containers::MapEqualRange(map->GetCreatureBySpawnIdStore(), m_spawnId))
toUnload.push_back(pair.second);
for (Creature* creature : toUnload)
map->AddObjectToRemoveList(creature);
map->RemoveCreatureRespawnTime(m_spawnId);
}
);
sObjectMgr->DeleteCreatureData(m_spawnId);
WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction();
@@ -3060,10 +3075,7 @@ std::string const& Creature::GetNameForLocaleIdx(LocaleConstant loc_idx) const
void Creature::SetPosition(float x, float y, float z, float o)
{
if (!Acore::IsValidMapCoord(x, y, z, o))
return;
GetMap()->CreatureRelocation(this, x, y, z, o);
UpdatePosition(x, y, z, o, false);
}
bool Creature::IsDungeonBoss() const
@@ -68,6 +68,7 @@ public:
void Update(uint32 time) override; // overwrited Unit::Update
void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr, float* dist = nullptr) const;
bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->mapid != GetMapId(); }
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
void SetCorpseRemoveTime(uint32 delay);
@@ -47,14 +47,6 @@ DynamicObject::~DynamicObject()
void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */)
{
if (Transport* transport = GetTransport())
{
transport->RemovePassenger(this);
SetTransport(nullptr);
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
WorldObject::CleanupsBeforeDelete(finalCleanup);
}
@@ -88,9 +80,6 @@ void DynamicObject::RemoveFromWorld()
UnbindFromCaster();
if (Transport* transport = GetTransport())
transport->RemovePassenger(this, true);
WorldObject::RemoveFromWorld();
GetMap()->GetObjectsStore().Remove<DynamicObject>(GetGUID());
@@ -125,17 +114,15 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste
SetFloatValue(DYNAMICOBJECT_RADIUS, radius);
SetUInt32Value(DYNAMICOBJECT_CASTTIME, GameTime::GetGameTimeMS().count());
if (IsWorldObject())
setActive(true); //must before add to map to be put in world container
if (!GetMap()->AddToMap(this, true))
{
// Returning false will cause the object to be deleted - remove from transport
return false;
}
if (IsWorldObject())
{
setActive(true);
}
return true;
}
@@ -27,6 +27,7 @@
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "GroupMgr.h"
#include "MapMgr.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
#include "PoolMgr.h"
@@ -102,18 +103,9 @@ std::string const& GameObject::GetAIName() const
return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName;
}
void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
void GameObject::CleanupsBeforeDelete(bool finalCleanup)
{
if (GetTransport() && !ToTransport())
{
GetTransport()->RemovePassenger(this);
SetTransport(nullptr);
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
if (IsInWorld())
RemoveFromWorld();
WorldObject::CleanupsBeforeDelete(finalCleanup);
if (m_uint32Values) // field array can be not exist if GameOBject not loaded
RemoveFromOwner();
@@ -182,9 +174,6 @@ void GameObject::RemoveFromWorld()
if (GetMap()->ContainsGameObjectModel(*m_model))
GetMap()->RemoveGameObjectModel(*m_model);
if (Transport* transport = GetTransport())
transport->RemovePassenger(this, true);
// If linked trap exists, despawn it
if (GameObject* linkedTrap = GetLinkedTrap())
{
@@ -888,7 +877,11 @@ void GameObject::Update(uint32 diff)
if (!m_spawnedByDefault)
{
m_respawnTime = 0;
if (m_spawnId)
DestroyForNearbyPlayers(); // xinef: old UpdateObjectVisibility();
else
Delete();
return;
}
@@ -1184,7 +1177,31 @@ bool GameObject::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, boo
void GameObject::DeleteFromDB()
{
GetMap()->RemoveGORespawnTime(m_spawnId);
if (!m_spawnId)
{
LOG_ERROR("entities.gameobject", "Trying to delete not saved gameobject: {}", GetGUID().ToString());
return;
}
GameObjectData const* data = sObjectMgr->GetGameObjectData(m_spawnId);
if (!data)
return;
CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction();
sMapMgr->DoForAllMapsWithMapId(data->mapid,
[this, charTrans](Map* map) -> void
{
// despawn all active objects, and remove their respawns
std::vector<GameObject*> toUnload;
for (auto const& pair : Acore::Containers::MapEqualRange(map->GetGameObjectBySpawnIdStore(), m_spawnId))
toUnload.push_back(pair.second);
for (GameObject* obj : toUnload)
map->AddObjectToRemoveList(obj);
map->RemoveGORespawnTime(m_spawnId);
}
);
sObjectMgr->DeleteGOData(m_spawnId);
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT);
@@ -2173,15 +2190,6 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const
&& dz < (info->maxZ * scale) + radius && dz > (info->minZ * scale) - radius;
}
void GameObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const
{
dist += GetObjectSize();
if (includeMargin)
dist += VISIBILITY_COMPENSATION * 2.0f; // pussywizard: to ensure everyone receives all important packets
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
Cell::VisitWorldObjects(this, notifier, dist);
}
void GameObject::EventInform(uint32 eventId)
{
if (!eventId)
@@ -289,8 +289,6 @@ public:
void SendCustomAnim(uint32 anim);
[[nodiscard]] bool IsInRange(float x, float y, float z, float radius) const;
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard!
void ModifyHealth(int32 change, Unit* attackerOrHealer = nullptr, uint32 spellId = 0);
void SetDestructibleBuildingModifyState(bool allow) { m_allowModifyDestructibleBuilding = allow; }
// sets GameObject type 33 destruction flags and optionally default health for that state
+30 -65
View File
@@ -21,7 +21,6 @@
#include "CellImpl.h"
#include "Chat.h"
#include "Creature.h"
#include "DynamicVisibility.h"
#include "GameObjectAI.h"
#include "GameTime.h"
#include "GridNotifiers.h"
@@ -249,6 +248,9 @@ void Object::SendUpdateToPlayer(Player* player)
UpdateData upd;
WorldPacket packet;
if (player->HaveAtClient(this))
BuildValuesUpdateBlockForPlayer(&upd, player);
else
BuildCreateUpdateBlockForPlayer(&upd, player);
upd.BuildPacket(&packet);
player->GetSession()->SendPacket(&packet);
@@ -1048,7 +1050,7 @@ void MovementInfo::OutDebug()
}
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(),
LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
LastUsedScriptID(0), m_name(""), m_isActive(false), m_isFarVisible(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
{
@@ -1105,8 +1107,6 @@ void WorldObject::setActive(bool on)
map->AddToActive(this->ToCreature());
else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
map->AddToActive((DynamicObject*)this);
else if (GetTypeId() == TYPEID_GAMEOBJECT)
map->AddToActive((GameObject*)this);
}
else
{
@@ -1114,11 +1114,17 @@ void WorldObject::setActive(bool on)
map->RemoveFromActive(this->ToCreature());
else if (GetTypeId() == TYPEID_DYNAMICOBJECT)
map->RemoveFromActive((DynamicObject*)this);
else if (GetTypeId() == TYPEID_GAMEOBJECT)
map->RemoveFromActive((GameObject*)this);
}
}
void WorldObject::SetFarVisible(bool on)
{
if (GetTypeId() == TYPEID_PLAYER)
return;
m_isFarVisible = on;
}
void WorldObject::SetVisibilityDistanceOverride(VisibilityDistanceType type)
{
ASSERT(type < VisibilityDistanceType::Max);
@@ -1134,6 +1140,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
{
if (IsInWorld())
RemoveFromWorld();
if (Transport* transport = GetTransport())
transport->RemovePassenger(this, true);
}
void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask)
@@ -1626,9 +1635,9 @@ float WorldObject::GetGridActivationRange() const
{
if (ToPlayer()->GetCinematicMgr()->IsOnCinematic())
{
return DEFAULT_VISIBILITY_INSTANCE;
return std::max(DEFAULT_VISIBILITY_INSTANCE, GetMap()->GetVisibilityRange());
}
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange();
}
else if (ToCreature())
{
@@ -1644,29 +1653,12 @@ float WorldObject::GetGridActivationRange() const
float WorldObject::GetVisibilityRange() const
{
if (IsVisibilityOverridden() && GetTypeId() == TYPEID_UNIT)
{
if (IsVisibilityOverridden() && !ToPlayer())
return *m_visibilityDistanceOverride;
}
else if (GetTypeId() == TYPEID_GAMEOBJECT)
{
{
if (IsInWintergrasp())
{
return VISIBILITY_DIST_WINTERGRASP + VISIBILITY_INC_FOR_GOBJECTS;
}
else if (IsVisibilityOverridden())
{
return *m_visibilityDistanceOverride;
}
else if (IsFarVisible() && !ToPlayer())
return MAX_VISIBILITY_DISTANCE;
else
{
return GetMap()->GetVisibilityRange() + VISIBILITY_INC_FOR_GOBJECTS;
}
}
}
else
return IsInWintergrasp() ? VISIBILITY_DIST_WINTERGRASP : GetMap()->GetVisibilityRange();
return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange();
}
float WorldObject::GetSightRange(WorldObject const* target) const
@@ -1675,45 +1667,20 @@ float WorldObject::GetSightRange(WorldObject const* target) const
{
if (ToPlayer())
{
if (target)
{
if (target->IsVisibilityOverridden() && target->GetTypeId() == TYPEID_UNIT)
{
if (target && target->IsVisibilityOverridden() && !target->ToPlayer())
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 (target && target->IsFarVisible() && !target->ToPlayer())
return MAX_VISIBILITY_DISTANCE;
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();
return IsInWintergrasp() ? VISIBILITY_DISTANCE_LARGE : GetMap()->GetVisibilityRange();
}
else if (ToCreature())
{
return ToCreature()->m_SightDistance;
}
else
{
return SIGHT_RANGE_UNIT;
}
}
if (ToDynObject() && isActiveObject())
{
@@ -2077,11 +2044,8 @@ void Unit::BuildHeartBeatMsg(WorldPacket* data) const
BuildMovementPacket(data);
}
void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin, Player const* skipped_rcvr) const
void WorldObject::SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, Player const* skipped_rcvr) const
{
dist += GetObjectSize();
if (includeMargin)
dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
Cell::VisitWorldObjects(this, notifier, dist);
}
@@ -2228,6 +2192,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
return nullptr;
}
if (!IsGridLoaded(pos.GetPositionX(), pos.GetPositionY()))
EnsureGridLoaded(Cell(pos.GetPositionX(), pos.GetPositionY()));
if (!summon->Create(GenerateLowGuid<HighGuid::Unit>(), this, phase, entry, vehId, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()))
{
@@ -2901,8 +2866,8 @@ void WorldObject::DestroyForNearbyPlayers()
return;
std::list<Player*> targets;
Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange() + VISIBILITY_COMPENSATION, false);
Acore::PlayerListSearcherWithSharedVision<Acore::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
Acore::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange(), false);
Acore::PlayerListSearcher<Acore::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
Cell::VisitWorldObjects(this, searcher, GetVisibilityRange());
for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
@@ -2984,7 +2949,7 @@ struct WorldObjectChangeAccumulator
source = iter->GetSource();
ObjectGuid guid = source->GetCasterGUID();
if (guid)
if (guid.IsPlayer())
{
//Caster may be nullptr if DynObj is in removelist
if (Player* caster = ObjectAccessor::FindPlayer(guid))
+5 -4
View File
@@ -488,9 +488,9 @@ public:
virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
virtual void SendMessageToSet(WorldPacket const* data, bool self) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const; // pussywizard!
virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), false, true, skipped_rcvr); } // pussywizard!
virtual void SendMessageToSet(WorldPacket const* data, bool self) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), self); } // pussywizard!
virtual void SendMessageToSetInRange(WorldPacket const* data, float dist, bool /*self*/, Player const* skipped_rcvr = nullptr) const; // pussywizard!
virtual void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const { if (IsInWorld()) SendMessageToSetInRange(data, GetVisibilityRange(), false, skipped_rcvr); } // pussywizard!
virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; }
@@ -569,6 +569,7 @@ public:
[[nodiscard]] bool isActiveObject() const { return m_isActive; }
void setActive(bool isActiveObject);
[[nodiscard]] bool IsFarVisible() const { return m_isFarVisible; }
void SetFarVisible(bool on);
[[nodiscard]] bool IsVisibilityOverridden() const { return m_visibilityDistanceOverride.has_value(); }
void SetVisibilityDistanceOverride(VisibilityDistanceType type);
void SetWorldObject(bool apply);
@@ -577,7 +578,7 @@ public:
[[nodiscard]] bool IsInWintergrasp() const
{
return GetMapId() == 571 && GetPositionX() > 3733.33331f && GetPositionX() < 5866.66663f && GetPositionY() > 1599.99999f && GetPositionY() < 4799.99997f;
return GetMapId() == 571 && GetZoneId() == 4197;
}
#ifdef MAP_BASED_RAND_GEN
@@ -23,10 +23,7 @@
#define CONTACT_DISTANCE 0.5f
#define INTERACTION_DISTANCE 5.5f
#define ATTACK_DISTANCE 5.0f
#define VISIBILITY_COMPENSATION 15.0f // increase searchers
#define INSPECT_DISTANCE 28.0f
#define VISIBILITY_INC_FOR_GOBJECTS 30.0f // pussywizard
#define SPELL_SEARCHER_COMPENSATION 30.0f // increase searchers size in case we have large npc near cell border
#define TRADE_DISTANCE 11.11f
#define MAX_VISIBILITY_DISTANCE SIZE_OF_GRIDS // max distance for visible objects, experimental
#define SIGHT_RANGE_UNIT 50.0f
@@ -38,7 +35,6 @@
#define VISIBILITY_DISTANCE_TINY 25.0f
#define DEFAULT_VISIBILITY_DISTANCE VISIBILITY_DISTANCE_NORMAL // default visible distance, 100 yards on continents
#define DEFAULT_VISIBILITY_INSTANCE 170.0f // default visible distance in instances, 170 yards
#define VISIBILITY_DIST_WINTERGRASP 175.0f
#define DEFAULT_VISIBILITY_BGARENAS 533.0f // default visible distance in BG/Arenas, roughly 533 yards
#define DEFAULT_WORLD_OBJECT_SIZE 0.388999998569489f // player size, also currently used (correctly?) for any non Unit world objects
@@ -134,6 +134,7 @@ class ObjectGuid
ObjectGuid(HighGuid hi, uint32 entry, LowType counter) : _guid(counter ? uint64(counter) | (uint64(entry) << 24) | (uint64(hi) << 48) : 0) { }
ObjectGuid(HighGuid hi, LowType counter) : _guid(counter ? uint64(counter) | (uint64(hi) << 48) : 0) { }
operator uint64() const { return _guid; }
PackedGuidReader ReadAsPacked() { return PackedGuidReader(*this); }
void Set(uint64 guid) { _guid = guid; }
+5 -17
View File
@@ -1353,10 +1353,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if (GetTransport())
{
m_transport->RemovePassenger(this);
m_transport = nullptr;
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
m_transport->RemovePassenger(this, true);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
}
@@ -1398,10 +1395,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
else
{
m_transport->RemovePassenger(this);
m_transport = nullptr;
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
m_transport->RemovePassenger(this, true);
}
}
@@ -5581,14 +5575,11 @@ void Player::SaveRecallPosition()
m_recallO = GetOrientation();
}
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin, Player const* skipped_rcvr) const
void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, Player const* skipped_rcvr) const
{
if (self)
GetSession()->SendPacket(data);
dist += GetObjectSize();
if (includeMargin)
dist += VISIBILITY_COMPENSATION; // pussywizard: to ensure everyone receives all important packets
Acore::MessageDistDeliverer notifier(this, data, dist, false, skipped_rcvr);
Cell::VisitWorldObjects(this, notifier, dist);
}
@@ -11322,7 +11313,7 @@ WorldLocation Player::GetStartPosition() const
return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0);
}
bool Player::HaveAtClient(WorldObject const* u) const
bool Player::HaveAtClient(Object const* u) const
{
if (u == this)
{
@@ -13096,14 +13087,11 @@ void Player::SetViewpoint(WorldObject* target, bool apply)
UpdateVisibilityOf(target);
if (target->isType(TYPEMASK_UNIT) && !GetVehicle())
((Unit*)target)->AddPlayerToVision(this);
static_cast<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()))
+6 -7
View File
@@ -1986,10 +1986,10 @@ public:
void ProcessTerrainStatusUpdate() override;
void SendMessageToSet(WorldPacket const* data, bool self) const override { SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool includeMargin = false, Player const* skipped_rcvr = nullptr) const override; // pussywizard!
void SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const; // pussywizard! param includeMargin not needed here
void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override { SendMessageToSetInRange(data, GetVisibilityRange(), skipped_rcvr != this, true, skipped_rcvr); } // pussywizard!
void SendMessageToSet(WorldPacket const* data, bool self) const override { SendMessageToSetInRange(data, GetVisibilityRange(), self); } // pussywizard!
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, Player const* skipped_rcvr = nullptr) const override; // pussywizard!
void SendMessageToSetInRange_OwnTeam(WorldPacket const* data, float dist, bool self) const; // pussywizard!
void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const override { SendMessageToSetInRange(data, GetVisibilityRange(), skipped_rcvr != this, skipped_rcvr); } // pussywizard!
void SendTeleportAckPacket();
@@ -2342,9 +2342,8 @@ public:
// currently visible objects at player client
GuidUnorderedSet m_clientGUIDs;
std::vector<Unit*> m_newVisible; // pussywizard
[[nodiscard]] bool HaveAtClient(WorldObject const* u) const;
[[nodiscard]] bool HaveAtClient(Object const* u) const;
[[nodiscard]] bool HaveAtClient(ObjectGuid guid) const;
[[nodiscard]] bool IsNeverVisible() const override;
@@ -2358,7 +2357,7 @@ public:
void UpdateTriggerVisibility();
template<class T>
void UpdateVisibilityOf(T* target, UpdateData& data, std::vector<Unit*>& visibleNow);
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow);
uint8 m_forced_speed_changes[MAX_MOVE_TYPE];
@@ -1521,17 +1521,11 @@ void Player::UpdatePotionCooldown(Spell* spell)
SetLastPotionId(0);
}
template void Player::UpdateVisibilityOf(Player* target, UpdateData& data,
std::vector<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data,
std::vector<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data,
std::vector<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data,
std::vector<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(DynamicObject* target,
UpdateData& data,
std::vector<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, std::set<Unit*>& visibleNow);
template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, std::set<Unit*>& visibleNow);
void Player::UpdateVisibilityForPlayer(bool mapChange)
{
@@ -1543,7 +1537,7 @@ void Player::UpdateVisibilityForPlayer(bool mapChange)
}
// updates visibility of all objects around point of view for current player
Acore::VisibleNotifier notifier(*this, mapChange);
Acore::VisibleNotifier notifier(*this);
Cell::VisitAllObjects(m_seer, notifier, GetSightRange());
notifier.SendToSelf(); // send gathered data
}
@@ -1564,15 +1558,13 @@ void Player::UpdateObjectVisibility(bool forced)
}
template <class T>
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target,
std::vector<Unit*>& /*v*/)
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, T* target, std::set<Unit*>& /*v*/)
{
s64.insert(target->GetGUID());
}
template <>
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target,
std::vector<Unit*>& /*v*/)
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target, std::set<Unit*>& /*v*/)
{
// @HACK: This is to prevent objects like deeprun tram from disappearing
// when player moves far from its spawn point while riding it
@@ -1581,19 +1573,17 @@ inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, GameObject* target,
}
template <>
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target,
std::vector<Unit*>& v)
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Creature* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.push_back(target);
v.insert(target);
}
template <>
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target,
std::vector<Unit*>& v)
inline void UpdateVisibilityOf_helper(GuidUnorderedSet& s64, Player* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.push_back(target);
v.insert(target);
}
template <class T>
@@ -1609,8 +1599,7 @@ inline void BeforeVisibilityDestroy<Creature>(Creature* t, Player* p)
}
template <class T>
void Player::UpdateVisibilityOf(T* target, UpdateData& data,
std::vector<Unit*>& visibleNow)
void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow)
{
if (HaveAtClient(target))
{
@@ -32,7 +32,7 @@
#include "World.h"
#include "WorldModel.h"
MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false)
MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _delayedTeleport(false)
{
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
@@ -230,8 +230,14 @@ void MotionTransport::Update(uint32 diff)
3. transport moves from active to inactive grid
4. the grid that transport is currently in unloads
*/
if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2.
bool gridActive = GetMap()->IsGridLoaded(GetPositionX(), GetPositionY());
if (_staticPassengers.empty() && gridActive) // 2.
LoadStaticPassengers();
else if (!_staticPassengers.empty() && !gridActive)
// 4. - if transports stopped on grid edge, some passengers can remain in active grids
// unload all static passengers otherwise passengers won't load correctly when the grid that transport is currently in becomes active
UnloadStaticPassengers();
}
}
@@ -248,18 +254,27 @@ void MotionTransport::DelayedUpdate(uint32 /*diff*/)
void MotionTransport::UpdatePosition(float x, float y, float z, float o)
{
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
GetMap()->LoadGrid(x, y);
bool newActive = GetMap()->IsGridLoaded(x, y);
Cell oldCell(GetPositionX(), GetPositionY());
Relocate(x, y, z, o);
UpdateModelPosition();
UpdatePassengerPositions(_passengers);
if (_staticPassengers.empty())
/* There are four possible scenarios that trigger loading/unloading passengers:
1. transport moves from inactive to active grid
2. the grid that transport is currently in becomes active
3. transport moves from active to inactive grid
4. the grid that transport is currently in unloads
*/
if (_staticPassengers.empty() && newActive) // 1.
LoadStaticPassengers();
else if (!_staticPassengers.empty() && !newActive && oldCell.DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3.
UnloadStaticPassengers();
else
UpdatePassengerPositions(_staticPassengers);
// 4. is handed by grid unload
}
void MotionTransport::AddPassenger(WorldObject* passenger, bool withAll)
@@ -306,8 +321,7 @@ void MotionTransport::RemovePassenger(WorldObject* passenger, bool withAll)
{
passenger->SetTransport(nullptr);
passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
passenger->m_movementInfo.transport.guid.Clear();
passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
passenger->m_movementInfo.transport.Reset();
if (passenger->ToUnit())
{
passenger->ToUnit()->ClearUnitState(UNIT_STATE_IGNORE_PATHFINDING);
@@ -407,9 +421,6 @@ GameObject* MotionTransport::CreateGOPassenger(ObjectGuid::LowType guid, GameObj
void MotionTransport::LoadStaticPassengers()
{
if (PassengersLoaded())
return;
SetPassengersLoaded(true);
if (uint32 mapId = GetGOInfo()->moTransport.mapID)
{
CellObjectGuidsMap const& cells = sObjectMgr->GetMapObjectGuids(mapId, GetMap()->GetSpawnMode());
@@ -431,7 +442,6 @@ void MotionTransport::LoadStaticPassengers()
void MotionTransport::UnloadStaticPassengers()
{
SetPassengersLoaded(false);
while (!_staticPassengers.empty())
{
WorldObject* obj = *_staticPassengers.begin();
@@ -542,11 +552,19 @@ void MotionTransport::DelayedTeleportTransport()
_delayedTeleport = false;
uint32 newMapId = _nextFrame->Node->mapid;
Map* newMap = sMapMgr->CreateBaseMap(newMapId);
GetMap()->RemoveFromMap<MotionTransport>(this, false);
float x = _nextFrame->Node->x,
y = _nextFrame->Node->y,
z = _nextFrame->Node->z,
o = _nextFrame->InitialOrientation;
if (!newMap->IsGridLoaded(x, y) && !_passengers.empty())
newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map
SetMap(newMap);
PassengerSet _passengersCopy = _passengers;
for (PassengerSet::iterator itr = _passengersCopy.begin(); itr != _passengersCopy.end(); )
{
@@ -592,15 +610,8 @@ void MotionTransport::DelayedTeleportTransport()
}
}
Map* newMap = sMapMgr->CreateBaseMap(newMapId);
GetMap()->RemoveFromMap<MotionTransport>(this, false);
newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map
SetMap(newMap);
Relocate(x, y, z, o);
GetMap()->AddToMap<MotionTransport>(this);
LoadStaticPassengers();
}
void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers)
@@ -631,7 +642,7 @@ void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers)
case TYPEID_UNIT:
{
Creature* creature = passenger->ToCreature();
GetMap()->CreatureRelocation(creature, x, y, z, o);
GetMap()->CreatureRelocation(creature, x, y, z, o, false);
creature->GetTransportHomePosition(x, y, z, o);
CalculatePassengerPosition(x, y, z, &o);
@@ -643,7 +654,7 @@ void MotionTransport::UpdatePassengerPositions(PassengerSet& passengers)
GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
break;
case TYPEID_GAMEOBJECT:
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o);
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false);
break;
case TYPEID_DYNAMICOBJECT:
GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o);
@@ -780,7 +791,6 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize();
this->setActive(true);
return true;
}
@@ -915,7 +925,8 @@ void StaticTransport::UpdatePosition(float x, float y, float z, float o)
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
GetMap()->LoadGrid(x, y);
GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model
Relocate(x, y, z, o);
UpdateModelPosition();
UpdatePassengerPositions();
}
@@ -942,17 +953,14 @@ void StaticTransport::UpdatePassengerPositions()
switch (passenger->GetTypeId())
{
case TYPEID_UNIT:
GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o);
GetMap()->CreatureRelocation(passenger->ToCreature(), x, y, z, o, false);
break;
case TYPEID_PLAYER:
if (passenger->IsInWorld())
{
GetMap()->PlayerRelocation(passenger->ToPlayer(), x, y, z, o);
passenger->ToPlayer()->SetFallInformation(GameTime::GetGameTime().count(), z);
}
break;
case TYPEID_GAMEOBJECT:
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o);
GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false);
break;
case TYPEID_DYNAMICOBJECT:
GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o);
@@ -1001,8 +1009,7 @@ void StaticTransport::RemovePassenger(WorldObject* passenger, bool withAll)
{
passenger->SetTransport(nullptr);
passenger->m_movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
passenger->m_movementInfo.transport.guid.Clear();
passenger->m_movementInfo.transport.pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
passenger->m_movementInfo.transport.Reset();
}
}
}
@@ -68,8 +68,6 @@ public:
PassengerSet const& GetStaticPassengers() const { return _staticPassengers; }
void UnloadStaticPassengers();
void UnloadNonStaticPassengers();
void SetPassengersLoaded(bool loaded) { _passengersLoaded = loaded; }
bool PassengersLoaded() const { return _passengersLoaded; }
KeyFrameVec const& GetKeyFrames() const { return _transportInfo->keyFrames; }
void EnableMovement(bool enabled);
@@ -104,7 +102,6 @@ private:
PassengerSet _staticPassengers;
mutable std::mutex Lock;
bool _passengersLoaded;
bool _delayedTeleport;
};
+29 -29
View File
@@ -32,7 +32,6 @@
#include "CreatureAIImpl.h"
#include "CreatureGroups.h"
#include "DisableMgr.h"
#include "DynamicVisibility.h"
#include "Formulas.h"
#include "GameObjectAI.h"
#include "GameTime.h"
@@ -44,6 +43,7 @@
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "MovementGenerator.h"
#include "MovementPacketBuilder.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@@ -567,11 +567,19 @@ void Unit::UpdateSplineMovement(uint32 t_diff)
// this code cant be placed inside EscortMovementGenerator, because we cant delete active MoveGen while it is updated
SplineHandler handler(this);
movespline->updateState(t_diff, handler);
// Xinef: Spline was cleared by StopMoving, return
if (!movespline->Initialized())
if (movespline->isCyclic())
{
DisableSpline();
return;
m_splineSyncTimer.Update(t_diff);
if (m_splineSyncTimer.Passed())
{
m_splineSyncTimer.Reset(5000); // Retail value, do not change
WorldPacket data(SMSG_FLIGHT_SPLINE_SYNC, 4 + GetPackGUID().size());
Movement::PacketBuilder::WriteSplineSync(*movespline, data);
data.appendPackGUID(GetGUID());
SendMessageToSet(&data, true);
}
}
bool arrived = movespline->Finalized();
@@ -584,17 +592,11 @@ void Unit::UpdateSplineMovement(uint32 t_diff)
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, movespline->GetAnimationType());
}
// pussywizard: update always! not every 400ms, because movement generators need the actual position
//m_movesplineTimer.Update(t_diff);
//if (m_movesplineTimer.Passed() || arrived)
UpdateSplinePosition();
}
void Unit::UpdateSplinePosition()
{
//static uint32 const positionUpdateDelay = 400;
//m_movesplineTimer.Reset(positionUpdateDelay);
Movement::Location loc = movespline->ComputePosition();
if (movespline->onTransport)
@@ -607,16 +609,14 @@ void Unit::UpdateSplinePosition()
if (TransportBase* transport = GetDirectTransport())
transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
else
return;
}
// Xinef: if we had spline running update orientation along with position
//if (HasUnitState(UNIT_STATE_CANNOT_TURN))
// loc.orientation = GetOrientation();
if (HasUnitState(UNIT_STATE_CANNOT_TURN))
loc.orientation = GetOrientation();
if (GetTypeId() == TYPEID_PLAYER)
UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
else
ToCreature()->SetPosition(loc.x, loc.y, loc.z, loc.orientation);
}
void Unit::DisableSpline()
@@ -15709,15 +15709,9 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup)
void Unit::CleanupsBeforeDelete(bool finalCleanup)
{
if (GetTransport())
{
GetTransport()->RemovePassenger(this);
SetTransport(nullptr);
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
CleanupBeforeRemoveFromMap(finalCleanup);
WorldObject::CleanupsBeforeDelete(finalCleanup);
}
void Unit::UpdateCharmAI()
@@ -20253,10 +20247,14 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel
if (!Acore::IsValidMapCoord(x, y, z, orientation))
return false;
float old_orientation = GetOrientation();
float current_z = GetPositionZ();
bool turn = (old_orientation != orientation);
bool relocated = (teleport || GetPositionX() != x || GetPositionY() != y || current_z != z);
// Check if angular distance changed
bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
// G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
bool const relocated = (teleport ||
std::fabs(GetPositionX() - x) > 0.001f ||
std::fabs(GetPositionY() - y) > 0.001f ||
std::fabs(GetPositionZ() - z) > 0.001f);
if (!GetVehicle())
{
@@ -20282,6 +20280,8 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel
UpdateObjectVisibility(false);
}
UpdatePositionData();
return (relocated || turn);
}
+1 -1
View File
@@ -2575,7 +2575,7 @@ private:
uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer;
uint32 m_lastManaUse; // msecs
//TimeTrackerSmall m_movesplineTimer;
TimeTrackerSmall m_splineSyncTimer;
Diminishing m_Diminishing;
// Manage all Units that are threatened by us
@@ -545,6 +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->NearTeleportTo(x, y, z, ang, true);
+1 -1
View File
@@ -23,7 +23,7 @@ i_unloadActiveLockCount(0), i_unloadExplicitLock(false), i_unloadReferenceLock(f
{
}
GridInfo::GridInfo(std::chrono::seconds expiry, bool unload /*= true */) : i_timer(expiry.count()), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)),
GridInfo::GridInfo(time_t expiry, bool unload /*= true */) : i_timer(expiry), vis_Update(0, irand(0, DEFAULT_VISIBILITY_NOTIFY_PERIOD)),
i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), i_unloadReferenceLock(false)
{
}
+4 -4
View File
@@ -32,7 +32,7 @@ class AC_GAME_API GridInfo
{
public:
GridInfo();
GridInfo(std::chrono::seconds expiry, bool unload = true);
GridInfo(time_t expiry, bool unload = true);
TimeTracker const& getTimeTracker() const { return i_timer; }
bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; }
void setUnloadExplicitLock(bool on) { i_unloadExplicitLock = on; }
@@ -73,7 +73,7 @@ class NGrid
{
public:
typedef Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> GridType;
NGrid(uint32 id, int32 x, int32 y, std::chrono::seconds expiry, bool unload = true) :
NGrid(uint32 id, int32 x, int32 y, time_t expiry, bool unload = true) :
i_gridId(id), i_GridInfo(GridInfo(expiry, unload)), i_x(x), i_y(y),
i_cellstate(GRID_STATE_INVALID), i_GridObjectDataLoaded(false)
{ }
@@ -111,8 +111,8 @@ public:
void setUnloadReferenceLock(bool on) { i_GridInfo.setUnloadReferenceLock(on); }
void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); }
void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); }
void ResetTimeTracker(std::chrono::seconds interval) { i_GridInfo.ResetTimeTracker(interval.count()); }
void UpdateTimeTracker(std::chrono::seconds diff) { i_GridInfo.UpdateTimeTracker(diff.count()); }
void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); }
void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); }
/*
template<class SPECIFIC_OBJECT> void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT *obj)
@@ -86,7 +86,7 @@ void VisibleNotifier::SendToSelf()
i_data.BuildPacket(&packet);
i_player.GetSession()->SendPacket(&packet);
for (std::vector<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
for (std::set<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
{
i_player.GetInitialVisiblePackets(*it);
}
@@ -42,16 +42,10 @@ namespace Acore
{
Player& i_player;
GuidUnorderedSet vis_guids;
std::vector<Unit*>& i_visibleNow;
bool i_gobjOnly;
std::set<Unit*> i_visibleNow;
UpdateData i_data;
VisibleNotifier(Player& player, bool gobjOnly) :
i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly)
{
i_visibleNow.clear();
}
VisibleNotifier(Player& player) : i_player(player), vis_guids(player.m_clientGUIDs) {}
template<class T> void Visit(GridRefMgr<T>& m);
void SendToSelf(void);
};
@@ -69,7 +63,7 @@ namespace Acore
struct PlayerRelocationNotifier : public VisibleNotifier
{
PlayerRelocationNotifier(Player& player) : VisibleNotifier(player, false) { }
PlayerRelocationNotifier(Player& player) : VisibleNotifier(player) { }
template<class T> void Visit(GridRefMgr<T>& m) { VisibleNotifier::Visit(m); }
void Visit(CreatureMapType&);
@@ -32,10 +32,6 @@
template<class T>
inline void Acore::VisibleNotifier::Visit(GridRefMgr<T>& m)
{
// Xinef: Update gameobjects only
if (i_gobjOnly)
return;
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
{
vis_guids.erase(iter->GetSource()->GetGUID());
+12 -13
View File
@@ -25,6 +25,7 @@
#include "ObjectMgr.h"
#include "Transport.h"
#include "Vehicle.h"
#include "GameTime.h"
void ObjectGridEvacuator::Visit(CreatureMapType& m)
{
@@ -113,18 +114,6 @@ void AddObjectHelper(CellCoord& cell, CreatureMapType& m, uint32& count, Map* ma
++count;
}
template <>
void AddObjectHelper(CellCoord& cell, GameObjectMapType& m, uint32& count, Map* map, GameObject* obj)
{
obj->AddToGrid(m);
ObjectGridLoader::SetObjectCell(obj, cell);
obj->AddToWorld();
if (obj->isActiveObject())
map->AddToActive(obj);
++count;
}
template <class T>
void LoadHelper(CellGuidSet const& /*guid_set*/, CellCoord& /*cell*/, GridRefMgr<T>& /*m*/, uint32& /*count*/, Map* /*map*/)
{
@@ -135,8 +124,13 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<Creatur
{
for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
{
Creature* obj = new Creature();
// Don't spawn at all if there's a respawn timer
ObjectGuid::LowType guid = *i_guid;
time_t now = GameTime::GetGameTime().count();
if (map->GetCreatureRespawnTime(guid) > now)
continue;
Creature* obj = new Creature();
if (!obj->LoadFromDB(guid, map))
{
delete obj;
@@ -162,7 +156,12 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord& cell, GridRefMgr<GameObj
{
for (CellGuidSet::const_iterator i_guid = guid_set.begin(); i_guid != guid_set.end(); ++i_guid)
{
// Don't spawn at all if there's a respawn timer
ObjectGuid::LowType guid = *i_guid;
time_t now = GameTime::GetGameTime().count();
if (map->GetGORespawnTime(guid) > now)
continue;
GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject();
+86 -81
View File
@@ -49,19 +49,20 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket& /*recvData*/)
void WorldSession::HandleMoveWorldportAck()
{
Player* player = GetPlayer();
// ignore unexpected far teleports
if (!GetPlayer()->IsBeingTeleportedFar())
if (!player->IsBeingTeleportedFar())
return;
GetPlayer()->SetSemaphoreTeleportFar(0);
player->SetSemaphoreTeleportFar(0);
// get the teleport destination
WorldLocation const& loc = GetPlayer()->GetTeleportDest();
WorldLocation const& loc = player->GetTeleportDest();
// possible errors in the coordinate validity check
if (!MapMgr::IsValidMapCoord(loc))
{
KickPlayer("!MapMgr::IsValidMapCoord(loc)");
LogoutPlayer(false);
return;
}
@@ -69,198 +70,202 @@ void WorldSession::HandleMoveWorldportAck()
MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId());
InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId());
Map* oldMap = GetPlayer()->GetMap();
if (GetPlayer()->IsInWorld())
Map* oldMap = player->GetMap();
if (player->IsInWorld())
{
LOG_ERROR("network.opcode", "Player (Name {}) is still in world when teleported from map {} to new map {}", GetPlayer()->GetName(), oldMap->GetId(), loc.GetMapId());
oldMap->RemovePlayerFromMap(GetPlayer(), false);
LOG_ERROR("network.opcode", "Player (Name {}) is still in world when teleported from map {} to new map {}", player->GetName(), oldMap->GetId(), loc.GetMapId());
oldMap->RemovePlayerFromMap(player, false);
}
// reset instance validity, except if going to an instance inside an instance
if (!GetPlayer()->m_InstanceValid && !mInstance)
if (!player->m_InstanceValid && !mInstance)
{
GetPlayer()->m_InstanceValid = true;
player->m_InstanceValid = true;
// pussywizard: m_InstanceValid can be false only by leaving a group in an instance => so remove temp binds that could not be removed because player was still on the map!
if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty()))
sInstanceSaveMgr->PlayerUnbindInstance(GetPlayer()->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true);
if (!sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty()))
sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), oldMap->GetId(), oldMap->GetDifficulty(), true);
}
// relocate the player to the teleport destination
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), player);
// the CanEnter checks are done in TeleporTo but conditions may change
// while the player is in transit, for example the map may get full
if (!newMap || newMap->CannotEnter(GetPlayer(), false))
if (!newMap || newMap->CannotEnter(player, false))
{
LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString());
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
LOG_ERROR("network.opcode", "Map {} could not be created for player {}, porting player to homebind", loc.GetMapId(), player->GetGUID().ToString());
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO);
return;
}
float z = loc.GetPositionZ() + GetPlayer()->GetHoverHeight();
GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
float z = loc.GetPositionZ() + player->GetHoverHeight();
player->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
GetPlayer()->ResetMap();
GetPlayer()->SetMap(newMap);
player->ResetMap();
player->SetMap(newMap);
GetPlayer()->UpdatePositionData();
player->UpdatePositionData();
GetPlayer()->SendInitialPacketsBeforeAddToMap();
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
player->SendInitialPacketsBeforeAddToMap();
if (!player->GetMap()->AddPlayerToMap(player))
{
LOG_ERROR("network.opcode", "WORLD: failed to teleport player {} ({}) to map {} because of unknown reason!",
GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString(), loc.GetMapId());
GetPlayer()->ResetMap();
GetPlayer()->SetMap(oldMap);
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->m_homebindO);
player->GetName(), player->GetGUID().ToString(), loc.GetMapId());
player->ResetMap();
player->SetMap(oldMap);
player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->m_homebindO);
return;
}
oldMap->AfterPlayerUnlinkFromMap();
// pussywizard: transport teleport couldn't teleport us to the same map (some other teleport pending, reqs not met, etc.), but we still have transport set until player moves! clear it if map differs (crashfix)
if (Transport* t = _player->GetTransport())
if (!t->IsInMap(_player))
if (Transport* t = player->GetTransport())
if (!t->IsInMap(player))
{
t->RemovePassenger(_player);
_player->m_transport = nullptr;
_player->m_movementInfo.transport.Reset();
_player->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
t->RemovePassenger(player);
player->m_transport = nullptr;
player->m_movementInfo.transport.Reset();
player->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
if (!_player->getHostileRefMgr().IsEmpty())
_player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix
if (!player->getHostileRefMgr().IsEmpty())
player->getHostileRefMgr().deleteReferences(true); // pussywizard: multithreading crashfix
CellCoord pair(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()));
CellCoord pair(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()));
Cell cell(pair);
if (!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid())
{
KickPlayer("!GridCoord(cell.GridX(), cell.GridY()).IsCoordValid()");
LogoutPlayer(false);
return;
}
newMap->LoadGrid(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY()))
newMap->LoadGrid(player->GetPositionX(), player->GetPositionY());
// pussywizard: player supposed to enter bg map
if (_player->InBattleground())
if (player->InBattleground())
{
// but landed on another map, cleanup data
if (!mEntry->IsBattlegroundOrArena())
_player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
// everything ok
else if (Battleground* bg = _player->GetBattleground())
else if (Battleground* bg = player->GetBattleground())
{
if (_player->IsInvitedForBattlegroundInstance()) // GMs are not invited, so they are not added to participants
bg->AddPlayer(_player);
if (player->IsInvitedForBattlegroundInstance()) // GMs are not invited, so they are not added to participants
bg->AddPlayer(player);
}
}
// pussywizard: arena spectator stuff
{
if (newMap->IsBattleArena() && ((BattlegroundMap*)newMap)->GetBG() && _player->HasPendingSpectatorForBG(((BattlegroundMap*)newMap)->GetInstanceId()))
if (newMap->IsBattleArena() && ((BattlegroundMap*)newMap)->GetBG() && player->HasPendingSpectatorForBG(((BattlegroundMap*)newMap)->GetInstanceId()))
{
_player->ClearReceivedSpectatorResetFor();
_player->SetIsSpectator(true);
ArenaSpectator::SendCommand(_player, "%sENABLE", SPECTATOR_ADDON_PREFIX);
((BattlegroundMap*)newMap)->GetBG()->AddSpectator(_player);
ArenaSpectator::HandleResetCommand(_player);
player->ClearReceivedSpectatorResetFor();
player->SetIsSpectator(true);
ArenaSpectator::SendCommand(player, "%sENABLE", SPECTATOR_ADDON_PREFIX);
((BattlegroundMap*)newMap)->GetBG()->AddSpectator(player);
ArenaSpectator::HandleResetCommand(player);
}
else
_player->SetIsSpectator(false);
player->SetIsSpectator(false);
GetPlayer()->SetPendingSpectatorForBG(0);
player->SetPendingSpectatorForBG(0);
if (uint32 inviteInstanceId = _player->GetPendingSpectatorInviteInstanceId())
if (uint32 inviteInstanceId = player->GetPendingSpectatorInviteInstanceId())
{
if (Battleground* tbg = sBattlegroundMgr->GetBattleground(inviteInstanceId, BATTLEGROUND_TYPE_NONE))
tbg->RemoveToBeTeleported(_player->GetGUID());
_player->SetPendingSpectatorInviteInstanceId(0);
tbg->RemoveToBeTeleported(player->GetGUID());
player->SetPendingSpectatorInviteInstanceId(0);
}
}
// xinef: do this again, player can be teleported inside bg->AddPlayer(_player)!!!!
CellCoord pair2(Acore::ComputeCellCoord(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()));
// xinef: do this again, player can be teleported inside bg->AddPlayer(player)!!!!
CellCoord pair2(Acore::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()));
Cell cell2(pair2);
if (!GridCoord(cell2.GridX(), cell2.GridY()).IsCoordValid())
{
KickPlayer("!GridCoord(cell2.GridX(), cell2.GridY()).IsCoordValid()");
return;
}
newMap->LoadGrid(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY());
GetPlayer()->SendInitialPacketsAfterAddToMap();
if (!newMap->IsGridLoaded(player->GetPositionX(), player->GetPositionY()))
newMap->LoadGrid(player->GetPositionX(), player->GetPositionY());
player->SendInitialPacketsAfterAddToMap();
// flight fast teleport case
if (GetPlayer()->IsInFlight())
if (player->IsInFlight())
{
if (!GetPlayer()->InBattleground())
if (!player->InBattleground())
{
// short preparations to continue flight
MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->top();
movementGenerator->Initialize(GetPlayer());
MovementGenerator* movementGenerator = player->GetMotionMaster()->top();
movementGenerator->Initialize(player);
return;
}
// battleground state prepare, stop flight
GetPlayer()->GetMotionMaster()->MovementExpired();
GetPlayer()->CleanupAfterTaxiFlight();
player->GetMotionMaster()->MovementExpired();
player->CleanupAfterTaxiFlight();
}
// resurrect character at enter into instance where his corpse exist after add to map
Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID());
Corpse* corpse = player->GetMap()->GetCorpseByPlayer(player->GetGUID());
if (corpse && corpse->GetType() != CORPSE_BONES)
{
if (mEntry->IsDungeon())
{
GetPlayer()->ResurrectPlayer(0.5f);
GetPlayer()->SpawnCorpseBones();
player->ResurrectPlayer(0.5f);
player->SpawnCorpseBones();
}
}
if (!corpse && mEntry->IsDungeon())
{
// resurrect character upon entering instance when the corpse is not available anymore
if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->MapID)
if (player->GetCorpseLocation().GetMapId() == mEntry->MapID)
{
GetPlayer()->ResurrectPlayer(0.5f);
GetPlayer()->RemoveCorpse();
player->ResurrectPlayer(0.5f);
player->RemoveCorpse();
}
}
bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena();
if (mInstance)
{
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
Difficulty diff = player->GetDifficulty(mEntry->IsRaid());
if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
if (mapDiff->resetTime)
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff))
{
uint32 timeleft = uint32(timeReset - GameTime::GetGameTime().count());
GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
player->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
}
allowMount = mInstance->AllowMount;
}
// mount allow check
if (!allowMount)
_player->RemoveAurasByType(SPELL_AURA_MOUNTED);
player->RemoveAurasByType(SPELL_AURA_MOUNTED);
// update zone immediately, otherwise leave channel will cause crash in mtmap
uint32 newzone, newarea;
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
GetPlayer()->UpdateZone(newzone, newarea);
player->GetZoneAndAreaId(newzone, newarea);
player->UpdateZone(newzone, newarea);
// honorless target
if (GetPlayer()->pvpInfo.IsHostile)
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
if (player->pvpInfo.IsHostile)
player->CastSpell(player, 2479, true);
// in friendly area
else if (GetPlayer()->IsPvP() && !GetPlayer()->HasPlayerFlag(PLAYER_FLAGS_IN_PVP))
GetPlayer()->UpdatePvP(false, false);
else if (player->IsPvP() && !player->HasPlayerFlag(PLAYER_FLAGS_IN_PVP))
player->UpdatePvP(false, false);
// resummon pet
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
player->ResummonPetTemporaryUnSummonedIfAny();
//lets process all delayed operations on successful teleport
GetPlayer()->ProcessDelayedOperations();
player->ProcessDelayedOperations();
}
void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
+61 -67
View File
@@ -69,6 +69,11 @@ Map::~Map()
sScriptMgr->OnDestroyMap(this);
// Delete all waiting spawns, else there will be a memory leak
// This doesn't delete from database.
_creatureRespawnTimes.clear();
_goRespawnTimes.clear();
while (!i_worldObjects.empty())
{
WorldObject* obj = *i_worldObjects.begin();
@@ -237,7 +242,7 @@ void Map::LoadMapAndVMap(int gx, int gy)
}
}
Map::Map(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
_creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false),
i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0),
@@ -440,6 +445,9 @@ void Map::DeleteFromWorld(Player* player)
void Map::EnsureGridCreated(const GridCoord& p)
{
if (getNGrid(p.x_coord, p.y_coord))
return;
std::lock_guard<std::mutex> guard(GridLock);
EnsureGridCreated_i(p);
}
@@ -493,13 +501,13 @@ bool Map::EnsureGridLoaded(const Cell& cell)
NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
ASSERT(grid);
if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
if (!grid->isGridObjectDataLoaded())
{
//if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
//{
LOG_DEBUG("maps", "Loading grid[{}, {}] for map {} instance {}", cell.GridX(), cell.GridY(), GetId(), i_InstanceId);
setGridObjectDataLoaded(true, cell.GridX(), cell.GridY());
grid->setGridObjectDataLoaded(true);
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
@@ -685,15 +693,7 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
return false; //Should delete object
}
Cell cell(cellCoord);
if (obj->isActiveObject())
EnsureGridLoaded(cell);
obj->AddToWorld();
if (obj->isActiveObject())
AddToActive(obj);
_transports.insert(obj);
// Broadcast creation to players
@@ -717,7 +717,8 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
bool Map::IsGridLoaded(const GridCoord& p) const
{
return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord));
NGridType* grid = getNGrid(p.x_coord, p.y_coord);
return grid && grid->isGridObjectDataLoaded();
}
void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
@@ -746,7 +747,7 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
markCell(cell_id);
CellCoord pair(x, y);
Cell cell(pair);
//cell.SetNoCreate(); // in mmaps this is missing
cell.SetNoCreate();
Visit(cell, gridVisitor);
Visit(cell, worldVisitor);
@@ -786,18 +787,6 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
std::vector<Creature*> updateList;
updateList.reserve(10);
// non-player active objects, increasing iterator in the loop in case of object removal
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
{
WorldObject* obj = *m_activeNonPlayersIter;
++m_activeNonPlayersIter;
if (!obj || !obj->IsInWorld())
continue;
VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
}
// the player iterator is stored in the map object
// to make sure calls to Map::Remove don't invalidate it
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
@@ -836,6 +825,18 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
}
}
// non-player active objects, increasing iterator in the loop in case of object removal
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
{
WorldObject* obj = *m_activeNonPlayersIter;
++m_activeNonPlayersIter;
if (!obj || !obj->IsInWorld())
continue;
VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
}
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) // pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok
{
MotionTransport* transport = *_transportsUpdateIter;
@@ -1015,8 +1016,6 @@ template<>
void Map::RemoveFromMap(MotionTransport* obj, bool remove)
{
obj->RemoveFromWorld();
if (obj->isActiveObject())
RemoveFromActive(obj);
Map::PlayerList const& players = GetPlayers();
if (!players.IsEmpty())
@@ -1060,6 +1059,10 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o)
Cell old_cell(player->GetPositionX(), player->GetPositionY());
Cell new_cell(x, y);
player->Relocate(x, y, z, o);
if (player->IsVehicle())
player->GetVehicleKit()->RelocatePassengers();
if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
{
LOG_DEBUG("maps", "Player {} relocation grid[{}, {}]cell[{}, {}]->grid[{}, {}]cell[{}, {}]", player->GetName().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
@@ -1072,64 +1075,63 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o)
AddToGrid(player, new_cell);
}
player->Relocate(x, y, z, o);
if (player->IsVehicle())
player->GetVehicleKit()->RelocatePassengers();
player->UpdatePositionData();
player->UpdateObjectVisibility(false);
}
void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float o)
void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float o, bool respawnRelocationOnFail)
{
Cell old_cell = creature->GetCurrentCell();
Cell new_cell(x, y);
if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
return;
// delay creature move for grid/cell to grid/cell moves
if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
{
if (old_cell.DiffGrid(new_cell))
EnsureGridLoaded(new_cell);
#ifdef ACORE_DEBUG
LOG_DEBUG("maps", "Creature {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", creature->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
#endif
AddCreatureToMoveList(creature, x, y, z, o);
// in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList
}
else
{
RemoveCreatureFromMoveList(creature);
}
creature->Relocate(x, y, z, o);
if (creature->IsVehicle())
creature->GetVehicleKit()->RelocatePassengers();
creature->UpdatePositionData();
creature->UpdateObjectVisibility(false);
creature->UpdatePositionData();
RemoveCreatureFromMoveList(creature);
}
}
void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float o)
void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float o, bool respawnRelocationOnFail)
{
Cell old_cell = go->GetCurrentCell();
Cell new_cell(x, y);
if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
return;
// delay creature move for grid/cell to grid/cell moves
if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
{
if (old_cell.DiffGrid(new_cell))
EnsureGridLoaded(new_cell);
#ifdef ACORE_DEBUG
LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", go->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
#endif
AddGameObjectToMoveList(go, x, y, z, o);
// in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList
}
else
{
RemoveGameObjectFromMoveList(go);
}
go->Relocate(x, y, z, o);
go->UpdateModelPosition();
go->SetPositionDataUpdate();
go->UpdateObjectVisibility(false);
RemoveGameObjectFromMoveList(go);
}
}
void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float z, float o)
@@ -1137,24 +1139,25 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
Cell old_cell = dynObj->GetCurrentCell();
Cell new_cell(x, y);
if (!getNGrid(new_cell.GridX(), new_cell.GridY()))
return;
// delay creature move for grid/cell to grid/cell moves
if (old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell))
{
if (old_cell.DiffGrid(new_cell))
EnsureGridLoaded(new_cell);
#ifdef ACORE_DEBUG
LOG_DEBUG("maps", "GameObject {} added to moving list from grid[{}, {}]cell[{}, {}] to grid[{}, {}]cell[{}, {}].", dynObj->GetGUID().ToString().c_str(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
#endif
AddDynamicObjectToMoveList(dynObj, x, y, z, o);
// in diffcell/diffgrid case notifiers called at finishing move dynObj in Map::MoveAllGameObjectsInMoveList
}
else
{
RemoveDynamicObjectFromMoveList(dynObj);
}
dynObj->Relocate(x, y, z, o);
dynObj->SetPositionDataUpdate();
dynObj->UpdateObjectVisibility(false);
RemoveDynamicObjectFromMoveList(dynObj);
}
}
void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang)
@@ -3150,11 +3153,14 @@ void Map::RemoveAllObjectsInRemoveList()
RemoveFromMap((DynamicObject*)obj, true);
break;
case TYPEID_GAMEOBJECT:
if (MotionTransport* transport = obj->ToGameObject()->ToMotionTransport())
{
GameObject* go = obj->ToGameObject();
if (MotionTransport* transport = go->ToMotionTransport())
RemoveFromMap(transport, true);
else
RemoveFromMap(obj->ToGameObject(), true);
RemoveFromMap(go, true);
break;
}
case TYPEID_UNIT:
// in case triggered sequence some spell can continue casting after prev CleanupsBeforeDelete call
// make sure that like sources auras/etc removed before destructor start
@@ -3258,12 +3264,6 @@ void Map::AddToActive(DynamicObject* d)
AddToActiveHelper(d);
}
template<>
void Map::AddToActive(GameObject* d)
{
AddToActiveHelper(d);
}
template<class T>
void Map::RemoveFromActive(T* obj)
{
@@ -3298,12 +3298,6 @@ void Map::RemoveFromActive(DynamicObject* obj)
RemoveFromActiveHelper(obj);
}
template<>
void Map::RemoveFromActive(GameObject* obj)
{
RemoveFromActiveHelper(obj);
}
template bool Map::AddToMap(Corpse*, bool);
template bool Map::AddToMap(Creature*, bool);
template bool Map::AddToMap(GameObject*, bool);
@@ -3316,7 +3310,7 @@ template void Map::RemoveFromMap(DynamicObject*, bool);
/* ******* Dungeon Instance Maps ******* */
InstanceMap::InstanceMap(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
: Map(id, expiry, InstanceId, SpawnMode, _parent),
m_resetAfterUnload(false), m_unloadWhenEmpty(false),
instance_data(nullptr), i_script_id(0)
@@ -3726,7 +3720,7 @@ uint32 InstanceMap::GetMaxResetDelay() const
/* ******* Battleground Instance Maps ******* */
BattlegroundMap::BattlegroundMap(uint32 id, std::chrono::seconds expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode)
BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode)
: Map(id, expiry, InstanceId, spawnMode, _parent), m_bg(nullptr)
{
//lets initialize visibility distance for BG/Arenas
+19 -15
View File
@@ -311,7 +311,7 @@ class Map : public GridRefMgr<NGridType>
{
friend class MapReference;
public:
Map(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = nullptr);
~Map() override;
[[nodiscard]] MapEntry const* GetEntry() const { return i_mapEntry; }
@@ -346,12 +346,18 @@ public:
virtual void InitVisibilityDistance();
void PlayerRelocation(Player*, float x, float y, float z, float o);
void CreatureRelocation(Creature* creature, float x, float y, float z, float o);
void GameObjectRelocation(GameObject* go, float x, float y, float z, float o);
void CreatureRelocation(Creature* creature, float x, float y, float z, float o, bool respawnRelocationOnFail = true);
void GameObjectRelocation(GameObject* go, float x, float y, float z, float o, bool respawnRelocationOnFail = true);
void DynamicObjectRelocation(DynamicObject* go, float x, float y, float z, float o);
template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER>& visitor);
[[nodiscard]] bool IsActiveGrid(float x, float y) const
{
GridCoord p = Acore::ComputeGridCoord(x, y);
return !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_ACTIVE;
}
[[nodiscard]] bool IsRemovalGrid(float x, float y) const
{
GridCoord p = Acore::ComputeGridCoord(x, y);
@@ -374,10 +380,10 @@ public:
void ResetGridExpiry(NGridType& grid, float factor = 1) const
{
grid.ResetTimeTracker(std::chrono::duration_cast<std::chrono::seconds>(i_gridExpiry * factor));
grid.ResetTimeTracker(time_t(float(i_gridExpiry) * factor));
}
[[nodiscard]] std::chrono::seconds GetGridExpiry(void) const { return i_gridExpiry; }
[[nodiscard]] time_t GetGridExpiry(void) const { return i_gridExpiry; }
[[nodiscard]] uint32 GetId() const { return i_mapEntry->MapID; }
static void InitStateMachine();
@@ -702,9 +708,6 @@ private:
}
bool EnsureGridLoaded(Cell const&);
[[nodiscard]] bool isGridObjectDataLoaded(uint32 x, uint32 y) const { return getNGrid(x, y)->isGridObjectDataLoaded(); }
void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x, y)->setGridObjectDataLoaded(pLoaded); }
void setNGrid(NGridType* grid, uint32 x, uint32 y);
void ScriptsProcess();
@@ -750,7 +753,7 @@ private:
void _ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const;
GameObject* _FindGameObject(WorldObject* pWorldObject, ObjectGuid::LowType guid) const;
std::chrono::seconds i_gridExpiry;
time_t i_gridExpiry;
//used for fast base_map (e.g. MapInstanced class object) search for
//InstanceMaps and BattlegroundMaps...
@@ -839,7 +842,7 @@ enum InstanceResetMethod
class InstanceMap : public Map
{
public:
InstanceMap(uint32 id, std::chrono::seconds, uint32 InstanceId, uint8 SpawnMode, Map* _parent);
InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent);
~InstanceMap() override;
bool AddPlayerToMap(Player*) override;
void RemovePlayerFromMap(Player*, bool) override;
@@ -873,7 +876,7 @@ private:
class BattlegroundMap : public Map
{
public:
BattlegroundMap(uint32 id, std::chrono::seconds, uint32 InstanceId, Map* _parent, uint8 spawnMode);
BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode);
~BattlegroundMap() override;
bool AddPlayerToMap(Player*) override;
@@ -898,11 +901,12 @@ inline void Map::Visit(Cell const& cell, TypeContainerVisitor<T, CONTAINER>& vis
const uint32 cell_x = cell.CellX();
const uint32 cell_y = cell.CellY();
if (!cell.NoCreate() || IsGridLoaded(GridCoord(x, y)))
{
if (!cell.NoCreate())
EnsureGridLoaded(cell);
getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor);
}
NGridType* grid = getNGrid(x, y);
if (grid && grid->isGridObjectDataLoaded())
grid->VisitGrid(cell_x, cell_y, visitor);
}
#endif
+11 -1
View File
@@ -25,8 +25,9 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "VMapFactory.h"
#include "VMapMgr2.h"
MapInstanced::MapInstanced(uint32 id, std::chrono::seconds expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL)
MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL)
{
// fill with zero
memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS * sizeof(uint16));
@@ -260,6 +261,15 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator& itr)
sScriptMgr->OnDestroyInstance(this, itr->second);
itr->second->UnloadAll();
// should only unload VMaps if this is the last instance
if (m_InstancedMaps.size() <= 1)
{
VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(itr->second->GetId());
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(itr->second->GetId());
// in that case, unload grids of the base map, too
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
Map::UnloadAll();
}
// erase map
delete itr->second;
+1 -1
View File
@@ -28,7 +28,7 @@ class MapInstanced : public Map
public:
using InstancedMaps = std::unordered_map<uint32, Map*>;
MapInstanced(uint32 id, std::chrono::seconds expiry);
MapInstanced(uint32 id, time_t expiry);
~MapInstanced() override {}
// functions overwrite Map versions
+2 -2
View File
@@ -84,10 +84,10 @@ Map* MapMgr::CreateBaseMap(uint32 id)
ASSERT(entry);
if (entry->Instanceable())
map = new MapInstanced(id, std::chrono::seconds(i_gridCleanUpDelay));
map = new MapInstanced(id, i_gridCleanUpDelay);
else
{
map = new Map(id, std::chrono::seconds(i_gridCleanUpDelay), 0, REGULAR_DIFFICULTY);
map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY);
map->LoadRespawnTimes();
map->LoadCorpseData();
}
-2
View File
@@ -411,8 +411,6 @@ MotionTransport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType
if (map && map->IsDungeon())
trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
// xinef: transports are active so passengers can be relocated (grids must be loaded)
trans->setActive(true);
HashMapHolder<MotionTransport>::Insert(trans);
trans->GetMap()->AddToMap<MotionTransport>(trans);
return trans;
@@ -1,28 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DynamicVisibility.h"
uint8 DynamicVisibilityMgr::visibilitySettingsIndex = 0;
void DynamicVisibilityMgr::Update(uint32 sessionCount)
{
if (sessionCount >= (visibilitySettingsIndex + 1) * ((uint32)VISIBILITY_SETTINGS_PLAYER_INTERVAL) && visibilitySettingsIndex < VISIBILITY_SETTINGS_MAX_INTERVAL_NUM - 1)
++visibilitySettingsIndex;
else if (visibilitySettingsIndex && sessionCount < visibilitySettingsIndex * ((uint32)VISIBILITY_SETTINGS_PLAYER_INTERVAL) - 100)
--visibilitySettingsIndex;
}
-58
View File
@@ -1,58 +0,0 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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
+40 -6
View File
@@ -125,14 +125,13 @@ namespace Movement
if (args.flags.cyclic)
{
uint32 cyclic_point = 0;
// MoveSplineFlag::Enter_Cycle support dropped
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
//cyclic_point = 1; // shouldn't be modified, came from client
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
if (splineflags.enter_cycle)
cyclic_point = 1; // shouldn't be modified, came from client
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point, args.initialOrientation);
}
else
{
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], args.initialOrientation);
}
// init spline timestamps
@@ -204,7 +203,7 @@ namespace Movement
if (!(exp)) \
{ \
if (unit) \
LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for {}", #exp, unit->GetGUID().ToString()); \
LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for GUID: {} Entry: {}", #exp, unit->GetGUID().ToString().c_str(), unit->GetEntry());\
else \
LOG_ERROR("misc.movesplineinitargs", "MoveSplineInitArgs::Validate: expression '{}' failed for cyclic spline continuation", #exp); \
return false;\
@@ -273,6 +272,41 @@ namespace Movement
point_Idx = spline.first();
time_passed = time_passed % Duration();
result = Movement::MoveSpline::UpdateResult(Result_NextCycle | Result_JustArrived);
// Remove first point from the path after one full cycle.
// That point was the position of the unit prior to entering the cycle and it shouldn't be repeated with continuous cycles.
if (splineflags.enter_cycle)
{
splineflags.enter_cycle = false;
MoveSplineInitArgs args{ (size_t)spline.getPointCount() };
args.path.assign(spline.getPoints().begin() + spline.first() + 1, spline.getPoints().begin() + spline.last());
args.facing = facing;
args.flags = splineflags;
args.path_Idx_offset = point_Idx_offset;
// MoveSplineFlag::Parabolic | MoveSplineFlag::Animation not supported currently
//args.parabolic_amplitude = ?;
//args.time_perc = ?;
args.splineId = m_Id;
args.initialOrientation = initialOrientation;
args.velocity = 1.0f; // Calculated below
args.HasVelocity = true;
args.TransformForTransport = onTransport;
if (args.Validate(nullptr))
{
// New cycle should preserve previous cycle's duration for some weird reason, even though
// the path is really different now. Blizzard is weird. Or this was just a simple oversight.
// Since our splines precalculate length with velocity in mind, if we want to find the desired
// velocity, we have to make a fake spline, calculate its duration and then compare it to the
// desired duration, thus finding out how much the velocity has to be increased for them to match.
MoveSpline tempSpline;
tempSpline.Initialize(args);
args.velocity = (float)tempSpline.Duration() / Duration();
if (args.Validate(nullptr))
init_spline(args);
}
}
}
else
{
@@ -87,6 +87,7 @@ namespace Movement
// corrent first vertex
args.path[0] = real_position;
args.initialOrientation = real_position.orientation;
args.flags.enter_cycle = args.flags.cyclic;
move_spline.onTransport = transport;
uint32 moveFlags = unit->m_movementInfo.GetMovementFlags();
@@ -67,10 +67,6 @@ namespace Movement
break;
}
// add fake Enter_Cycle flag - needed for client-side cyclic movement (client will erase first spline vertex after first cycle done)
// Xinef: this flag breaks cycle for ground movement, client teleports npc between last and first point instead of using smooth movement
if (splineflags & MoveSplineFlag::Flying)
splineflags.enter_cycle = move_spline.isCyclic();
data << uint32(splineflags & uint32(~MoveSplineFlag::Mask_No_Monster_Move));
if (splineflags.animation)
@@ -123,21 +119,12 @@ namespace Movement
data.append<Vector3>(&spline.getPoint(2), count);
}
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data, bool flying)
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 count = spline.getPointCount() - 3;
data << uint32(count + 1);
if (flying)
{
data << spline.getPoint(1); // fake point, client will erase it from the spline after first cycle done
uint32 count = spline.getPointCount() - 4;
data << count;
data.append<Vector3>(&spline.getPoint(2), count);
}
else
{
data.append<Vector3>(&spline.getPoint(2), count);
data << Vector3::zero(); //Xinef: fake point
}
}
void PacketBuilder::WriteMonsterMove(const MoveSpline& move_spline, ByteBuffer& data)
{
@@ -148,7 +135,7 @@ namespace Movement
if (splineflags & MoveSplineFlag::Mask_CatmullRom)
{
if (splineflags.cyclic)
WriteCatmullRomCyclicPath(spline, data, splineflags & MoveSplineFlag::Flying);
WriteCatmullRomCyclicPath(spline, data);
else
WriteCatmullRomPath(spline, data);
}
@@ -199,4 +186,8 @@ namespace Movement
data << (move_spline.isCyclic() ? Vector3::zero() : move_spline.FinalDestination());
}
}
void PacketBuilder::WriteSplineSync(MoveSpline const& move_spline, ByteBuffer& data)
{
data << (float)move_spline.timePassed() / move_spline.Duration();
}
}
@@ -38,6 +38,7 @@ namespace Movement
static void WriteMonsterMove(const MoveSpline& mov, ByteBuffer& data);
static void WriteStopMovement(Vector3 const& loc, uint32 splineId, ByteBuffer& data);
static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
static void WriteSplineSync(MoveSpline const& mov, ByteBuffer& data);
};
}
#endif // AC_PACKET_BUILDER_H
+11 -9
View File
@@ -199,23 +199,25 @@ namespace Movement
return length;
}
void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m)
void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation)
{
m_mode = m;
cyclic = false;
initialOrientation = orientation;
(this->*initializers[m_mode])(controls, count, cyclic, 0);
(this->*initializers[m_mode])(controls, count, 0);
}
void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point)
void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation)
{
m_mode = m;
cyclic = true;
initialOrientation = orientation;
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
(this->*initializers[m_mode])(controls, count, cyclic_point);
}
void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
void SplineBase::InitLinear(const Vector3* controls, index_type count, index_type cyclic_point)
{
ASSERT(count >= 2);
const int real_size = count + 1;
@@ -235,7 +237,7 @@ namespace Movement
index_hi = cyclic ? count : (count - 1);
}
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, index_type cyclic_point)
{
const int real_size = count + (cyclic ? (1 + 2) : (1 + 1));
@@ -253,14 +255,14 @@ namespace Movement
if (cyclic_point == 0)
points[0] = controls[count - 1];
else
points[0] = controls[0].lerp(controls[1], -1);
points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f };
points[high_index + 1] = controls[cyclic_point];
points[high_index + 2] = controls[cyclic_point + 1];
}
else
{
points[0] = controls[0].lerp(controls[1], -1);
points[0] = controls[0] - G3D::Vector3{ std::cos(initialOrientation), std::sin(initialOrientation), 0.0f };
points[high_index + 1] = controls[count - 1];
}
@@ -268,7 +270,7 @@ namespace Movement
index_hi = high_index + (cyclic ? 1 : 0);
}
void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
void SplineBase::InitBezier3(const Vector3* controls, index_type count, index_type /*cyclic_point*/)
{
index_type c = count / 3u * 3u;
index_type t = c / 3u;
+11 -10
View File
@@ -48,6 +48,7 @@ namespace Movement
uint8 m_mode{UninitializedMode};
bool cyclic{false};
float initialOrientation;
enum
{
@@ -77,15 +78,15 @@ namespace Movement
typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
static SegLenghtMethtod seglengths[ModesEnd];
void InitLinear(const Vector3*, index_type, bool, index_type);
void InitCatmullRom(const Vector3*, index_type, bool, index_type);
void InitBezier3(const Vector3*, index_type, bool, index_type);
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
void InitLinear(const Vector3*, index_type, index_type);
void InitCatmullRom(const Vector3*, index_type, index_type);
void InitBezier3(const Vector3*, index_type, index_type);
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, index_type);
static InitMethtod initializers[ModesEnd];
void UninitializedSplineEvaluationMethod(index_type, float, Vector3&) const { ABORT(); }
[[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); }
void UninitializedSplineInitMethod(Vector3 const*, index_type, bool, index_type) { ABORT(); }
[[nodiscard]] float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); return 0.0f; }
void UninitializedSplineInitMethod(Vector3 const*, index_type, index_type) { ABORT(); }
public:
explicit SplineBase() = default;
@@ -116,8 +117,8 @@ namespace Movement
[[nodiscard]] const Vector3& getPoint(index_type i) const { return points[i];}
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3* controls, index_type count, EvaluationMode m);
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point);
void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation);
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation);
/** As i can see there are a lot of ways how spline can be initialized
would be no harm to have some custom initializers. */
@@ -170,8 +171,8 @@ namespace Movement
void computeIndex(float t, index_type& out_idx, float& out_u) const;
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3* controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);}
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point);}
void init_spline(const Vector3* controls, index_type count, EvaluationMode m, float orientation = 0) { SplineBase::init_spline(controls, count, m, orientation);}
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point, float orientation = 0) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point, orientation);}
/** Initializes lengths with SplineBase::SegLength method. */
void initLengths();
@@ -2435,7 +2435,7 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo
*/
UnitList targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetVisibilityRange());
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, targets, u_check);
Cell::VisitAllObjects(target, searcher, target->GetMap()->GetVisibilityRange());
for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter)
+3 -3
View File
@@ -4048,7 +4048,7 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/)
}
UnitList targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, unitTarget->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, unitTarget->GetVisibilityRange());
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(unitTarget, targets, u_check);
Cell::VisitAllObjects(unitTarget, searcher, unitTarget->GetVisibilityRange());
for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter)
@@ -4787,7 +4787,7 @@ void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/)
WorldPacket data(SMSG_CLEAR_TARGET, 8);
data << m_caster->GetGUID();
float dist = m_caster->GetVisibilityRange() + VISIBILITY_COMPENSATION;
float dist = m_caster->GetVisibilityRange();
Acore::MessageDistDelivererToHostile notifier(m_caster, &data, dist);
Cell::VisitWorldObjects(m_caster, notifier, dist);
@@ -4812,7 +4812,7 @@ void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/)
return;
UnitList targets;
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, m_caster->GetVisibilityRange()); // no VISIBILITY_COMPENSATION, distance is enough
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, m_caster->GetVisibilityRange());
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(m_caster, targets, u_check);
Cell::VisitAllObjects(m_caster, searcher, m_caster->GetVisibilityRange());
for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter)
-3
View File
@@ -44,7 +44,6 @@
#include "DBCStores.h"
#include "DatabaseEnv.h"
#include "DisableMgr.h"
#include "DynamicVisibility.h"
#include "GameEventMgr.h"
#include "GameGraveyard.h"
#include "GameTime.h"
@@ -2255,8 +2254,6 @@ void World::Update(uint32 diff)
// Record update if recording set in log and diff is greater then minimum set in log
sWorldUpdateTime.RecordUpdateTime(GameTime::GetGameTimeMS(), diff, GetActiveSessionCount());
DynamicVisibilityMgr::Update(GetActiveSessionCount());
///- Update the different timers
for (int i = 0; i < WUPDATE_COUNT; ++i)
{
@@ -327,6 +327,7 @@ public:
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn))
{
nefarian->setActive(true);
nefarian->SetFarVisible(true);
nefarian->SetCanFly(true);
nefarian->SetDisableGravity(true);
nefarian->GetMotionMaster()->MovePath(NEFARIAN_PATH, false);
@@ -425,6 +425,7 @@ public:
{
nefarius->SetPhaseMask(1, true);
nefarius->setActive(true);
nefarius->SetFarVisible(true);
nefarius->Respawn();
nefarius->GetMotionMaster()->MoveTargetedHome();
}
@@ -105,6 +105,7 @@ struct boss_nightbane : public BossAI
me->SetDisableGravity(_intro);
me->SetWalk(false);
me->setActive(true);
me->SetFarVisible(true);
if (instance)
{
@@ -55,6 +55,7 @@ public:
void Reset() override
{
me->setActive(true);
me->SetFarVisible(true);
me->SetVisible(false);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetCanFly(true);
@@ -347,6 +347,7 @@ void hyjalAI::Reset()
{
IsDummy = false;
me->setActive(true);
me->SetFarVisible(true);
// GUIDs
PlayerGUID.Clear();
BossGUID[0].Clear();
@@ -493,6 +494,7 @@ void hyjalAI::SummonCreature(uint32 entry, float Base[4][3])
creature->SetWalk(false);
creature->setActive(true);
creature->SetFarVisible(true);
switch (entry)
{
case NECROMANCER:
@@ -1021,6 +1023,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
for (uint8 i = 0; i < 3; ++i)//summon 3 abominations
@@ -1033,6 +1036,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
for (uint8 i = 0; i < 5; ++i)//summon 5 gargoyles
@@ -1045,6 +1049,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
break;
@@ -1062,6 +1067,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
for (uint8 i = 0; i < 25; ++i)//summon 25 ghouls
@@ -1074,6 +1080,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
for (uint8 i = 0; i < 5; ++i)//summon 5 abominations
@@ -1086,6 +1093,7 @@ void hyjalAI::DoOverrun(uint32 faction, const uint32 diff)
CAST_AI(hyjal_trashAI, unit->AI())->IsOverrun = true;
CAST_AI(hyjal_trashAI, unit->AI())->OverrunType = i;
unit->setActive(true);
unit->SetFarVisible(true);
}
}
break;
@@ -389,6 +389,7 @@ public:
if (action == ACTION_BALTHARUS_DEATH)
{
me->setActive(true);
me->SetFarVisible(true);
_isIntro = false;
_events.ScheduleEvent(EVENT_XERESTRASZA_EVENT_0, 6s);
@@ -339,6 +339,7 @@ public:
events.ScheduleEvent(EVENT_ICY_GRIP, 33s + 500ms, EVENT_GROUP_LAND_PHASE);
me->setActive(true);
me->SetFarVisible(true);
me->SetInCombatWithZone();
instance->SetBossState(DATA_SINDRAGOSA, IN_PROGRESS);
@@ -377,6 +378,7 @@ public:
return;
me->setActive(true);
me->SetFarVisible(true);
me->SetDisableGravity(true);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetSpeed(MOVE_RUN, 4.28571f);
@@ -1407,6 +1409,7 @@ public:
return;
me->setActive(true);
me->SetFarVisible(true);
me->SetImmuneToPC(true);
float moveTime = me->GetExactDist(&SpinestalkerFlyPos) / (me->GetSpeed(MOVE_RUN) * 0.001f);
me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, SpinestalkerLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250));
@@ -1423,6 +1426,7 @@ public:
return;
me->setActive(false);
me->SetFarVisible(false);
me->SetDisableGravity(false);
me->SetHomePosition(SpinestalkerLandPos);
me->SetFacingTo(SpinestalkerLandPos.GetOrientation());
@@ -1538,6 +1542,7 @@ public:
return;
me->setActive(true);
me->SetFarVisible(true);
me->SetImmuneToPC(true);
float moveTime = me->GetExactDist(&RimefangFlyPos) / (me->GetSpeed(MOVE_RUN) * 0.001f);
me->m_Events.AddEvent(new FrostwyrmLandEvent(*me, RimefangLandPos), me->m_Events.CalculateTime(uint64(moveTime) + 250));
@@ -1556,6 +1561,8 @@ public:
if (point == POINT_FROSTWYRM_LAND)
{
me->setActive(false);
me->SetFarVisible(false);
me->SetFarVisible(false);
me->SetDisableGravity(false);
me->SetHomePosition(RimefangLandPos);
me->SetFacingTo(RimefangLandPos.GetOrientation());
@@ -484,6 +484,7 @@ public:
uint32 introDelay = 0;
me->setActive(true);
me->SetFarVisible(true);
me->SetInCombatWithZone();
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToNPC(true);
@@ -175,6 +175,7 @@ public:
{
me->SetDisableGravity(true);
me->setActive(true);
me->SetFarVisible(true);
Reset();
}
@@ -517,6 +517,7 @@ public:
if (m_pInstance && !_encounterFinished)
m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS);
me->setActive(true);
me->SetFarVisible(true);
DisableThorim(true);
me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true);
//me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true);