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__