[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:
VladimirMangos 2009-02-25 13:27:13 +03:00
parent dd06340d6c
commit 872d791ca6
15 changed files with 282 additions and 51 deletions

View file

@ -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 *);