Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-07-15 20:34:44 +08:00
80 changed files with 11484 additions and 699 deletions

View File

@@ -80,6 +80,7 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
m_parentMap = (_parent ? _parent : this);
_zonePlayerCountMap.clear();
_updatableObjectListRecheckTimer.SetInterval(UPDATABLE_OBJECT_LIST_RECHECK_TIMER);
//lets initialize visibility distance for map
Map::InitVisibilityDistance();
@@ -492,45 +493,7 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
return true;
}
void Map::VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
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)
void Map::MarkNearbyCellsOf(WorldObject* obj)
{
// Check for valid position
if (!obj->IsPositionValid())
@@ -538,30 +501,13 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
// Update mobs/objects in ALL visible cells around object!
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 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 (isCellMarked(cell_id))
continue;
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;
}
/// update active cells around players and active objects
_updatableObjectListRecheckTimer.Update(t_diff);
resetMarkedCells();
resetMarkedCellsLarge();
// Prepare object updaters
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
// Update players
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->GetSource();
@@ -654,53 +571,37 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
continue;
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 (WorldObject* viewPoint = player->GetViewpoint())
if (_updatableObjectListRecheckTimer.Passed())
{
if (Creature* viewCreature = viewPoint->ToCreature())
{
VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
{
VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
}
MarkNearbyCellsOf(player);
// handle updates for creatures in combat with player and are more than X yards away
if (player->IsInCombat())
{
updateList.clear();
float rangeSq = player->GetGridActivationRange() - 1.0f;
rangeSq *= rangeSq;
HostileReference* ref = player->getHostileRefMgr().getFirst();
while (ref)
// If player is using far sight, update viewpoint
if (WorldObject* viewPoint = player->GetViewpoint())
{
if (Unit* unit = ref->GetSource()->GetOwner())
if (Creature* cre = unit->ToCreature())
if (cre->FindMap() == player->FindMap() && cre->GetExactDist2dSq(player) > rangeSq)
updateList.push_back(cre);
ref = ref->next();
if (Creature* viewCreature = viewPoint->ToCreature())
MarkNearbyCellsOf(viewCreature);
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
MarkNearbyCellsOf(viewObject);
}
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
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
if (_updatableObjectListRecheckTimer.Passed())
{
MotionTransport* transport = *_transportsUpdateIter;
++_transportsUpdateIter;
// Mark all cells near active objects
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())
transport->Update(t_diff);
MarkNearbyCellsOf(obj);
}
}
UpdateNonPlayerObjects(t_diff);
SendObjectUpdates();
///- 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())));
}
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()
{
if (i_objectsForDelayedVisibility.empty())
@@ -795,7 +791,10 @@ void Map::RemoveFromMap(T* obj, bool remove)
obj->ResetMap();
if (remove)
{
RemoveObjectFromMapUpdateList(obj);
DeleteFromWorld(obj);
}
}
template<>
@@ -831,6 +830,10 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove)
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 option set then object already saved at this moment