mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 07:37:01 +00:00
[7335] Implement active objects support.
Active objects triggrering grid loading and updating around self like players. It can be used for event long run movements or escoring quest travels. Also can be used for proper implementation far vision spells. Currently only creatures can be activated by function call (from script) cr->SetActiveObjectState(true); Please avoid lot amount active objects in same time use. Existance active objects support isn't meaning that each rabbit must be active creature. Also added independent grid unloading locks for explicit unloading lock, lock for used by instance copied grids, lock counter for actiove object spawn grids locks. Last case required for prevent double spawn active creature walk far away from spawn point.
This commit is contained in:
parent
dd06340d6c
commit
872d791ca6
15 changed files with 282 additions and 51 deletions
181
src/game/Map.cpp
181
src/game/Map.cpp
|
|
@ -138,7 +138,6 @@ void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y)
|
|||
// return;
|
||||
|
||||
((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(x,y));
|
||||
baseMap->SetUnloadFlag(GridPair(63-x,63-y), false);
|
||||
GridMaps[x][y] = baseMap->GridMaps[x][y];
|
||||
return;
|
||||
}
|
||||
|
|
@ -209,7 +208,8 @@ void Map::DeleteStateMachine()
|
|||
|
||||
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
|
||||
: i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
|
||||
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry)
|
||||
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), i_gridExpiry(expiry),
|
||||
m_activeNonPlayersIter(m_activeNonPlayers.end())
|
||||
{
|
||||
for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
|
||||
{
|
||||
|
|
@ -360,22 +360,22 @@ Map::EnsureGridCreated(const GridPair &p)
|
|||
}
|
||||
|
||||
void
|
||||
Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player)
|
||||
Map::EnsureGridLoaded(const Cell &cell, Player *player)
|
||||
{
|
||||
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
|
||||
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
|
||||
|
||||
assert(grid != NULL);
|
||||
if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) )
|
||||
if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
|
||||
{
|
||||
if( player != NULL )
|
||||
if (player)
|
||||
{
|
||||
player->SendDelayResponse(MAX_GRID_LOAD_TIME);
|
||||
DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG("Player nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
|
||||
DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
|
||||
}
|
||||
|
||||
ObjectGridLoader loader(*grid, this, cell);
|
||||
|
|
@ -387,11 +387,9 @@ Map::EnsureGridLoadedForPlayer(const Cell &cell, Player *player, bool add_player
|
|||
|
||||
ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
|
||||
grid->SetGridState(GRID_STATE_ACTIVE);
|
||||
|
||||
if( add_player && player != NULL )
|
||||
(*grid)(cell.CellX(), cell.CellY()).AddWorldObject(player, player->GetGUID());
|
||||
}
|
||||
else if( player && add_player )
|
||||
|
||||
if (player)
|
||||
AddToGrid(player,grid,cell);
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +410,7 @@ Map::LoadGrid(const Cell& cell, bool no_unload)
|
|||
|
||||
setGridObjectDataLoaded(true,cell.GridX(), cell.GridY());
|
||||
if(no_unload)
|
||||
getNGrid(cell.GridX(), cell.GridY())->setUnloadFlag(false);
|
||||
getNGrid(cell.GridX(), cell.GridY())->setUnloadExplicitLock(true);
|
||||
}
|
||||
LoadVMap(63-cell.GridX(),63-cell.GridY());
|
||||
}
|
||||
|
|
@ -426,7 +424,7 @@ bool Map::Add(Player *player)
|
|||
// update player state for other player and visa-versa
|
||||
CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
|
||||
Cell cell(p);
|
||||
EnsureGridLoadedForPlayer(cell, player, true);
|
||||
EnsureGridLoaded(cell, player);
|
||||
player->AddToWorld();
|
||||
|
||||
SendInitSelf(player);
|
||||
|
|
@ -454,13 +452,19 @@ Map::Add(T *obj)
|
|||
}
|
||||
|
||||
Cell cell(p);
|
||||
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
|
||||
if(obj->isActiveObject())
|
||||
EnsureGridLoaded(cell);
|
||||
else
|
||||
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
|
||||
|
||||
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
|
||||
assert( grid != NULL );
|
||||
|
||||
AddToGrid(obj,grid,cell);
|
||||
obj->AddToWorld();
|
||||
|
||||
AddToActive(obj);
|
||||
|
||||
DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());
|
||||
|
||||
UpdateObjectVisibility(obj,cell,p);
|
||||
|
|
@ -616,6 +620,56 @@ void Map::Update(const uint32 &t_diff)
|
|||
}
|
||||
}
|
||||
|
||||
// non-player active objects
|
||||
if(!m_activeNonPlayers.empty())
|
||||
{
|
||||
for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
|
||||
{
|
||||
// skip not in world
|
||||
WorldObject* obj = *m_activeNonPlayersIter;
|
||||
|
||||
// step before processing, in this case if Map::Remove remove next object we correctly
|
||||
// step to next-next, and if we step to end() then newly added objects can wait next update.
|
||||
++m_activeNonPlayersIter;
|
||||
|
||||
if(!obj->IsInWorld())
|
||||
continue;
|
||||
|
||||
CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
|
||||
|
||||
// Check for correctness of standing_cell, it also avoids problems with update_cell
|
||||
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
|
||||
continue;
|
||||
|
||||
// the overloaded operators handle range checking
|
||||
// so ther's no need for range checking inside the loop
|
||||
CellPair begin_cell(standing_cell), end_cell(standing_cell);
|
||||
begin_cell << 1; begin_cell -= 1; // upper left
|
||||
end_cell >> 1; end_cell += 1; // lower right
|
||||
|
||||
for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
|
||||
{
|
||||
for(uint32 y = begin_cell.y_coord; y <= end_cell.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))
|
||||
{
|
||||
markCell(cell_id);
|
||||
CellPair pair(x,y);
|
||||
Cell cell(pair);
|
||||
cell.data.Part.reserved = CENTER_DISTRICT;
|
||||
cell.SetNoCreate();
|
||||
CellLock<NullGuard> cell_lock(cell, pair);
|
||||
cell_lock->Visit(cell_lock, grid_object_update, *this);
|
||||
cell_lock->Visit(cell_lock, world_object_update, *this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
|
||||
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
|
||||
if (IsBattleGroundOrArena())
|
||||
|
|
@ -708,6 +762,8 @@ Map::Remove(T *obj, bool remove)
|
|||
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
|
||||
assert( grid != NULL );
|
||||
|
||||
RemoveFromActive(obj);
|
||||
|
||||
obj->RemoveFromWorld();
|
||||
RemoveFromGrid(obj,grid,cell);
|
||||
|
||||
|
|
@ -749,9 +805,8 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
|
|||
RemoveFromGrid(player, oldGrid,old_cell);
|
||||
if( !old_cell.DiffGrid(new_cell) )
|
||||
AddToGrid(player, oldGrid,new_cell);
|
||||
|
||||
if( old_cell.DiffGrid(new_cell) )
|
||||
EnsureGridLoadedForPlayer(new_cell, player, true);
|
||||
else
|
||||
EnsureGridLoaded(new_cell, player);
|
||||
}
|
||||
|
||||
// if move then update what player see and who seen
|
||||
|
|
@ -868,8 +923,27 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
|
|||
sLog.outDebug("Creature (GUID: %u Entry: %u) move in same grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else // in diff. grids
|
||||
|
||||
// in diff. grids but active creature
|
||||
if(c->isActiveObject())
|
||||
{
|
||||
EnsureGridLoaded(new_cell);
|
||||
|
||||
#ifdef MANGOS_DEBUG
|
||||
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
|
||||
sLog.outDebug("Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), 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
|
||||
|
||||
RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell);
|
||||
AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// in diff. loaded grid normal creature
|
||||
if(loaded(GridPair(new_cell.GridX(), new_cell.GridY())))
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
|
|
@ -882,17 +956,16 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell)
|
|||
EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY()));
|
||||
AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MANGOS_DEBUG
|
||||
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
|
||||
sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
|
||||
#endif
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
// fail to move: normal creature attempt move to unloaded grid
|
||||
#ifdef MANGOS_DEBUG
|
||||
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
|
||||
sLog.outDebug("Creature (GUID: %u Entry: %u) attempt move from grid[%u,%u]cell[%u,%u] to unloaded grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Map::CreatureRespawnRelocation(Creature *c)
|
||||
|
|
@ -929,7 +1002,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce)
|
|||
assert( grid != NULL);
|
||||
|
||||
{
|
||||
if(!pForce && PlayersNearGrid(x, y) )
|
||||
if(!pForce && ActiveObjectsNearGrid(x, y) )
|
||||
return false;
|
||||
|
||||
DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id);
|
||||
|
|
@ -1513,7 +1586,7 @@ void Map::SendToPlayers(WorldPacket const* data) const
|
|||
itr->getSource()->GetSession()->SendPacket(data);
|
||||
}
|
||||
|
||||
bool Map::PlayersNearGrid(uint32 x, uint32 y) const
|
||||
bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const
|
||||
{
|
||||
CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
|
||||
CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
|
||||
|
|
@ -1532,9 +1605,61 @@ bool Map::PlayersNearGrid(uint32 x, uint32 y) const
|
|||
return true;
|
||||
}
|
||||
|
||||
for(ActiveNonPlayers::const_iterator iter = m_activeNonPlayers.begin(); iter != m_activeNonPlayers.end(); ++iter)
|
||||
{
|
||||
WorldObject* obj = *iter;
|
||||
|
||||
CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
|
||||
if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
|
||||
(cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Map::AddToActive( Creature* c )
|
||||
{
|
||||
AddToActiveHelper(c);
|
||||
|
||||
// also not allow unloading spawn grid to prevent creating creature clone at load
|
||||
if(c->GetDBTableGUIDLow())
|
||||
{
|
||||
float x,y,z;
|
||||
c->GetRespawnCoord(x,y,z);
|
||||
GridPair p = MaNGOS::ComputeGridPair(x, y);
|
||||
if(getNGrid(p.x_coord, p.y_coord))
|
||||
getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock();
|
||||
else
|
||||
{
|
||||
GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY());
|
||||
sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] not loaded.",
|
||||
c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Map::RemoveFromActive( Creature* c )
|
||||
{
|
||||
RemoveFromActiveHelper(c);
|
||||
|
||||
// also allow unloading spawn grid
|
||||
if(c->GetDBTableGUIDLow())
|
||||
{
|
||||
float x,y,z;
|
||||
c->GetRespawnCoord(x,y,z);
|
||||
GridPair p = MaNGOS::ComputeGridPair(x, y);
|
||||
if(getNGrid(p.x_coord, p.y_coord))
|
||||
getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock();
|
||||
else
|
||||
{
|
||||
GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY());
|
||||
sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] not loaded.",
|
||||
c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void Map::Add(Corpse *);
|
||||
template void Map::Add(Creature *);
|
||||
template void Map::Add(GameObject *);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue