From 872d791ca67ed9b51184cf7c280bcbc064b4f9eb Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 25 Feb 2009 13:27:13 +0300 Subject: [PATCH] [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. --- src/framework/GameSystem/Grid.h | 18 ++- src/framework/GameSystem/NGrid.h | 21 +++- src/game/Corpse.h | 2 + src/game/Creature.cpp | 22 +++- src/game/Creature.h | 6 +- src/game/DynamicObject.h | 2 + src/game/GameObject.h | 2 + src/game/GridStates.cpp | 6 +- src/game/Map.cpp | 181 ++++++++++++++++++++++++++----- src/game/Map.h | 53 ++++++++- src/game/MapInstanced.h | 11 +- src/game/ObjectGridLoader.cpp | 4 + src/game/Player.h | 1 + src/game/Traveller.h | 2 +- src/shared/revision_nr.h | 2 +- 15 files changed, 282 insertions(+), 51 deletions(-) diff --git a/src/framework/GameSystem/Grid.h b/src/framework/GameSystem/Grid.h index f1c826da0..ce1d5463e 100644 --- a/src/framework/GameSystem/Grid.h +++ b/src/framework/GameSystem/Grid.h @@ -103,7 +103,7 @@ class MANGOS_DLL_DECL Grid /** Returns the number of object within the grid. */ - unsigned int ActiveObjectsInGrid(void) const { return i_objects.template Count(); } + unsigned int ActiveObjectsInGrid(void) const { return m_activeGridObjects.size()+i_objects.template Count(); } /** Accessors: Returns a specific type of object in the GRID_OBJECT_TYPES */ @@ -112,11 +112,21 @@ class MANGOS_DLL_DECL Grid /** Inserts a container type object into the grid. */ - template bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template insert(hdl, obj); } + template bool AddGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) + { + if(obj->isActiveObject()) + m_activeGridObjects.insert(obj); + return i_container.template insert(hdl, obj); + } /** Removes a containter type object from the grid */ - template bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) { return i_container.template remove(obj, hdl); } + template bool RemoveGridObject(SPECIFIC_OBJECT *obj, OBJECT_HANDLE hdl) + { + if(obj->isActiveObject()) + m_activeGridObjects.erase(obj); + return i_container.template remove(obj, hdl); + } private: @@ -125,5 +135,7 @@ class MANGOS_DLL_DECL Grid TypeMapContainer i_container; TypeMapContainer i_objects; + typedef std::set ActiveGridObjects; + ActiveGridObjects m_activeGridObjects; }; #endif diff --git a/src/framework/GameSystem/NGrid.h b/src/framework/GameSystem/NGrid.h index 663cf2059..0d6211243 100644 --- a/src/framework/GameSystem/NGrid.h +++ b/src/framework/GameSystem/NGrid.h @@ -30,17 +30,23 @@ class GridInfo { public: GridInfo() : i_timer(0) {} - GridInfo(time_t expiry, bool unload = true ) : i_timer(expiry), i_unloadflag(unload) {} + GridInfo(time_t expiry, bool unload = true ) : i_timer(expiry), i_unloadExplicitLock(!unload) {} const TimeTracker& getTimeTracker() const { return i_timer; } - bool getUnloadFlag() const { return i_unloadflag; } - void setUnloadFlag( bool pFlag) { i_unloadflag = pFlag; } + bool getUnloadLock() const { return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; } + void setUnloadExplicitLock( bool on ) { i_unloadExplicitLock = on; } + void setUnloadReferenceLock( bool on ) { i_unloadReferenceLock = on; } + void incUnloadActiveLock() { ++i_unloadActiveLockCount; } + void decUnloadActiveLock() { if(i_unloadActiveLockCount) --i_unloadActiveLockCount; } + void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; } void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); } void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); } private: TimeTracker i_timer; - bool i_unloadflag; + uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading) + bool i_unloadExplicitLock : 1; // explicit manual lock or config setting + bool i_unloadReferenceLock : 1; // lock from instance map copy }; typedef enum @@ -90,8 +96,11 @@ class MANGOS_DLL_DECL NGrid GridInfo* getGridInfoRef() { return &i_GridInfo; } const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); } - bool getUnloadFlag() const { return i_GridInfo.getUnloadFlag(); } - void setUnloadFlag( bool pFlag) { i_GridInfo.setUnloadFlag(pFlag); } + bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); } + void setUnloadExplicitLock( bool on ) { i_GridInfo.setUnloadExplicitLock(on); } + void setUnloadReferenceLock( bool on ) { i_GridInfo.setUnloadReferenceLock(on); } + void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); } + void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); } void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); } void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); } diff --git a/src/game/Corpse.h b/src/game/Corpse.h index a072402e5..819382847 100644 --- a/src/game/Corpse.h +++ b/src/game/Corpse.h @@ -86,6 +86,8 @@ class Corpse : public WorldObject void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } private: GridReference m_gridRef; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index df96a2b88..e0d9846e0 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -114,7 +114,7 @@ m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_resp m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isVehicle(false), m_isTotem(false), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_creatureInfo(NULL) +m_creatureInfo(NULL), m_isActiveObject(false) { m_regenTimer = 200; m_valuesCount = UNIT_END; @@ -2098,3 +2098,23 @@ const char* Creature::GetNameForLocaleIdx(int32 loc_idx) const return GetName(); } + +void Creature::SetActiveObjectState( bool on ) +{ + if(m_isActiveObject==on) + return; + + bool world = IsInWorld(); + + Map* map; + if(world) + { + map = GetMap(); + map->Remove(this,false); + } + + m_isActiveObject = on; + + if(world) + map->Add(this); +} \ No newline at end of file diff --git a/src/game/Creature.h b/src/game/Creature.h index e6076dbbb..59c655477 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -609,7 +609,10 @@ class MANGOS_DLL_SPEC Creature : public Unit uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - void SetDeadByDefault (bool death_state) {m_isDeadByDefault = death_state;} + void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } + + bool isActiveObject() const { return m_isActiveObject; } + void SetActiveObjectState(bool on); protected: bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL); @@ -661,6 +664,7 @@ class MANGOS_DLL_SPEC Creature : public Unit private: GridReference m_gridRef; CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) + bool m_isActiveObject; }; class AssistDelayEvent : public BasicEvent diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h index 7c1d821e1..830662f0c 100644 --- a/src/game/DynamicObject.h +++ b/src/game/DynamicObject.h @@ -54,6 +54,8 @@ class DynamicObject : public WorldObject void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); } GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } protected: uint64 m_casterGuid; uint32 m_spellId; diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 404d20fac..f34364bc5 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -575,6 +575,8 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject GameObject* LookupFishingHoleAround(float range); GridReference &GetGridRef() { return m_gridRef; } + + bool isActiveObject() const { return false; } protected: uint32 m_charges; // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22) uint32 m_spellId; diff --git a/src/game/GridStates.cpp b/src/game/GridStates.cpp index 1bace7c27..4743860f5 100644 --- a/src/game/GridStates.cpp +++ b/src/game/GridStates.cpp @@ -34,7 +34,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c info.UpdateTimeTracker(t_diff); if( info.getTimeTracker().Passed() ) { - if( grid.ActiveObjectsInGrid() == 0 && !m.PlayersNearGrid(x, y) ) + if( grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y) ) { ObjectGridStoper stoper(grid); stoper.StopN(); @@ -58,14 +58,14 @@ IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const ui void RemovalState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &t_diff) const { - if(info.getUnloadFlag()) + if(!info.getUnloadLock()) { info.UpdateTimeTracker(t_diff); if( info.getTimeTracker().Passed() ) { if( !m.UnloadGrid(x, y, false) ) { - sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players nearby", x, y, m.GetId()); + sLog.outDebug("Grid[%u,%u] for map %u differed unloading due to players or active objects nearby", x, y, m.GetId()); m.ResetGridExpiry(grid); } } diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 47df9ebc9..18cc41174 100644 --- a/src/game/Map.cpp +++ b/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 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 *); diff --git a/src/game/Map.h b/src/game/Map.h index 65baba71d..a5900f7d7 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -164,8 +164,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj return( !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL ); } - bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); } - void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); } + bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } + void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void LoadGrid(const Cell& cell, bool no_unload = false); bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); virtual void UnloadAll(bool pForce); @@ -256,12 +256,24 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } uint32 GetPlayersCountExceptGMs() const; - bool PlayersNearGrid(uint32 x,uint32 y) const; + bool ActiveObjectsNearGrid(uint32 x,uint32 y) const; void SendToPlayers(WorldPacket const* data) const; typedef MapRefManager PlayerList; PlayerList const& GetPlayers() const { return m_mapRefManager; } + + // must called with AddToWorld + template + void AddToActive(T* obj) { AddToActiveHelper(obj); } + + void AddToActive(Creature* obj); + + // must called with RemoveFromWorld + template + void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); } + + void RemoveFromActive(Creature* obj); private: void LoadVMap(int pX, int pY); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); @@ -283,7 +295,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj CreatureMoveList i_creaturesToMove; bool loaded(const GridPair &) const; - void EnsureGridLoadedForPlayer(const Cell&, Player*, bool add_player); + void EnsureGridLoaded(const Cell&, Player* player = NULL); void EnsureGridCreated(const GridPair &); void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); } @@ -302,6 +314,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void setNGrid(NGridType* grid, uint32 x, uint32 y); protected: + void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } + typedef MaNGOS::ObjectLevelLockable::Lock Guard; MapEntry const* i_mapEntry; @@ -312,6 +326,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj MapRefManager m_mapRefManager; MapRefManager::iterator m_mapRefIter; + + typedef std::set ActiveNonPlayers; + ActiveNonPlayers m_activeNonPlayers; + ActiveNonPlayers::iterator m_activeNonPlayersIter; private: typedef GridReadGuard ReadGuard; typedef GridWriteGuard WriteGuard; @@ -336,6 +354,31 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj template void DeleteFromWorld(T*); + + template + void AddToActiveHelper(T* obj) + { + if(obj->isActiveObject()) + m_activeNonPlayers.insert(obj); + } + + template + void RemoveFromActiveHelper(T* obj) + { + if(obj->isActiveObject()) + { + // Map::Update for active object in proccess + if(m_activeNonPlayersIter != m_activeNonPlayers.end()) + { + ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); + if(itr==m_activeNonPlayersIter) + ++m_activeNonPlayersIter; + m_activeNonPlayers.erase(itr); + } + else + m_activeNonPlayers.erase(obj); + } + } }; enum InstanceResetMethod @@ -408,7 +451,7 @@ Map::Visit(const CellLock &cell, TypeContainerVisitor & if( !cell->NoCreate() || loaded(GridPair(x,y)) ) { - EnsureGridLoadedForPlayer(cell, NULL, false); + EnsureGridLoaded(cell); //LOCK_TYPE guard(i_info[x][y]->i_lock); getNGrid(x, y)->Visit(cell_x, cell_y, visitor); } diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 0a998e50d..e195cdcb7 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -42,11 +42,18 @@ class MANGOS_DLL_DECL MapInstanced : public Map Map* FindMap(uint32 InstanceId) { return _FindMap(InstanceId); } void DestroyInstance(uint32 InstanceId); void DestroyInstance(InstancedMaps::iterator &itr); - void AddGridMapReference(const GridPair &p) { ++GridMapReference[p.x_coord][p.y_coord]; } + + void AddGridMapReference(const GridPair &p) + { + ++GridMapReference[p.x_coord][p.y_coord]; + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), true); + } + void RemoveGridMapReference(const GridPair &p) { --GridMapReference[p.x_coord][p.y_coord]; - if (!GridMapReference[p.x_coord][p.y_coord]) { SetUnloadFlag(GridPair(63-p.x_coord,63-p.y_coord), true); } + if (!GridMapReference[p.x_coord][p.y_coord]) + SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false); } InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index b2735df3b..9b944893e 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -125,6 +125,8 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & addUnitState(obj,cell); obj->AddToWorld(); + map->AddToActive(obj); + ++count; } @@ -150,6 +152,8 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType addUnitState(obj,cell); obj->AddToWorld(); + map->AddToActive(obj); + ++count; } } diff --git a/src/game/Player.h b/src/game/Player.h index 9e102436a..76d6cc272 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2142,6 +2142,7 @@ class MANGOS_DLL_SPEC Player : public Unit bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } void SetTitle(CharTitlesEntry const* title); + bool isActiveObject() const { return true; } protected: /*********************************************************/ diff --git a/src/game/Traveller.h b/src/game/Traveller.h index bfb3715d5..6aa55eb14 100644 --- a/src/game/Traveller.h +++ b/src/game/Traveller.h @@ -62,7 +62,7 @@ template inline uint32 Traveller::GetTotalTrevelTimeTo(float x, float y, float z) { float dist = GetMoveDestinationTo(x,y,z); - float speed = Speed(); + double speed = Speed(); speed *= 0.001f; // speed is in seconds so convert from second to millisecond return static_cast(dist/speed); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 90e21aa91..c4c742e0a 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7334" + #define REVISION_NR "7335" #endif // __REVISION_NR_H__