mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
feat(Core/Maps): Improve map object updater (#22392)
This commit is contained in:
@@ -1419,18 +1419,6 @@ CheckGameObjectLoS = 1
|
|||||||
|
|
||||||
PreloadAllNonInstancedMapGrids = 0
|
PreloadAllNonInstancedMapGrids = 0
|
||||||
|
|
||||||
#
|
|
||||||
# SetAllCreaturesWithWaypointMovementActive
|
|
||||||
# Description: Set all creatures with waypoint movement active. This means that they will start
|
|
||||||
# movement once they are loaded (which happens on grid load) and keep moving even
|
|
||||||
# when no player is near. This will increase CPU usage significantly and can be
|
|
||||||
# used with enabled "PreloadAllNonInstancedMapGrids" to start waypoint movement on
|
|
||||||
# server startup.
|
|
||||||
# Default: 0 - (Disabled)
|
|
||||||
# 1 - (Enabled)
|
|
||||||
|
|
||||||
SetAllCreaturesWithWaypointMovementActive = 0
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# DontCacheRandomMovementPaths
|
# DontCacheRandomMovementPaths
|
||||||
# Description: Random movement paths (calculated using MoveMaps) can be cached to save cpu time,
|
# Description: Random movement paths (calculated using MoveMaps) can be cached to save cpu time,
|
||||||
|
|||||||
@@ -2772,11 +2772,7 @@ bool Creature::LoadCreaturesAddon(bool reload)
|
|||||||
|
|
||||||
//Load Path
|
//Load Path
|
||||||
if (cainfo->path_id != 0)
|
if (cainfo->path_id != 0)
|
||||||
{
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_SET_ALL_CREATURES_WITH_WAYPOINT_MOVEMENT_ACTIVE))
|
|
||||||
setActive(true);
|
|
||||||
m_path_id = cainfo->path_id;
|
m_path_id = cainfo->path_id;
|
||||||
}
|
|
||||||
|
|
||||||
if (!cainfo->auras.empty())
|
if (!cainfo->auras.empty())
|
||||||
{
|
{
|
||||||
@@ -3896,3 +3892,27 @@ std::string Creature::GetDebugInfo() const
|
|||||||
<< " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
|
<< " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
|
||||||
return sstr.str();
|
return sstr.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: This is called in a tight (heavy) loop, is it critical that all checks are FAST and are hopefully only simple conditionals.
|
||||||
|
bool Creature::IsUpdateNeeded()
|
||||||
|
{
|
||||||
|
if (WorldObject::IsUpdateNeeded())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (GetMap()->isCellMarked(GetCurrentCell().GetCellCoord().GetId()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (IsInCombat())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (IsVisibilityOverridden())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (GetMotionMaster()->HasMovementGeneratorType(WAYPOINT_MOTION_TYPE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (HasUnitState(UNIT_STATE_EVADE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class CreatureGroup;
|
|||||||
|
|
||||||
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
|
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
|
||||||
|
|
||||||
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject
|
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject, public UpdatableMapObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Creature(bool isWorldObject = false);
|
explicit Creature(bool isWorldObject = false);
|
||||||
@@ -436,6 +436,8 @@ public:
|
|||||||
|
|
||||||
std::string GetDebugInfo() const override;
|
std::string GetDebugInfo() const override;
|
||||||
|
|
||||||
|
bool IsUpdateNeeded() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
|
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
|
||||||
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
|
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ enum DynamicObjectType
|
|||||||
DYNAMIC_OBJECT_FARSIGHT_FOCUS = 0x2,
|
DYNAMIC_OBJECT_FARSIGHT_FOCUS = 0x2,
|
||||||
};
|
};
|
||||||
|
|
||||||
class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MovableMapObject
|
class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MovableMapObject, public UpdatableMapObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DynamicObject(bool isWorldObject);
|
DynamicObject(bool isWorldObject);
|
||||||
|
|||||||
@@ -3076,3 +3076,21 @@ std::string GameObject::GetDebugInfo() const
|
|||||||
<< "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
|
<< "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
|
||||||
return sstr.str();
|
return sstr.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: This is called in a tight (heavy) loop, is it critical that all checks are FAST and are hopefully only simple conditionals.
|
||||||
|
bool GameObject::IsUpdateNeeded()
|
||||||
|
{
|
||||||
|
if (WorldObject::IsUpdateNeeded())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (GetMap()->isCellMarked(GetCurrentCell().GetCellCoord().GetId()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (IsVisibilityOverridden())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (IsTransport())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ enum LootState
|
|||||||
// 5 sec for bobber catch
|
// 5 sec for bobber catch
|
||||||
#define FISHING_BOBBER_READY_TIME 5
|
#define FISHING_BOBBER_READY_TIME 5
|
||||||
|
|
||||||
class GameObject : public WorldObject, public GridObject<GameObject>, public MovableMapObject
|
class GameObject : public WorldObject, public GridObject<GameObject>, public MovableMapObject, public UpdatableMapObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit GameObject();
|
explicit GameObject();
|
||||||
@@ -362,6 +362,8 @@ public:
|
|||||||
void SaveStateToDB();
|
void SaveStateToDB();
|
||||||
|
|
||||||
std::string GetDebugInfo() const override;
|
std::string GetDebugInfo() const override;
|
||||||
|
|
||||||
|
bool IsUpdateNeeded() override;
|
||||||
protected:
|
protected:
|
||||||
bool AIM_Initialize();
|
bool AIM_Initialize();
|
||||||
GameObjectModel* CreateModel();
|
GameObjectModel* CreateModel();
|
||||||
|
|||||||
@@ -1188,6 +1188,7 @@ void WorldObject::AddToWorld()
|
|||||||
{
|
{
|
||||||
Object::AddToWorld();
|
Object::AddToWorld();
|
||||||
GetMap()->GetZoneAndAreaId(GetPhaseMask(), _zoneId, _areaId, GetPositionX(), GetPositionY(), GetPositionZ());
|
GetMap()->GetZoneAndAreaId(GetPhaseMask(), _zoneId, _areaId, GetPositionX(), GetPositionY(), GetPositionZ());
|
||||||
|
GetMap()->AddObjectToPendingUpdateList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldObject::RemoveFromWorld()
|
void WorldObject::RemoveFromWorld()
|
||||||
@@ -3220,3 +3221,27 @@ void WorldObject::RemoveAllowedLooter(ObjectGuid guid)
|
|||||||
{
|
{
|
||||||
_allowedLooters.erase(guid);
|
_allowedLooters.erase(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldObject::IsUpdateNeeded()
|
||||||
|
{
|
||||||
|
if (isActiveObject())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldObject::CanBeAddedToMapUpdateList()
|
||||||
|
{
|
||||||
|
switch (GetTypeId())
|
||||||
|
{
|
||||||
|
case TYPEID_UNIT:
|
||||||
|
return IsCreature();
|
||||||
|
case TYPEID_DYNAMICOBJECT:
|
||||||
|
case TYPEID_GAMEOBJECT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -405,14 +405,58 @@ class MovableMapObject
|
|||||||
protected:
|
protected:
|
||||||
MovableMapObject() = default;
|
MovableMapObject() = default;
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] Cell const& GetCurrentCell() const { return _currentCell; }
|
[[nodiscard]] Cell const& GetCurrentCell() const { return _currentCell; }
|
||||||
|
|
||||||
|
private:
|
||||||
void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
|
void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
|
||||||
|
|
||||||
Cell _currentCell;
|
Cell _currentCell;
|
||||||
MapObjectCellMoveState _moveState{MAP_OBJECT_CELL_MOVE_NONE};
|
MapObjectCellMoveState _moveState{MAP_OBJECT_CELL_MOVE_NONE};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UpdatableMapObject
|
||||||
|
{
|
||||||
|
friend class Map;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum UpdateState : uint8
|
||||||
|
{
|
||||||
|
NotUpdating,
|
||||||
|
PendingAdd,
|
||||||
|
Updating
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UpdatableMapObject() : _mapUpdateListOffset(0), _mapUpdateState(NotUpdating) { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetMapUpdateListOffset(std::size_t const offset)
|
||||||
|
{
|
||||||
|
ASSERT(_mapUpdateState == Updating, "Attempted to set update list offset when object is not in map update list");
|
||||||
|
_mapUpdateListOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetMapUpdateListOffset() const
|
||||||
|
{
|
||||||
|
ASSERT(_mapUpdateState == Updating, "Attempted to get update list offset when object is not in map update list");
|
||||||
|
return _mapUpdateListOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUpdateState(UpdateState state)
|
||||||
|
{
|
||||||
|
_mapUpdateState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateState GetUpdateState() const
|
||||||
|
{
|
||||||
|
return _mapUpdateState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t _mapUpdateListOffset;
|
||||||
|
UpdateState _mapUpdateState;
|
||||||
|
};
|
||||||
|
|
||||||
class WorldObject : public Object, public WorldLocation
|
class WorldObject : public Object, public WorldLocation
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -639,6 +683,9 @@ public:
|
|||||||
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
|
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
|
||||||
void RemoveAllowedLooter(ObjectGuid guid);
|
void RemoveAllowedLooter(ObjectGuid guid);
|
||||||
|
|
||||||
|
virtual bool IsUpdateNeeded();
|
||||||
|
bool CanBeAddedToMapUpdateList();
|
||||||
|
|
||||||
std::string GetDebugInfo() const override;
|
std::string GetDebugInfo() const override;
|
||||||
|
|
||||||
// Event handler
|
// Event handler
|
||||||
|
|||||||
@@ -1683,6 +1683,8 @@ template <class T>
|
|||||||
void Player::UpdateVisibilityOf(T* target, UpdateData& data,
|
void Player::UpdateVisibilityOf(T* target, UpdateData& data,
|
||||||
std::vector<Unit*>& visibleNow)
|
std::vector<Unit*>& visibleNow)
|
||||||
{
|
{
|
||||||
|
GetMap()->AddObjectToPendingUpdateList(target);
|
||||||
|
|
||||||
if (HaveAtClient(target))
|
if (HaveAtClient(target))
|
||||||
{
|
{
|
||||||
if (!CanSeeOrDetect(target, false, true))
|
if (!CanSeeOrDetect(target, false, true))
|
||||||
|
|||||||
@@ -116,6 +116,9 @@ void GridObjectUnloader::Visit(GridRefMgr<T>& m)
|
|||||||
//Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted
|
//Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted
|
||||||
//TODO: Check if that script has the correct logic. Do we really need to summons something before deleting?
|
//TODO: Check if that script has the correct logic. Do we really need to summons something before deleting?
|
||||||
obj->CleanupsBeforeDelete();
|
obj->CleanupsBeforeDelete();
|
||||||
|
|
||||||
|
obj->GetMap()->RemoveObjectFromMapUpdateList(obj);
|
||||||
|
|
||||||
///- object will get delinked from the manager when deleted
|
///- object will get delinked from the manager when deleted
|
||||||
delete obj;
|
delete obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -354,19 +354,6 @@ void MessageDistDelivererToHostile::Visit(DynamicObjectMapType& m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void ObjectUpdater::Visit(GridRefMgr<T>& m)
|
|
||||||
{
|
|
||||||
T* obj;
|
|
||||||
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); )
|
|
||||||
{
|
|
||||||
obj = iter->GetSource();
|
|
||||||
++iter;
|
|
||||||
if (obj->IsInWorld() && (i_largeOnly == obj->IsVisibilityOverridden()))
|
|
||||||
obj->Update(i_timeDiff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u)
|
bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u)
|
||||||
{
|
{
|
||||||
return !u->IsAlive() && !u->HasGhostAura() && i_searchObj->IsWithinDistInMap(u, i_range);
|
return !u->IsAlive() && !u->HasGhostAura() && i_searchObj->IsWithinDistInMap(u, i_range);
|
||||||
@@ -396,7 +383,3 @@ bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u)
|
|||||||
{
|
{
|
||||||
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
|
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
template void ObjectUpdater::Visit<Creature>(CreatureMapType&);
|
|
||||||
template void ObjectUpdater::Visit<GameObject>(GameObjectMapType&);
|
|
||||||
template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType&);
|
|
||||||
|
|||||||
@@ -154,16 +154,6 @@ namespace Acore
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectUpdater
|
|
||||||
{
|
|
||||||
uint32 i_timeDiff;
|
|
||||||
bool i_largeOnly;
|
|
||||||
explicit ObjectUpdater(const uint32 diff, bool largeOnly) : i_timeDiff(diff), i_largeOnly(largeOnly) {}
|
|
||||||
template<class T> void Visit(GridRefMgr<T>& m);
|
|
||||||
void Visit(PlayerMapType&) {}
|
|
||||||
void Visit(CorpseMapType&) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// SEARCHERS & LIST SEARCHERS & WORKERS
|
// SEARCHERS & LIST SEARCHERS & WORKERS
|
||||||
|
|
||||||
// WorldObject searchers & workers
|
// WorldObject searchers & workers
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
|
|||||||
m_parentMap = (_parent ? _parent : this);
|
m_parentMap = (_parent ? _parent : this);
|
||||||
|
|
||||||
_zonePlayerCountMap.clear();
|
_zonePlayerCountMap.clear();
|
||||||
|
_updatableObjectListRecheckTimer.SetInterval(UPDATABLE_OBJECT_LIST_RECHECK_TIMER);
|
||||||
|
|
||||||
//lets initialize visibility distance for map
|
//lets initialize visibility distance for map
|
||||||
Map::InitVisibilityDistance();
|
Map::InitVisibilityDistance();
|
||||||
@@ -492,45 +493,7 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
void Map::MarkNearbyCellsOf(WorldObject* obj)
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor)
|
|
||||||
{
|
|
||||||
// check for valid position
|
|
||||||
if (!player->IsPositionValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// check normal grid activation range of the player
|
|
||||||
VisitNearbyCellsOf(player, gridVisitor, worldVisitor, largeGridVisitor, largeWorldVisitor);
|
|
||||||
|
|
||||||
// check maximum visibility distance for large creatures
|
|
||||||
CellArea area = Cell::CalculateCellArea(player->GetPositionX(), player->GetPositionY(), MAX_VISIBILITY_DISTANCE);
|
|
||||||
|
|
||||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
|
||||||
{
|
|
||||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
|
||||||
{
|
|
||||||
// marked cells are those that have been visited
|
|
||||||
// don't visit the same cell twice
|
|
||||||
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
|
|
||||||
if (isCellMarkedLarge(cell_id))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
markCellLarge(cell_id);
|
|
||||||
CellCoord pair(x, y);
|
|
||||||
Cell cell(pair);
|
|
||||||
|
|
||||||
Visit(cell, largeGridVisitor);
|
|
||||||
Visit(cell, largeWorldVisitor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor)
|
|
||||||
{
|
{
|
||||||
// Check for valid position
|
// Check for valid position
|
||||||
if (!obj->IsPositionValid())
|
if (!obj->IsPositionValid())
|
||||||
@@ -538,30 +501,13 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
|
|||||||
|
|
||||||
// Update mobs/objects in ALL visible cells around object!
|
// Update mobs/objects in ALL visible cells around object!
|
||||||
CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), obj->GetGridActivationRange());
|
CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), obj->GetGridActivationRange());
|
||||||
|
|
||||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||||
{
|
{
|
||||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
||||||
{
|
{
|
||||||
// marked cells are those that have been visited
|
// marked cells are those that have been visited
|
||||||
// don't visit the same cell twice
|
|
||||||
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
|
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
|
||||||
if (isCellMarked(cell_id))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
markCell(cell_id);
|
markCell(cell_id);
|
||||||
CellCoord pair(x, y);
|
|
||||||
Cell cell(pair);
|
|
||||||
|
|
||||||
Visit(cell, gridVisitor);
|
|
||||||
Visit(cell, worldVisitor);
|
|
||||||
|
|
||||||
if (!isCellMarkedLarge(cell_id))
|
|
||||||
{
|
|
||||||
markCellLarge(cell_id);
|
|
||||||
Visit(cell, largeGridVisitor);
|
|
||||||
Visit(cell, largeWorldVisitor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -613,39 +559,10 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// update active cells around players and active objects
|
_updatableObjectListRecheckTimer.Update(t_diff);
|
||||||
resetMarkedCells();
|
resetMarkedCells();
|
||||||
resetMarkedCellsLarge();
|
|
||||||
|
|
||||||
// Prepare object updaters
|
// Update players
|
||||||
Acore::ObjectUpdater updater(t_diff, false);
|
|
||||||
|
|
||||||
// For creature
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_object_update(updater);
|
|
||||||
|
|
||||||
// For pets
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_object_update(updater);
|
|
||||||
|
|
||||||
// For large creatures
|
|
||||||
Acore::ObjectUpdater largeObjectUpdater(t_diff, true);
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_large_object_update(largeObjectUpdater);
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_large_object_update(largeObjectUpdater);
|
|
||||||
|
|
||||||
// pussywizard: container for far creatures in combat with players
|
|
||||||
std::vector<Creature*> updateList;
|
|
||||||
updateList.reserve(10);
|
|
||||||
|
|
||||||
// Update non-player active objects
|
|
||||||
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
|
|
||||||
{
|
|
||||||
WorldObject* obj = *m_activeNonPlayersIter;
|
|
||||||
++m_activeNonPlayersIter;
|
|
||||||
|
|
||||||
if (obj && obj->IsInWorld())
|
|
||||||
VisitNearbyCellsOf(obj, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update players and their associated objects
|
|
||||||
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
|
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
|
||||||
{
|
{
|
||||||
Player* player = m_mapRefIter->GetSource();
|
Player* player = m_mapRefIter->GetSource();
|
||||||
@@ -654,53 +571,37 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
player->Update(s_diff);
|
player->Update(s_diff);
|
||||||
VisitNearbyCellsOfPlayer(player, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
|
||||||
|
|
||||||
// If player is using far sight, update viewpoint
|
if (_updatableObjectListRecheckTimer.Passed())
|
||||||
if (WorldObject* viewPoint = player->GetViewpoint())
|
|
||||||
{
|
{
|
||||||
if (Creature* viewCreature = viewPoint->ToCreature())
|
MarkNearbyCellsOf(player);
|
||||||
{
|
|
||||||
VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
|
||||||
}
|
|
||||||
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
|
|
||||||
{
|
|
||||||
VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle updates for creatures in combat with player and are more than X yards away
|
// If player is using far sight, update viewpoint
|
||||||
if (player->IsInCombat())
|
if (WorldObject* viewPoint = player->GetViewpoint())
|
||||||
{
|
|
||||||
updateList.clear();
|
|
||||||
float rangeSq = player->GetGridActivationRange() - 1.0f;
|
|
||||||
rangeSq *= rangeSq;
|
|
||||||
|
|
||||||
HostileReference* ref = player->getHostileRefMgr().getFirst();
|
|
||||||
while (ref)
|
|
||||||
{
|
{
|
||||||
if (Unit* unit = ref->GetSource()->GetOwner())
|
if (Creature* viewCreature = viewPoint->ToCreature())
|
||||||
if (Creature* cre = unit->ToCreature())
|
MarkNearbyCellsOf(viewCreature);
|
||||||
if (cre->FindMap() == player->FindMap() && cre->GetExactDist2dSq(player) > rangeSq)
|
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
|
||||||
updateList.push_back(cre);
|
MarkNearbyCellsOf(viewObject);
|
||||||
ref = ref->next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Creature* cre : updateList)
|
|
||||||
VisitNearbyCellsOf(cre, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update transports - pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok
|
if (_updatableObjectListRecheckTimer.Passed())
|
||||||
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
|
|
||||||
{
|
{
|
||||||
MotionTransport* transport = *_transportsUpdateIter;
|
// Mark all cells near active objects
|
||||||
++_transportsUpdateIter;
|
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); ++m_activeNonPlayersIter)
|
||||||
|
{
|
||||||
|
WorldObject* obj = *m_activeNonPlayersIter;
|
||||||
|
if (!obj || !obj->IsInWorld())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (transport->IsInWorld())
|
MarkNearbyCellsOf(obj);
|
||||||
transport->Update(t_diff);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateNonPlayerObjects(t_diff);
|
||||||
|
|
||||||
SendObjectUpdates();
|
SendObjectUpdates();
|
||||||
|
|
||||||
///- Process necessary scripts
|
///- Process necessary scripts
|
||||||
@@ -728,6 +629,101 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
|||||||
METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
|
METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::UpdateNonPlayerObjects(uint32 const diff)
|
||||||
|
{
|
||||||
|
for (WorldObject* obj : _pendingAddUpdatableObjectList)
|
||||||
|
_AddObjectToUpdateList(obj);
|
||||||
|
_pendingAddUpdatableObjectList.clear();
|
||||||
|
|
||||||
|
if (_updatableObjectListRecheckTimer.Passed())
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < _updatableObjectList.size();)
|
||||||
|
{
|
||||||
|
WorldObject* obj = _updatableObjectList[i];
|
||||||
|
if (!obj->IsInWorld())
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->Update(diff);
|
||||||
|
|
||||||
|
if (!obj->IsUpdateNeeded())
|
||||||
|
{
|
||||||
|
_RemoveObjectFromUpdateList(obj);
|
||||||
|
// Intentional no iteration here, obj is swapped with last element in
|
||||||
|
// _updatableObjectList so next loop will update that object at the same index
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
_updatableObjectListRecheckTimer.Reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < _updatableObjectList.size(); ++i)
|
||||||
|
{
|
||||||
|
WorldObject* obj = _updatableObjectList[i];
|
||||||
|
if (!obj->IsInWorld())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
obj->Update(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::AddObjectToPendingUpdateList(WorldObject* obj)
|
||||||
|
{
|
||||||
|
if (!obj->CanBeAddedToMapUpdateList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
|
||||||
|
if (mapUpdatableObject->GetUpdateState() != UpdatableMapObject::UpdateState::NotUpdating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_pendingAddUpdatableObjectList.insert(obj);
|
||||||
|
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::PendingAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal use only
|
||||||
|
void Map::_AddObjectToUpdateList(WorldObject* obj)
|
||||||
|
{
|
||||||
|
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
|
||||||
|
ASSERT(mapUpdatableObject && mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::PendingAdd);
|
||||||
|
|
||||||
|
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::Updating);
|
||||||
|
mapUpdatableObject->SetMapUpdateListOffset(_updatableObjectList.size());
|
||||||
|
_updatableObjectList.push_back(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal use only
|
||||||
|
void Map::_RemoveObjectFromUpdateList(WorldObject* obj)
|
||||||
|
{
|
||||||
|
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
|
||||||
|
ASSERT(mapUpdatableObject && mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::Updating);
|
||||||
|
|
||||||
|
if (obj != _updatableObjectList.back())
|
||||||
|
{
|
||||||
|
dynamic_cast<UpdatableMapObject*>(_updatableObjectList.back())->SetMapUpdateListOffset(mapUpdatableObject->GetMapUpdateListOffset());
|
||||||
|
std::swap(_updatableObjectList[mapUpdatableObject->GetMapUpdateListOffset()], _updatableObjectList.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
_updatableObjectList.pop_back();
|
||||||
|
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::NotUpdating);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::RemoveObjectFromMapUpdateList(WorldObject* obj)
|
||||||
|
{
|
||||||
|
if (!obj->CanBeAddedToMapUpdateList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
|
||||||
|
if (mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::PendingAdd)
|
||||||
|
_pendingAddUpdatableObjectList.erase(obj);
|
||||||
|
else if (mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::Updating)
|
||||||
|
_RemoveObjectFromUpdateList(obj);
|
||||||
|
}
|
||||||
|
|
||||||
void Map::HandleDelayedVisibility()
|
void Map::HandleDelayedVisibility()
|
||||||
{
|
{
|
||||||
if (i_objectsForDelayedVisibility.empty())
|
if (i_objectsForDelayedVisibility.empty())
|
||||||
@@ -795,7 +791,10 @@ void Map::RemoveFromMap(T* obj, bool remove)
|
|||||||
obj->ResetMap();
|
obj->ResetMap();
|
||||||
|
|
||||||
if (remove)
|
if (remove)
|
||||||
|
{
|
||||||
|
RemoveObjectFromMapUpdateList(obj);
|
||||||
DeleteFromWorld(obj);
|
DeleteFromWorld(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
@@ -831,6 +830,10 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove)
|
|||||||
|
|
||||||
obj->ResetMap();
|
obj->ResetMap();
|
||||||
|
|
||||||
|
// Transports are never actually deleted, but it *should* be safe to clear
|
||||||
|
// from update list when removing from world
|
||||||
|
RemoveObjectFromMapUpdateList(obj);
|
||||||
|
|
||||||
if (remove)
|
if (remove)
|
||||||
{
|
{
|
||||||
// if option set then object already saved at this moment
|
// if option set then object already saved at this moment
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "Position.h"
|
#include "Position.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "TaskScheduler.h"
|
#include "TaskScheduler.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include "GridTerrainData.h"
|
#include "GridTerrainData.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -85,6 +86,7 @@ struct ScriptAction
|
|||||||
|
|
||||||
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
|
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
|
||||||
#define MIN_UNLOAD_DELAY 1 // immediate unload
|
#define MIN_UNLOAD_DELAY 1 // immediate unload
|
||||||
|
#define UPDATABLE_OBJECT_LIST_RECHECK_TIMER 30 * IN_MILLISECONDS // Time to recheck update object list
|
||||||
|
|
||||||
struct PositionFullTerrainStatus
|
struct PositionFullTerrainStatus
|
||||||
{
|
{
|
||||||
@@ -181,14 +183,7 @@ public:
|
|||||||
template<class T> bool AddToMap(T*, bool checkTransport = false);
|
template<class T> bool AddToMap(T*, bool checkTransport = false);
|
||||||
template<class T> void RemoveFromMap(T*, bool);
|
template<class T> void RemoveFromMap(T*, bool);
|
||||||
|
|
||||||
void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
void MarkNearbyCellsOf(WorldObject* obj);
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
|
|
||||||
void VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
|
|
||||||
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
|
|
||||||
|
|
||||||
virtual void Update(const uint32, const uint32, bool thread = true);
|
virtual void Update(const uint32, const uint32, bool thread = true);
|
||||||
|
|
||||||
@@ -317,9 +312,6 @@ public:
|
|||||||
void resetMarkedCells() { marked_cells.reset(); }
|
void resetMarkedCells() { marked_cells.reset(); }
|
||||||
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
|
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
|
||||||
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
|
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
|
||||||
void resetMarkedCellsLarge() { marked_cells_large.reset(); }
|
|
||||||
bool isCellMarkedLarge(uint32 pCellId) { return marked_cells_large.test(pCellId); }
|
|
||||||
void markCellLarge(uint32 pCellId) { marked_cells_large.set(pCellId); }
|
|
||||||
|
|
||||||
[[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); }
|
[[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); }
|
||||||
[[nodiscard]] uint32 GetPlayersCountExceptGMs() const;
|
[[nodiscard]] uint32 GetPlayersCountExceptGMs() const;
|
||||||
@@ -512,6 +504,12 @@ public:
|
|||||||
uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y);
|
uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y);
|
||||||
uint32 GetCreatedCellsInMapCount();
|
uint32 GetCreatedCellsInMapCount();
|
||||||
|
|
||||||
|
void AddObjectToPendingUpdateList(WorldObject* obj);
|
||||||
|
void RemoveObjectFromMapUpdateList(WorldObject* obj);
|
||||||
|
|
||||||
|
typedef std::vector<WorldObject*> UpdatableObjectList;
|
||||||
|
typedef std::unordered_set<WorldObject*> PendingAddUpdatableObjectList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template<class T> void InitializeObject(T* obj);
|
template<class T> void InitializeObject(T* obj);
|
||||||
@@ -576,7 +574,6 @@ private:
|
|||||||
Map* m_parentMap;
|
Map* m_parentMap;
|
||||||
|
|
||||||
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
|
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
|
||||||
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
|
|
||||||
|
|
||||||
bool i_scriptLock;
|
bool i_scriptLock;
|
||||||
std::unordered_set<WorldObject*> i_objectsToRemove;
|
std::unordered_set<WorldObject*> i_objectsToRemove;
|
||||||
@@ -610,6 +607,11 @@ private:
|
|||||||
m_activeNonPlayers.erase(obj);
|
m_activeNonPlayers.erase(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateNonPlayerObjects(uint32 const diff);
|
||||||
|
|
||||||
|
void _AddObjectToUpdateList(WorldObject* obj);
|
||||||
|
void _RemoveObjectFromUpdateList(WorldObject* obj);
|
||||||
|
|
||||||
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _creatureRespawnTimes;
|
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _creatureRespawnTimes;
|
||||||
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _goRespawnTimes;
|
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _goRespawnTimes;
|
||||||
|
|
||||||
@@ -637,6 +639,10 @@ private:
|
|||||||
std::unordered_set<Corpse*> _corpseBones;
|
std::unordered_set<Corpse*> _corpseBones;
|
||||||
|
|
||||||
std::unordered_set<Object*> _updateObjects;
|
std::unordered_set<Object*> _updateObjects;
|
||||||
|
|
||||||
|
UpdatableObjectList _updatableObjectList;
|
||||||
|
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
||||||
|
IntervalTimer _updatableObjectListRecheckTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InstanceResetMethod
|
enum InstanceResetMethod
|
||||||
|
|||||||
@@ -926,6 +926,20 @@ MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const
|
|||||||
return Impl[slot]->GetMovementGeneratorType();
|
return Impl[slot]->GetMovementGeneratorType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MotionMaster::HasMovementGeneratorType(MovementGeneratorType type) const
|
||||||
|
{
|
||||||
|
if (empty() && type == IDLE_MOTION_TYPE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (int i = _top; i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (Impl[i] && Impl[i]->GetMovementGeneratorType() == type)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Xinef: Escort system
|
// Xinef: Escort system
|
||||||
uint32 MotionMaster::GetCurrentSplineId() const
|
uint32 MotionMaster::GetCurrentSplineId() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] MovementGeneratorType GetCurrentMovementGeneratorType() const;
|
[[nodiscard]] MovementGeneratorType GetCurrentMovementGeneratorType() const;
|
||||||
[[nodiscard]] MovementGeneratorType GetMotionSlotType(int slot) const;
|
[[nodiscard]] MovementGeneratorType GetMotionSlotType(int slot) const;
|
||||||
|
bool HasMovementGeneratorType(MovementGeneratorType type) const;
|
||||||
[[nodiscard]] uint32 GetCurrentSplineId() const; // Xinef: Escort system
|
[[nodiscard]] uint32 GetCurrentSplineId() const; // Xinef: Escort system
|
||||||
|
|
||||||
void propagateSpeedChange();
|
void propagateSpeedChange();
|
||||||
|
|||||||
Reference in New Issue
Block a user