diff --git a/src/framework/GameSystem/NGrid.h b/src/framework/GameSystem/NGrid.h index f18e65cc6..465c56166 100644 --- a/src/framework/GameSystem/NGrid.h +++ b/src/framework/GameSystem/NGrid.h @@ -33,14 +33,12 @@ class GridInfo public: GridInfo() - : i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false), - i_unloadReferenceLock(false) + : i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false) { } GridInfo(time_t expiry, bool unload = true ) - : i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload), - i_unloadReferenceLock(false) + : i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload) { } @@ -48,11 +46,10 @@ class GridInfo bool getUnloadLock() const { - return i_unloadActiveLockCount || i_unloadExplicitLock || i_unloadReferenceLock; + return i_unloadActiveLockCount || i_unloadExplicitLock; } 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; } @@ -65,7 +62,6 @@ class GridInfo TimeTracker i_timer; 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 @@ -129,7 +125,6 @@ class MANGOS_DLL_DECL NGrid const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); } 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); } diff --git a/src/framework/Policies/ThreadingModel.h b/src/framework/Policies/ThreadingModel.h index dfb38247b..e23bbc0e4 100644 --- a/src/framework/Policies/ThreadingModel.h +++ b/src/framework/Policies/ThreadingModel.h @@ -121,12 +121,12 @@ namespace MaNGOS { public: - Lock(T& /*host*/) + Lock(const T& /*host*/) { ClassLevelLockable::si_mtx.acquire(); } - Lock(ClassLevelLockable &) + Lock(const ClassLevelLockable &) { ClassLevelLockable::si_mtx.acquire(); } diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index f0bef722c..92a20af0d 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -35,7 +35,6 @@ #include "BattleGroundRB.h" #include "MapManager.h" #include "Map.h" -#include "MapInstanced.h" #include "ObjectMgr.h" #include "ProgressBar.h" #include "Chat.h" diff --git a/src/game/ConfusedMovementGenerator.cpp b/src/game/ConfusedMovementGenerator.cpp index d9718a842..c8a5e7abb 100644 --- a/src/game/ConfusedMovementGenerator.cpp +++ b/src/game/ConfusedMovementGenerator.cpp @@ -32,7 +32,7 @@ ConfusedMovementGenerator::Initialize(T &unit) y = unit.GetPositionY(); z = unit.GetPositionZ(); - Map const* map = unit.GetBaseMap(); + TerrainInfo const* map = unit.GetTerrain(); i_nextMove = 1; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index d029ef6d6..db43f90ee 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -1237,7 +1237,7 @@ bool Creature::LoadFromDB(uint32 guidlow, Map *map) m_deathState = DEAD; if(CanFly()) { - float tz = GetMap()->GetHeight(data->posX, data->posY, data->posZ, false); + float tz = GetTerrain()->GetHeight(data->posX, data->posY, data->posZ, false); if(data->posZ - tz > 0.1) Relocate(data->posX, data->posY, tz); } @@ -1427,7 +1427,7 @@ bool Creature::FallGround() return false; // use larger distance for vmap height search than in most other cases - float tz = GetMap()->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true, MAX_FALL_DISTANCE); + float tz = GetTerrain()->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true, MAX_FALL_DISTANCE); if (tz < INVALID_HEIGHT) { diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index 08bb44f81..48758c268 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -133,9 +133,9 @@ DestinationHolder::UpdateTraveller(TRAVELLER &traveller, uint32 diff, float x,y,z; if (traveller.GetTraveller().hasUnitState(UNIT_STAT_TAXI_FLIGHT)) - GetLocationNow(traveller.GetTraveller().GetBaseMap() ,x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation + GetLocationNow(traveller.GetTraveller().GetMap() ,x, y, z, true); // Should reposition Object with right Coord, so I can bypass some Grid Relocation else - GetLocationNow(traveller.GetTraveller().GetBaseMap(), x, y, z, false); + GetLocationNow(traveller.GetTraveller().GetMap(), x, y, z, false); if (traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y || traveller.GetTraveller().GetPositionZ() != z) { @@ -185,7 +185,7 @@ DestinationHolder::GetLocationNow(const Map * map, float &x, float &y else { //That part is good for mob Walking on the floor. But the floor is not always what we thought. - z = map->GetHeight(x,y,i_fromZ,false); // Disable cave check + z = map->GetTerrain()->GetHeight(x,y,i_fromZ,false); // Disable cave check const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY); const float zDist = fabs(i_fromZ - z) + 0.000001f; const float slope = groundDist / zDist; diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp index ba8bb2861..545490fbf 100644 --- a/src/game/FleeingMovementGenerator.cpp +++ b/src/game/FleeingMovementGenerator.cpp @@ -61,7 +61,7 @@ FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z) z = owner.GetPositionZ(); float temp_x, temp_y, angle; - const Map * _map = owner.GetBaseMap(); + const TerrainInfo * _map = owner.GetTerrain(); //primitive path-finding for(uint8 i = 0; i < 18; ++i) { diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 51719fe7a..c2d21cbe4 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -568,7 +568,10 @@ void GameEventMgr::GameEventSpawn(int16 event_id) sObjectMgr.AddCreatureToGrid(*itr, data); // Spawn if necessary (loaded grids only) - Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); + Map* map = const_cast(sMapMgr.FindMap(data->mapid)); + if(!map) + return; + // We use spawn coords to spawn if(!map->Instanceable() && map->IsLoaded(data->posX,data->posY)) { @@ -614,7 +617,10 @@ void GameEventMgr::GameEventSpawn(int16 event_id) // Spawn if necessary (loaded grids only) // this base map checked as non-instanced and then only existing - Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); + Map* map = const_cast(sMapMgr.FindMap(data->mapid)); + if(!map) + return; + // We use current coords to unspawn, not spawn coords since creature can have changed grid if(!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { diff --git a/src/game/GridMap.cpp b/src/game/GridMap.cpp index 501ad807d..13cb3f8e5 100644 --- a/src/game/GridMap.cpp +++ b/src/game/GridMap.cpp @@ -26,6 +26,8 @@ #include "GridMap.h" #include "VMapFactory.h" #include "World.h" +#include "Policies/SingletonImp.h" +#include "Util.h" char const* MAP_MAGIC = "MAPS"; char const* MAP_VERSION_MAGIC = "v1.1"; @@ -614,3 +616,597 @@ bool GridMap::ExistVMap(uint32 mapid,int gx,int gy) return true; } + +////////////////////////////////////////////////////////////////////////// +TerrainInfo::TerrainInfo(uint32 mapid) : m_mapId(mapid) +{ + for (int k = 0; k < MAX_NUMBER_OF_GRIDS; ++k) + { + for (int i = 0; i < MAX_NUMBER_OF_GRIDS; ++i) + { + m_GridMaps[i][k] = NULL; + m_GridRef[i][k] = 0; + } + } + + //clean up GridMap objects every minute + const uint32 iCleanUpInterval = 60; + //schedule start randlomly + const uint32 iRandomStart = urand(20, 40); + + i_timer.SetInterval(iCleanUpInterval * 1000); + i_timer.SetCurrent(iRandomStart * 1000); +} + +TerrainInfo::~TerrainInfo() +{ + for (int k = 0; k < MAX_NUMBER_OF_GRIDS; ++k) + for (int i = 0; i < MAX_NUMBER_OF_GRIDS; ++i) + delete m_GridMaps[i][k]; + + VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(m_mapId); +} + +GridMap * TerrainInfo::Load(const uint32 x, const uint32 y) +{ + MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS); + MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS); + + //reference grid as a first step + RefGrid(x, y); + + //quick check if GridMap already loaded + GridMap * pMap = m_GridMaps[x][y]; + if(!pMap) + pMap = LoadMapAndVMap(x, y); + + return pMap; +} + +//schedule lazy GridMap object cleanup +void TerrainInfo::Unload(const uint32 x, const uint32 y) +{ + MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS); + MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS); + + if(m_GridMaps[x][y]) + { + //decrease grid reference count... + if(UnrefGrid(x, y) == 0) + { + //TODO: add your additional logic here + + } + } +} + + +//call this method only +void TerrainInfo::CleanUpGrids(const uint32 diff) +{ + i_timer.Update(diff); + if( !i_timer.Passed() ) + return; + + for (int y = 0; y < MAX_NUMBER_OF_GRIDS; ++y) + { + for (int x = 0; x < MAX_NUMBER_OF_GRIDS; ++x) + { + const int16& iRef = m_GridRef[x][y]; + GridMap * pMap = m_GridMaps[x][y]; + + //delete those GridMap objects which have refcount = 0 + if(pMap && iRef == 0 ) + { + m_GridMaps[x][y] = NULL; + //delete grid data if reference count == 0 + pMap->unloadData(); + delete pMap; + + //unload VMAPS... + VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(m_mapId, x, y); + } + } + } + + i_timer.Reset(); +} + +int TerrainInfo::RefGrid(const uint32& x, const uint32& y) +{ + MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS); + MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS); + + LOCK_GUARD _lock(m_refMutex); + return (m_GridRef[x][y] += 1); +} + +int TerrainInfo::UnrefGrid(const uint32& x, const uint32& y) +{ + MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS); + MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS); + + int16& iRef = m_GridRef[x][y]; + + LOCK_GUARD _lock(m_refMutex); + if(iRef > 0) + return (iRef -= 1); + + return 0; +} + +float TerrainInfo::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchDist) const +{ + // find raw .map surface under Z coordinates + float mapHeight; + float z2 = z + 2.f; + if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) + { + float _mapheight = gmap->getHeight(x,y); + + // look from a bit higher pos to find the floor, ignore under surface case + if (z2 > _mapheight) + mapHeight = _mapheight; + else + mapHeight = VMAP_INVALID_HEIGHT_VALUE; + } + else + mapHeight = VMAP_INVALID_HEIGHT_VALUE; + + float vmapHeight; + if (pUseVmaps) + { + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + if (vmgr->isHeightCalcEnabled()) + { + // if mapHeight has been found search vmap height at least until mapHeight point + // this prevent case when original Z "too high above ground and vmap height search fail" + // this will not affect most normal cases (no map in instance, or stay at ground at continent) + if (mapHeight > INVALID_HEIGHT && z2 - mapHeight > maxSearchDist) + maxSearchDist = z2 - mapHeight + 1.0f; // 1.0 make sure that we not fail for case when map height near but above for vamp height + + // look from a bit higher pos to find the floor + vmapHeight = vmgr->getHeight(GetMapId(), x, y, z2, maxSearchDist); + } + else + vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + } + else + vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + + // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT + // vmapheight set for any under Z value or <= INVALID_HEIGHT + + if (vmapHeight > INVALID_HEIGHT) + { + if (mapHeight > INVALID_HEIGHT) + { + // we have mapheight and vmapheight and must select more appropriate + + // we are already under the surface or vmap height above map heigt + // or if the distance of the vmap height is less the land height distance + if (z < mapHeight || vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z)) + return vmapHeight; + else + return mapHeight; // better use .map surface height + + } + else + return vmapHeight; // we have only vmapHeight (if have) + } + + return mapHeight; +} + +inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId, + WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) +{ + bool outdoor = true; + + if(wmoEntry && atEntry) + { + if(atEntry->flags & AREA_FLAG_OUTSIDE) + return true; + if(atEntry->flags & AREA_FLAG_INSIDE) + return false; + } + + outdoor = mogpFlags&0x8; + + if(wmoEntry) + { + if(wmoEntry->Flags & 4) + return true; + + if((wmoEntry->Flags & 2)!=0) + outdoor = false; + } + return outdoor; +} + +bool TerrainInfo::IsOutdoors(float x, float y, float z) const +{ + uint32 mogpFlags; + int32 adtId, rootId, groupId; + + // no wmo found? -> outside by default + if(!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) + return true; + + AreaTableEntry const* atEntry = 0; + WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); + if(wmoEntry) + { + DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); + + atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + } + + return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); +} + +bool TerrainInfo::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const +{ + float vmap_z = z; + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + if (vmgr->getAreaInfo(GetMapId(), x, y, vmap_z, flags, adtId, rootId, groupId)) + { + // check if there's terrain between player height and object height + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + { + float _mapheight = gmap->getHeight(x,y); + // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice... + if(z + 2.0f > _mapheight && _mapheight > vmap_z) + return false; + } + return true; + } + return false; +} + +uint16 TerrainInfo::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const +{ + uint32 mogpFlags; + int32 adtId, rootId, groupId; + WMOAreaTableEntry const* wmoEntry = 0; + AreaTableEntry const* atEntry = 0; + bool haveAreaInfo = false; + + if(GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) + { + haveAreaInfo = true; + wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); + if(wmoEntry) + atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + } + + uint16 areaflag; + if (atEntry) + areaflag = atEntry->exploreFlag; + else + { + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + areaflag = gmap->getArea(x, y); + // this used while not all *.map files generated (instances) + else + areaflag = GetAreaFlagByMapId(GetMapId()); + } + + if (isOutdoors) + { + if (haveAreaInfo) + *isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); + else + *isOutdoors = true; + } + return areaflag; +} + +uint8 TerrainInfo::GetTerrainType(float x, float y ) const +{ + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getTerrainType(x, y); + else + return 0; +} + +uint32 TerrainInfo::GetAreaId(float x, float y, float z) const +{ + return TerrainManager::GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),m_mapId); +} + +uint32 TerrainInfo::GetZoneId(float x, float y, float z) const +{ + return TerrainManager::GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),m_mapId); +} + +void TerrainInfo::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const +{ + TerrainManager::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),m_mapId); +} + + +GridMapLiquidStatus TerrainInfo::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data) const +{ + GridMapLiquidStatus result = LIQUID_MAP_NO_WATER; + VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); + float liquid_level, ground_level = INVALID_HEIGHT; + uint32 liquid_type; + if (vmgr->GetLiquidLevel(GetMapId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type)) + { + DEBUG_LOG("getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type); + // Check water level and ground level + if (liquid_level > ground_level && z > ground_level - 2) + { + // All ok in water -> store data + if (data) + { + data->type = liquid_type; + data->level = liquid_level; + data->depth_level = ground_level; + } + + // For speed check as int values + int delta = int((liquid_level - z) * 10); + + // Get position delta + if (delta > 20) // Under water + return LIQUID_MAP_UNDER_WATER; + if (delta > 0 ) // In water + return LIQUID_MAP_IN_WATER; + if (delta > -1) // Walk on water + return LIQUID_MAP_WATER_WALK; + result = LIQUID_MAP_ABOVE_WATER; + } + } + if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) + { + GridMapLiquidData map_data; + GridMapLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data); + // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: + if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level)) + { + if (data) + *data = map_data; + return map_result; + } + } + return result; +} + +bool TerrainInfo::IsInWater(float x, float y, float pZ, GridMapLiquidData *data) const +{ + // Check surface in x, y point for liquid + if (const_cast(this)->GetGrid(x, y)) + { + GridMapLiquidData liquid_status; + GridMapLiquidData *liquid_ptr = data ? data : &liquid_status; + if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr)) + { + //if (liquid_prt->level - liquid_prt->depth_level > 2) //??? + return true; + } + } + return false; +} + +bool TerrainInfo::IsUnderWater(float x, float y, float z) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER) + return true; + } + return false; +} + +/** + * Function find higher form water or ground height for current floor + * + * @param x, y, z Coordinates original point at floor level + * + * @param pGround optional arg for retrun calculated by function work ground height, it let avoid in caller code recalculate height for point if it need + * + * @param swim z coordinate can be calculated for select above/at or under z coordinate (for fly or swim/walking by bottom) + * in last cases for in water returned under water height for avoid client set swimming unit as saty at water. + * + * @return calculated z coordinate + */ +float TerrainInfo::GetWaterOrGroundLevel(float x, float y, float z, float* pGround /*= NULL*/, bool swim /*= false*/) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); + if (pGround) + *pGround = ground_z; + + GridMapLiquidData liquid_status; + + GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z; + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + +GridMap * TerrainInfo::GetGrid( const float x, const float y ) +{ + // half opt method + int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x + int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y + + //quick check if GridMap already loaded + GridMap * pMap = m_GridMaps[gx][gy]; + if(!pMap) + pMap = LoadMapAndVMap(gx, gy); + + return pMap; +} + +GridMap * TerrainInfo::LoadMapAndVMap( const uint32 x, const uint32 y ) +{ + //double checked lock pattern + if(!m_GridMaps[x][y]) + { + LOCK_GUARD lock(m_mutex); + + if(!m_GridMaps[x][y]) + { + GridMap * map = new GridMap(); + + // map file name + char *tmp=NULL; + int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; + tmp = new char[len]; + snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),m_mapId, x, y); + sLog.outDetail("Loading map %s",tmp); + + if(!map->loadData(tmp)) + { + sLog.outError("Error load map file: \n %s\n", tmp); + //ASSERT(false); + } + + delete [] tmp; + m_GridMaps[x][y] = map; + + //load VMAPs for current map/grid... + const MapEntry * i_mapEntry = sMapStore.LookupEntry(m_mapId); + const char* mapName = i_mapEntry ? i_mapEntry->name[sWorld.GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; + + int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), m_mapId, x, y); + switch(vmapLoadResult) + { + case VMAP::VMAP_LOAD_RESULT_OK: + sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x,y,x,y); + break; + case VMAP::VMAP_LOAD_RESULT_ERROR: + sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x,y,x,y); + break; + case VMAP::VMAP_LOAD_RESULT_IGNORED: + DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x,y,x,y); + break; + } + } + } + + return m_GridMaps[x][y]; +} + +float TerrainInfo::GetWaterLevel(float x, float y, float z, float* pGround /*= NULL*/) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); + if (pGround) + *pGround = ground_z; + + GridMapLiquidData liquid_status; + + GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + return VMAP_INVALID_HEIGHT_VALUE; + + return liquid_status.level; + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + +////////////////////////////////////////////////////////////////////////// + +#define CLASS_LOCK MaNGOS::ClassLevelLockable +INSTANTIATE_SINGLETON_2(TerrainManager, CLASS_LOCK); +INSTANTIATE_CLASS_MUTEX(TerrainManager, ACE_Thread_Mutex); + +TerrainManager::TerrainManager() +{ +} + +TerrainManager::~TerrainManager() +{ + for (TerrainDataMap::iterator it = i_TerrainMap.begin(); it != i_TerrainMap.end(); ++it) + delete it->second; +} + +TerrainInfo * TerrainManager::LoadTerrain(const uint32 mapId) +{ + Guard _guard(*this); + + TerrainInfo * ptr = NULL; + TerrainDataMap::const_iterator iter = i_TerrainMap.find(mapId); + if(iter == i_TerrainMap.end()) + { + ptr = new TerrainInfo(mapId); + i_TerrainMap[mapId] = ptr; + } + else + ptr = (*iter).second; + + return ptr; +} + +void TerrainManager::UnloadTerrain(const uint32 mapId) +{ + if(sWorld.getConfig(CONFIG_BOOL_GRID_UNLOAD) == 0) + return; + + Guard _guard(*this); + + TerrainDataMap::iterator iter = i_TerrainMap.find(mapId); + if(iter != i_TerrainMap.end()) + { + TerrainInfo * ptr = (*iter).second; + //lets check if this object can be actually freed + if(ptr->IsReferenced() == false) + { + i_TerrainMap.erase(iter); + delete ptr; + } + } +} + +void TerrainManager::Update(const uint32 diff) +{ + //global garbage collection for GridMap objects and VMaps + for (TerrainDataMap::iterator iter = i_TerrainMap.begin(); iter != i_TerrainMap.end(); ++iter) + iter->second->CleanUpGrids(diff); +} + +void TerrainManager::UnloadAll() +{ + for (TerrainDataMap::iterator it = i_TerrainMap.begin(); it != i_TerrainMap.end(); ++it) + delete it->second; + + i_TerrainMap.clear(); +} + +uint32 TerrainManager::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + if (entry) + return entry->ID; + else + return 0; +} + +uint32 TerrainManager::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + if( entry ) + return ( entry->zone != 0 ) ? entry->zone : entry->ID; + else + return 0; +} + +void TerrainManager::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + areaid = entry ? entry->ID : 0; + zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0; +} diff --git a/src/game/GridMap.h b/src/game/GridMap.h index adc3421fd..51c2b58a9 100644 --- a/src/game/GridMap.h +++ b/src/game/GridMap.h @@ -20,6 +20,7 @@ #define MANGOS_GRIDMAP_H #include "Platform/Define.h" +#include "Policies/Singleton.h" #include "DBCStructure.h" #include "GridDefines.h" #include "Object.h" @@ -37,6 +38,7 @@ class InstanceSave; struct ScriptInfo; struct ScriptAction; class BattleGround; +class Map; struct GridMapFileHeader { @@ -180,4 +182,143 @@ class GridMap GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0); }; +template +class MANGOS_DLL_SPEC Referencable +{ +public: + Referencable() { m_count = 0; } + + void AddRef() { ++m_count; } + bool Release() { return (--m_count < 1); } + bool IsReferenced() const { return (m_count > 0); } + +private: + Referencable(const Referencable&); + Referencable& operator=(const Referencable&); + + Countable m_count; +}; + +typedef ACE_Atomic_Op AtomicLong; + +#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface +#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE +#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT +#define DEFAULT_HEIGHT_SEARCH 10.0f // default search distance to find height at nearby locations +#define DEFAULT_WATER_SEARCH 50.0f // default search distance to case detection water level + +//class for sharing and managin GridMap objects +class MANGOS_DLL_SPEC TerrainInfo : public Referencable +{ +public: + TerrainInfo(uint32 mapid); + ~TerrainInfo(); + + uint32 GetMapId() const { return m_mapId; } + + //TODO: move all terrain/vmaps data info query functions + //from 'Map' class into this class + float GetHeight(float x, float y, float z, bool pCheckVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const; + float GetWaterLevel(float x, float y, float z, float* pGround = NULL) const; + float GetWaterOrGroundLevel(float x, float y, float z, float* pGround = NULL, bool swim = false) const; + bool IsInWater(float x, float y, float z, GridMapLiquidData *data = 0) const; + bool IsUnderWater(float x, float y, float z) const; + + GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0) const; + + uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const; + uint8 GetTerrainType(float x, float y ) const; + + uint32 GetAreaId(float x, float y, float z) const; + uint32 GetZoneId(float x, float y, float z) const; + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const; + + bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; + bool IsOutdoors(float x, float y, float z) const; + + + //this method should be used only by TerrainManager + //to cleanup unreferenced GridMap objects - they are too heavy + //to destroy them dynamically, especially on highly populated servers + //THIS METHOD IS NOT THREAD-SAFE!!!! AND IT SHOULDN'T BE THREAD-SAFE!!!! + void CleanUpGrids(const uint32 diff); + +protected: + friend class Map; + //load/unload terrain data + GridMap * Load(const uint32 x, const uint32 y); + void Unload(const uint32 x, const uint32 y); + +private: + TerrainInfo(const TerrainInfo&); + TerrainInfo& operator=(const TerrainInfo&); + + GridMap * GetGrid( const float x, const float y ); + GridMap * LoadMapAndVMap(const uint32 x, const uint32 y ); + + int RefGrid(const uint32& x, const uint32& y); + int UnrefGrid(const uint32& x, const uint32& y); + + const uint32 m_mapId; + + GridMap *m_GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + int16 m_GridRef[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + + //global garbage collection timer + ShortIntervalTimer i_timer; + + typedef ACE_Thread_Mutex LOCK_TYPE; + typedef ACE_Guard LOCK_GUARD; + LOCK_TYPE m_mutex; + LOCK_TYPE m_refMutex; +}; + +//class for managing TerrainData object and all sort of geometry querying operations +class MANGOS_DLL_DECL TerrainManager : public MaNGOS::Singleton > +{ + typedef UNORDERED_MAP TerrainDataMap; + friend class MaNGOS::OperatorNew; + +public: + TerrainInfo * LoadTerrain(const uint32 mapId); + void UnloadTerrain(const uint32 mapId); + + void Update(const uint32 diff); + void UnloadAll(); + + uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const + { + TerrainInfo *pData = const_cast(this)->LoadTerrain(mapid); + return pData->GetAreaFlag(x, y, z); + } + uint32 GetAreaId(uint32 mapid, float x, float y, float z) const + { + return TerrainManager::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + uint32 GetZoneId(uint32 mapid, float x, float y, float z) const + { + return TerrainManager::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) + { + TerrainManager::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid); + } + + static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); + static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); + static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id); + +private: + TerrainManager(); + ~TerrainManager(); + + TerrainManager(const TerrainManager &); + TerrainManager& operator=(const TerrainManager &); + + typedef MaNGOS::ClassLevelLockable::Lock Guard; + TerrainDataMap i_TerrainMap; +}; + +#define sTerrainMgr TerrainManager::Instance() + #endif diff --git a/src/game/Group.cpp b/src/game/Group.cpp index fea7809b4..8ce8ecf37 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -30,7 +30,6 @@ #include "BattleGround.h" #include "MapManager.h" #include "InstanceSaveMgr.h" -#include "MapInstanced.h" #include "Util.h" #include "LootMgr.h" diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index 8ccf9f4d3..ceff0e373 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -26,7 +26,6 @@ #include "CellImpl.h" #include "Map.h" #include "MapManager.h" -#include "MapInstanced.h" #include "Timer.h" #include "GridNotifiersImpl.h" #include "Transports.h" @@ -581,8 +580,8 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr) void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId) { DEBUG_LOG("InstanceSaveMgr::_ResetInstance %u, %u", mapid, instanceId); - Map *map = (MapInstanced*)sMapMgr.CreateBaseMap(mapid); - if (!map->Instanceable()) + Map * iMap = sMapMgr.FindMap(mapid, instanceId); + if (!iMap || !iMap->Instanceable()) return; InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(instanceId); @@ -591,8 +590,7 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId) DeleteInstanceFromDB(instanceId); // even if save not loaded - Map* iMap = ((MapInstanced*)map)->FindMap(instanceId); - if (iMap && iMap->IsDungeon()) + if (iMap->IsDungeon()) ((InstanceMap*)iMap)->Reset(INSTANCE_RESET_RESPAWN_DELAY); else sObjectMgr.DeleteRespawnTimeForInstance(instanceId);// even if map is not loaded @@ -639,14 +637,14 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b } // note: this isn't fast but it's meant to be executed very rarely - Map const *map = sMapMgr.CreateBaseMap(mapid); // _not_ include difficulty - MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps(); - MapInstanced::InstancedMaps::iterator mitr; - for(mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr) + const MapManager::MapMapType& maps = sMapMgr.Maps(); + + MapManager::MapMapType::const_iterator iter_last = maps.lower_bound(MapID(mapid + 1)); + for(MapManager::MapMapType::const_iterator mitr = maps.lower_bound(MapID(mapid)); mitr != iter_last; ++mitr) { Map *map2 = mitr->second; - if (!map2->IsDungeon()) - continue; + if(map2->GetId() != mapid) + break; if (warn) ((InstanceMap*)map2)->SendResetWarnings(timeLeft); diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 74fb80f59..39da0bdad 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -293,7 +293,7 @@ bool ChatHandler::HandleGPSCommand(char* args) zone_y = 0; } - Map const *map = obj->GetMap(); + TerrainInfo const *map = obj->GetTerrain(); float ground_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), MAX_HEIGHT); float floor_z = map->GetHeight(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ()); @@ -1830,7 +1830,7 @@ bool ChatHandler::HandleTeleNameCommand(char* args) PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), GetMangosString(LANG_OFFLINE), tele->name.c_str()); Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation, - sMapMgr.GetZoneId(tele->mapId,tele->position_x,tele->position_y,tele->position_z),target_guid); + sTerrainMgr.GetZoneId(tele->mapId,tele->position_x,tele->position_y,tele->position_z),target_guid); } return true; @@ -2034,7 +2034,7 @@ bool ChatHandler::HandleGoHelper( Player* player, uint32 mapid, float x, float y return false; } - Map const *map = sMapMgr.CreateBaseMap(mapid); + TerrainInfo const *map = sTerrainMgr.LoadTerrain(mapid); z = map->GetWaterOrGroundLevel(x, y, MAX_HEIGHT); } diff --git a/src/game/Makefile.am b/src/game/Makefile.am index 1008833f7..3e9b847b2 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -178,8 +178,6 @@ libmangosgame_a_SOURCES = \ Mail.h \ Map.cpp \ Map.h \ - MapInstanced.cpp \ - MapInstanced.h \ MapManager.cpp \ MapManager.h \ MapReference.h \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index e7fae9b6a..215a526f0 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -34,7 +34,6 @@ #include "Group.h" #include "MapRefManager.h" #include "DBCEnums.h" -#include "MapInstanced.h" #include "InstanceSaveMgr.h" #include "VMapFactory.h" #include "BattleGroundMgr.h" @@ -57,88 +56,35 @@ Map::~Map() if (m_instanceSave) m_instanceSave->SetUsedByMapState(false); // field pointer can be deleted after this -} -void Map::LoadVMap(int gx,int gy) -{ - // x and y are swapped !! - VMAP::VMAPLoadResult vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath()+ "vmaps").c_str(), GetId(), gx,gy); - switch(vmapLoadResult) - { - case VMAP::VMAP_LOAD_RESULT_OK: - DETAIL_LOG("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy); - break; - case VMAP::VMAP_LOAD_RESULT_ERROR: - DETAIL_LOG("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy); - break; - case VMAP::VMAP_LOAD_RESULT_IGNORED: - DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx,gy,gx,gy); - break; - } -} - -void Map::LoadMap(int gx,int gy, bool reload) -{ - if( i_InstanceId != 0 ) - { - if(GridMaps[gx][gy]) - return; - - // load grid map for base map - if (!m_parentMap->GridMaps[gx][gy]) - m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy)); - - ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy)); - GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; - return; - } - - if(GridMaps[gx][gy] && !reload) - return; - - //map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?) - if(GridMaps[gx][gy]) - { - DETAIL_LOG("Unloading already loaded map %u before reloading.",i_id); - delete (GridMaps[gx][gy]); - GridMaps[gx][gy]=NULL; - } - - // map file name - char *tmp=NULL; - int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; - tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy); - DETAIL_LOG("Loading map %s",tmp); - // loading data - GridMaps[gx][gy] = new GridMap(); - if (!GridMaps[gx][gy]->loadData(tmp)) - { - sLog.outError("Error load map file: \n %s\n", tmp); - } - delete [] tmp; + //release reference count + if(m_TerrainData->Release()) + sTerrainMgr.UnloadTerrain(m_TerrainData->GetMapId()); } void Map::LoadMapAndVMap(int gx,int gy) { - LoadMap(gx,gy); - if(i_InstanceId == 0) - LoadVMap(gx, gy); // Only load the data for the base map + if(m_bLoadedGrids[gx][gx]) + return; + + GridMap * pInfo = m_TerrainData->Load(gx, gy); + if(pInfo) + m_bLoadedGrids[gx][gy] = true; } -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) +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), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_instanceSave(NULL), m_activeNonPlayersIter(m_activeNonPlayers.end()), - i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this) + i_gridExpiry(expiry), m_TerrainData(sTerrainMgr.LoadTerrain(id)) { - for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) + for(unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j) { - for(unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j) + for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) { //z code - GridMaps[idx][j] =NULL; + m_bLoadedGrids[idx][j] = false; setNGrid(NULL, idx, j); } } @@ -146,6 +92,9 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par //lets initialize visibility distance for map Map::InitVisibilityDistance(); + + //add reference for TerrainData object + m_TerrainData->AddRef(); } void Map::InitVisibilityDistance() @@ -292,7 +241,7 @@ Map::EnsureGridCreated(const GridPair &p) int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; - if(!GridMaps[gx][gy]) + if(!m_bLoadedGrids[gx][gy]) LoadMapAndVMap(gx,gy); } } @@ -916,23 +865,14 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; - // delete grid map, but don't delete if it is from parent map (and thus only reference) - //+++if (GridMaps[gx][gy]) don't check for GridMaps[gx][gy], we might have to unload vmaps + // unload GridMap - it is reference-countable so will be deleted safely when lockCount < 1 + // also simply set Map's pointer to corresponding GridMap object to NULL + if(m_bLoadedGrids[gx][gy]) { - if (i_InstanceId == 0) - { - if(GridMaps[gx][gy]) - { - GridMaps[gx][gy]->unloadData(); - delete GridMaps[gx][gy]; - } - VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy); - } - else - ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy)); - - GridMaps[gx][gy] = NULL; + m_bLoadedGrids[gx][gy] = false; + m_TerrainData->Unload(gx, gy); } + DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, i_id); return true; } @@ -973,346 +913,6 @@ uint32 Map::GetMaxResetDelay() const return InstanceResetScheduler::GetMaxResetTimeFor(GetMapDifficulty()); } -inline GridMap *Map::GetGrid(float x, float y) -{ - // half opt method - int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x - int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - - // ensure GridMap is loaded - EnsureGridCreated(GridPair(63-gx,63-gy)); - - return GridMaps[gx][gy]; -} - -float Map::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchDist) const -{ - // find raw .map surface under Z coordinates - float mapHeight; - float z2 = z + 2.f; - if (GridMap *gmap = const_cast(this)->GetGrid(x, y)) - { - float _mapheight = gmap->getHeight(x,y); - - // look from a bit higher pos to find the floor, ignore under surface case - if (z2 > _mapheight) - mapHeight = _mapheight; - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; - } - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; - - float vmapHeight; - if (pUseVmaps) - { - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->isHeightCalcEnabled()) - { - // if mapHeight has been found search vmap height at least until mapHeight point - // this prevent case when original Z "too high above ground and vmap height search fail" - // this will not affect most normal cases (no map in instance, or stay at ground at continent) - if (mapHeight > INVALID_HEIGHT && z2 - mapHeight > maxSearchDist) - maxSearchDist = z2 - mapHeight + 1.0f; // 1.0 make sure that we not fail for case when map height near but above for vamp height - - // look from a bit higher pos to find the floor - vmapHeight = vmgr->getHeight(GetId(), x, y, z2, maxSearchDist); - } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; - } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; - - // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT - // vmapheight set for any under Z value or <= INVALID_HEIGHT - - if (vmapHeight > INVALID_HEIGHT) - { - if (mapHeight > INVALID_HEIGHT) - { - // we have mapheight and vmapheight and must select more appropriate - - // we are already under the surface or vmap height above map heigt - // or if the distance of the vmap height is less the land height distance - if (z < mapHeight || vmapHeight > mapHeight || fabs(mapHeight-z) > fabs(vmapHeight-z)) - return vmapHeight; - else - return mapHeight; // better use .map surface height - - } - else - return vmapHeight; // we have only vmapHeight (if have) - } - - return mapHeight; -} - -inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId, - WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) -{ - bool outdoor = true; - - if(wmoEntry && atEntry) - { - if(atEntry->flags & AREA_FLAG_OUTSIDE) - return true; - if(atEntry->flags & AREA_FLAG_INSIDE) - return false; - } - - outdoor = mogpFlags&0x8; - - if(wmoEntry) - { - if(wmoEntry->Flags & 4) - return true; - - if((wmoEntry->Flags & 2)!=0) - outdoor = false; - } - return outdoor; -} - -bool Map::IsOutdoors(float x, float y, float z) const -{ - uint32 mogpFlags; - int32 adtId, rootId, groupId; - - // no wmo found? -> outside by default - if(!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) - return true; - - AreaTableEntry const* atEntry = 0; - WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); - if(wmoEntry) - { - DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); - - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); - } - - return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); -} - -bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const -{ - float vmap_z = z; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->getAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId)) - { - // check if there's terrain between player height and object height - if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) - { - float _mapheight = gmap->getHeight(x,y); - // z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice... - if(z + 2.0f > _mapheight && _mapheight > vmap_z) - return false; - } - return true; - } - return false; -} - -uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const -{ - uint32 mogpFlags; - int32 adtId, rootId, groupId; - WMOAreaTableEntry const* wmoEntry = 0; - AreaTableEntry const* atEntry = 0; - bool haveAreaInfo = false; - - if(GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId)) - { - haveAreaInfo = true; - wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); - if (wmoEntry) - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); - } - - uint16 areaflag; - if (atEntry) - areaflag = atEntry->exploreFlag; - else - { - if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) - areaflag = gmap->getArea(x, y); - // this used while not all *.map files generated (instances) - else - areaflag = GetAreaFlagByMapId(i_id); - } - - if (isOutdoors) - { - if (haveAreaInfo) - *isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); - else - *isOutdoors = true; - } - return areaflag; -} - -uint8 Map::GetTerrainType(float x, float y ) const -{ - if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) - return gmap->getTerrainType(x, y); - else - return 0; -} - -GridMapLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data) const -{ - GridMapLiquidStatus result = LIQUID_MAP_NO_WATER; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - float liquid_level, ground_level = INVALID_HEIGHT; - uint32 liquid_type; - if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type)) - { - DEBUG_LOG("getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type); - // Check water level and ground level - if (liquid_level > ground_level && z > ground_level - 2) - { - // All ok in water -> store data - if (data) - { - data->type = liquid_type; - data->level = liquid_level; - data->depth_level = ground_level; - } - - // For speed check as int values - int delta = int((liquid_level - z) * 10); - - // Get position delta - if (delta > 20) // Under water - return LIQUID_MAP_UNDER_WATER; - if (delta > 0 ) // In water - return LIQUID_MAP_IN_WATER; - if (delta > -1) // Walk on water - return LIQUID_MAP_WATER_WALK; - result = LIQUID_MAP_ABOVE_WATER; - } - } - if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) - { - GridMapLiquidData map_data; - GridMapLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data); - // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: - if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level)) - { - if (data) - *data = map_data; - return map_result; - } - } - return result; -} - -uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - if (entry) - return entry->ID; - else - return 0; -} - -uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - if( entry ) - return ( entry->zone != 0 ) ? entry->zone : entry->ID; - else - return 0; -} - -void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id) -{ - AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); - - areaid = entry ? entry->ID : 0; - zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0; -} - -bool Map::IsInWater(float x, float y, float pZ, GridMapLiquidData *data) const -{ - // Check surface in x, y point for liquid - if (const_cast(this)->GetGrid(x, y)) - { - GridMapLiquidData liquid_status; - GridMapLiquidData *liquid_ptr = data ? data : &liquid_status; - if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr)) - { - //if (liquid_prt->level - liquid_prt->depth_level > 2) //??? - return true; - } - } - return false; -} - -bool Map::IsUnderWater(float x, float y, float z) const -{ - if (const_cast(this)->GetGrid(x, y)) - { - if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER) - return true; - } - return false; -} - -/** - * Function find higher form water or ground height for current floor - * - * @param x, y, z Coordinates original point at floor level - * - * @param pGround optional arg for retrun calculated by function work ground height, it let avoid in caller code recalculate height for point if it need - * - * @param swim z coordinate can be calculated for select above/at or under z coordinate (for fly or swim/walking by bottom) - * in last cases for in water returned under water height for avoid client set swimming unit as saty at water. - * - * @return calculated z coordinate - */ -float Map::GetWaterOrGroundLevel(float x, float y, float z, float* pGround /*= NULL*/, bool swim /*= false*/) const -{ - if (const_cast(this)->GetGrid(x, y)) - { - // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); - if (pGround) - *pGround = ground_z; - - GridMapLiquidData liquid_status; - - GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); - return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z; - } - - return VMAP_INVALID_HEIGHT_VALUE; -} - -float Map::GetWaterLevel(float x, float y, float z, float* pGround /*= NULL*/) const -{ - if (const_cast(this)->GetGrid(x, y)) - { - // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); - if (pGround) - *pGround = ground_z; - - GridMapLiquidData liquid_status; - - GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); - if (!res) - return VMAP_INVALID_HEIGHT_VALUE; - - return liquid_status.level; - } - - return VMAP_INVALID_HEIGHT_VALUE; -} - bool Map::CheckGridIntegrity(Creature* c, bool moved) const { Cell const& cur_cell = c->GetCurrentCell(); @@ -1628,8 +1228,8 @@ template void Map::Remove(DynamicObject *, bool); /* ******* Dungeon Instance Maps ******* */ -InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) - : Map(id, expiry, InstanceId, SpawnMode, _parent), +InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) + : Map(id, expiry, InstanceId, SpawnMode), m_resetAfterUnload(false), m_unloadWhenEmpty(false), i_data(NULL), i_script_id(0) { @@ -1998,8 +1598,8 @@ void InstanceMap::SetResetSchedule(bool on) /* ******* Battleground Instance Maps ******* */ -BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) - : Map(id, expiry, InstanceId, spawnMode, _parent) +BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 spawnMode) + : Map(id, expiry, InstanceId, spawnMode) { //lets initialize visibility distance for BG/Arenas BattleGroundMap::InitVisibilityDistance(); diff --git a/src/game/Map.h b/src/game/Map.h index c375fb060..3f1ee0f04 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -78,11 +78,6 @@ enum LevelRequirementVsMode #pragma pack(pop) #endif -#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface -#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE -#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT -#define DEFAULT_HEIGHT_SEARCH 10.0f // default search distance to find height at nearby locations -#define DEFAULT_WATER_SEARCH 50.0f // default search distance to case detection water level #define MIN_UNLOAD_DELAY 1 // immediate unload class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::ObjectLevelLockable @@ -91,7 +86,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj friend class ObjectGridLoader; friend class ObjectWorldLoader; public: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); virtual ~Map(); // currently unused for normal maps @@ -150,39 +145,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj time_t GetGridExpiry(void) const { return i_gridExpiry; } uint32 GetId(void) const { return i_id; } - Map const * GetParent() const { return m_parentMap; } - // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height - float GetHeight(float x, float y, float z, bool pCheckVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const; - float GetWaterLevel(float x, float y, float z, float* pGround = NULL) const; - float GetWaterOrGroundLevel(float x, float y, float z, float* pGround = NULL, bool swim = false) const; - bool IsInWater(float x, float y, float z, GridMapLiquidData *data = 0) const; - bool IsUnderWater(float x, float y, float z) const; - - GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0) const; - - uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const; - uint8 GetTerrainType(float x, float y ) const; - - static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); - static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); - static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id); - - uint32 GetAreaId(float x, float y, float z) const - { - return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),i_id); - } - - uint32 GetZoneId(float x, float y, float z) const - { - return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),i_id); - } - - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const - { - GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),i_id); - } virtual void RemoveAllObjectsInRemoveList(); @@ -268,13 +232,12 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj // DynObjects currently uint32 GenerateLocalLowGuid(HighGuid guidhigh); - bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; - bool IsOutdoors(float x, float y, float z) const; + + //get corresponding TerrainData object for this particular map + const TerrainInfo * GetTerrain() const { return m_TerrainData; } + private: void LoadMapAndVMap(int gx, int gy); - void LoadVMap(int gx, int gy); - void LoadMap(int gx,int gy, bool reload = false); - GridMap *GetGrid(float x, float y); void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } @@ -313,8 +276,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void SendObjectUpdates(); std::set i_objectsToClientUpdate; 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; @@ -335,12 +296,12 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj private: time_t i_gridExpiry; - //used for fast base_map (e.g. MapInstanced class object) search for - //InstanceMaps and BattleGroundMaps... - Map* m_parentMap; - NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; - GridMap *GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + + //Shared geodata object with map coord info... + TerrainInfo * const m_TerrainData; + bool m_bLoadedGrids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; + std::bitset marked_cells; std::set i_objectsToRemove; @@ -368,7 +329,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj class MANGOS_DLL_SPEC InstanceMap : public Map { public: - InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); + InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); ~InstanceMap(); bool Add(Player *); void Remove(Player *, bool); @@ -394,7 +355,7 @@ class MANGOS_DLL_SPEC InstanceMap : public Map class MANGOS_DLL_SPEC BattleGroundMap : public Map { public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, uint8 spawnMode); ~BattleGroundMap(); void Update(const uint32&); diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp deleted file mode 100644 index 9780d8ede..000000000 --- a/src/game/MapInstanced.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2005-2010 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "MapInstanced.h" -#include "ObjectMgr.h" -#include "MapManager.h" -#include "BattleGround.h" -#include "VMapFactory.h" -#include "InstanceSaveMgr.h" -#include "World.h" - -MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) -{ - // initialize instanced maps list - m_InstancedMaps.clear(); - // fill with zero - memset(&GridMapReference, 0, MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_GRIDS*sizeof(uint16)); -} - -void MapInstanced::InitVisibilityDistance() -{ - if(m_InstancedMaps.empty()) - return; - //initialize visibility distances for all instance copies - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - { - (*i).second->InitVisibilityDistance(); - } -} - -void MapInstanced::Update(const uint32& t) -{ - // take care of loaded GridMaps (when unused, unload it!) - Map::Update(t); - - // update the instanced maps - InstancedMaps::iterator i = m_InstancedMaps.begin(); - - while (i != m_InstancedMaps.end()) - { - if(i->second->CanUnload(t)) - { - DestroyInstance(i); // iterator incremented - } - else - { - // update only here, because it may schedule some bad things before delete - i->second->Update(t); - ++i; - } - } -} - -void MapInstanced::RemoveAllObjectsInRemoveList() -{ - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - { - i->second->RemoveAllObjectsInRemoveList(); - } - - Map::RemoveAllObjectsInRemoveList(); -} - -void MapInstanced::UnloadAll(bool pForce) -{ - // Unload instanced maps - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - i->second->UnloadAll(pForce); - - // Delete the maps only after everything is unloaded to prevent crashes - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - delete i->second; - - m_InstancedMaps.clear(); - - // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) - Map::UnloadAll(pForce); -} - -/// returns a new or existing Instance -/// in case of battlegrounds it will only return an existing map, those maps are created by bg-system -Map* MapInstanced::CreateInstance(Player * player) -{ - Map* map; - uint32 NewInstanceId; // instanceId of the resulting map - - if(IsBattleGroundOrArena()) - { - // find existing bg map for player - NewInstanceId = player->GetBattleGroundId(); - MANGOS_ASSERT(NewInstanceId); - map = _FindMap(NewInstanceId); - MANGOS_ASSERT(map); - } - else if (InstanceSave* pSave = player->GetBoundInstanceSaveForSelfOrGroup(GetId())) - { - // solo/perm/group - NewInstanceId = pSave->GetInstanceId(); - map = _FindMap(NewInstanceId); - // it is possible that the save exists but the map doesn't - if (!map) - map = CreateInstanceMap(NewInstanceId, pSave->GetDifficulty(), pSave); - } - else - { - // if no instanceId via group members or instance saves is found - // the instance will be created for the first time - NewInstanceId = sObjectMgr.GenerateLowGuid(HIGHGUID_INSTANCE); - - Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid()); - map = CreateInstanceMap(NewInstanceId, diff); - } - - return map; -} - -InstanceMap* MapInstanced::CreateInstanceMap(uint32 InstanceId, Difficulty difficulty, InstanceSave *save) -{ - // load/create a map - Guard guard(*this); - - // make sure we have a valid map id - if (!sMapStore.LookupEntry(GetId())) - { - sLog.outError("CreateInstanceMap: no entry for map %d", GetId()); - MANGOS_ASSERT(false); - } - if (!ObjectMgr::GetInstanceTemplate(GetId())) - { - sLog.outError("CreateInstanceMap: no instance template for map %d", GetId()); - MANGOS_ASSERT(false); - } - - // some instances only have one difficulty - if (!GetMapDifficultyData(GetId(),difficulty)) - difficulty = DUNGEON_DIFFICULTY_NORMAL; - - DEBUG_LOG("MapInstanced::CreateInstanceMap: %s map instance %d for %d created with difficulty %d", save?"":"new ", InstanceId, GetId(), difficulty); - - InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); - MANGOS_ASSERT(map->IsDungeon()); - - bool load_data = save != NULL; - map->CreateInstanceData(load_data); - - m_InstancedMaps[InstanceId] = map; - return map; -} - -BattleGroundMap* MapInstanced::CreateBattleGroundMap(uint32 InstanceId, BattleGround* bg) -{ - // load/create a map - Guard guard(*this); - - DEBUG_LOG("MapInstanced::CreateBattleGroundMap: instance:%d for map:%d and bgType:%d created.", InstanceId, GetId(), bg->GetTypeID()); - - PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),bg->GetMinLevel()); - - uint8 spawnMode = bracketEntry ? bracketEntry->difficulty : REGULAR_DIFFICULTY; - - BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode); - MANGOS_ASSERT(map->IsBattleGroundOrArena()); - map->SetBG(bg); - bg->SetBgMap(map); - - m_InstancedMaps[InstanceId] = map; - return map; -} - -void MapInstanced::DestroyInstance(uint32 InstanceId) -{ - InstancedMaps::iterator itr = m_InstancedMaps.find(InstanceId); - if(itr != m_InstancedMaps.end()) - DestroyInstance(itr); -} - -// increments the iterator after erase -void MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) -{ - itr->second->UnloadAll(true); - // should only unload VMaps if this is the last instance and grid unloading is enabled - if(m_InstancedMaps.size() <= 1 && sWorld.getConfig(CONFIG_BOOL_GRID_UNLOAD)) - { - VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId()); - // in that case, unload grids of the base map, too - // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded - Map::UnloadAll(true); - } - // erase map - delete itr->second; - m_InstancedMaps.erase(itr++); -} diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h deleted file mode 100644 index 1a3884b2c..000000000 --- a/src/game/MapInstanced.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2005-2010 MaNGOS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MANGOS_MAP_INSTANCED_H -#define MANGOS_MAP_INSTANCED_H - -#include "Common.h" -#include "Map.h" -#include "InstanceSaveMgr.h" -#include "DBCEnums.h" - -class MANGOS_DLL_DECL MapInstanced : public Map -{ - friend class MapManager; - public: - typedef UNORDERED_MAP< uint32, Map* > InstancedMaps; - - MapInstanced(uint32 id, time_t expiry); - ~MapInstanced() {} - - // functions overwrite Map versions - void Update(const uint32&); - void RemoveAllObjectsInRemoveList(); - void UnloadAll(bool pForce); - - Map* CreateInstance(Player* player); - Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } - void DestroyInstance(uint32 InstanceId); - void DestroyInstance(InstancedMaps::iterator &itr); - - 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(GridPair const& p) - { - --GridMapReference[p.x_coord][p.y_coord]; - if (!GridMapReference[p.x_coord][p.y_coord]) - SetUnloadReferenceLock(GridPair(63-p.x_coord, 63-p.y_coord), false); - } - - InstancedMaps &GetInstancedMaps() { return m_InstancedMaps; } - virtual void InitVisibilityDistance(); - BattleGroundMap* CreateBattleGroundMap(uint32 InstanceId, BattleGround* bg); - - private: - - InstanceMap* CreateInstanceMap(uint32 InstanceId, Difficulty difficulty, InstanceSave *save = NULL); - - InstancedMaps m_InstancedMaps; - - Map* _FindMap(uint32 InstanceId) const - { - InstancedMaps::const_iterator i = m_InstancedMaps.find(InstanceId); - return(i == m_InstancedMaps.end() ? NULL : i->second); - } - - uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; -}; -#endif diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 9b12a063a..4cda78c01 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -23,16 +23,15 @@ #include "Log.h" #include "Transports.h" #include "GridDefines.h" -#include "MapInstanced.h" #include "DestinationHolderImp.h" #include "World.h" #include "CellImpl.h" #include "Corpse.h" #include "ObjectMgr.h" -#define CLASS_LOCK MaNGOS::ClassLevelLockable +#define CLASS_LOCK MaNGOS::ClassLevelLockable INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK); -INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex); +INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Recursive_Thread_Mutex); MapManager::MapManager() : i_gridCleanUpDelay(sWorld.getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN)) @@ -88,60 +87,64 @@ void MapManager::InitializeVisibilityDistanceInfo() (*iter).second->InitVisibilityDistance(); } -Map* -MapManager::_createBaseMap(uint32 id) -{ - Map *m = _findMap(id); - - if( m == NULL ) - { - Guard guard(*this); - - const MapEntry* entry = sMapStore.LookupEntry(id); - if (entry && entry->Instanceable()) - { - m = new MapInstanced(id, i_gridCleanUpDelay); - } - else - { - m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); - } - i_maps[id] = m; - } - - MANGOS_ASSERT(m != NULL); - return m; -} - Map* MapManager::CreateMap(uint32 id, const WorldObject* obj) { MANGOS_ASSERT(obj); //if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); - Map *m = _createBaseMap(id); + Guard _guard(*this); + + Map * m = NULL; - if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) - m = ((MapInstanced*)m)->CreateInstance((Player*)obj); + const MapEntry* entry = sMapStore.LookupEntry(id); + if(!entry) + return NULL; + + if(entry->Instanceable()) + { + MANGOS_ASSERT(obj->GetTypeId() == TYPEID_PLAYER); + //create InstanceMap object + if(obj->GetTypeId() == TYPEID_PLAYER) + m = CreateInstance(id, (Player*)obj); + } + else + { + //create regular Continent map + m = FindMap(id); + if( m == NULL ) + { + m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); + //add map into container + i_maps[MapID(id)] = m; + } + } return m; } Map* MapManager::CreateBgMap(uint32 mapid, BattleGround* bg) { - Map *m = _createBaseMap(mapid); - ((MapInstanced*)m)->CreateBattleGroundMap(sObjectMgr.GenerateLowGuid(HIGHGUID_INSTANCE), bg); - return m; + TerrainInfo * pData = sTerrainMgr.LoadTerrain(mapid); + + Guard _guard(*this); + return CreateBattleGroundMap(mapid, sObjectMgr.GenerateLowGuid(HIGHGUID_INSTANCE), bg); } Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const { - Map *map = _findMap(mapid); - if(!map) + Guard guard(*this); + + MapMapType::const_iterator iter = i_maps.find(MapID(mapid, instanceId)); + if(iter == i_maps.end()) return NULL; + + //this is a small workaround for transports + if(instanceId == 0 && iter->second->Instanceable()) + { + assert(false); + return NULL; + } - if(!map->Instanceable()) - return instanceId == 0 ? map : NULL; - - return ((MapInstanced*)map)->FindMap(instanceId); + return iter->second; } /* @@ -233,9 +236,20 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId) { - Map *m = _createBaseMap(mapid); - if (m && m->Instanceable()) - ((MapInstanced*)m)->DestroyInstance(instanceId); + Guard _guard(*this); + + MapMapType::iterator iter = i_maps.find(MapID(mapid, instanceId)); + if(iter != i_maps.end()) + { + Map * pMap = iter->second; + if (pMap->Instanceable()) + { + i_maps.erase(iter); + + pMap->UnloadAll(true); + delete pMap; + } + } } void @@ -251,6 +265,23 @@ MapManager::Update(uint32 diff) for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter) (*iter)->Update((uint32)i_timer.GetCurrent()); + //remove all maps which can be unloaded + MapMapType::iterator iter = i_maps.begin(); + while(iter != i_maps.end()) + { + Map * pMap = iter->second; + //check if map can be unloaded + if(pMap->CanUnload((uint32)i_timer.GetCurrent())) + { + pMap->UnloadAll(true); + delete pMap; + + i_maps.erase(iter++); + } + else + ++iter; + } + i_timer.SetCurrent(0); } @@ -287,6 +318,8 @@ void MapManager::UnloadAll() delete i_maps.begin()->second; i_maps.erase(i_maps.begin()); } + + TerrainManager::Instance().UnloadAll(); } uint32 MapManager::GetNumInstances() @@ -295,10 +328,8 @@ uint32 MapManager::GetNumInstances() for(MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { Map *map = itr->second; - if(!map->Instanceable()) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); - for(MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if(mitr->second->IsDungeon()) ret++; + if(!map->IsDungeon()) continue; + ret += 1; } return ret; } @@ -309,11 +340,103 @@ uint32 MapManager::GetNumPlayersInInstances() for(MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { Map *map = itr->second; - if(!map->Instanceable()) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); - for(MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if(mitr->second->IsDungeon()) - ret += ((InstanceMap*)mitr->second)->GetPlayers().getSize(); + if(!map->IsDungeon()) continue; + ret += map->GetPlayers().getSize(); } return ret; } + +///// returns a new or existing Instance +///// in case of battlegrounds it will only return an existing map, those maps are created by bg-system +Map* MapManager::CreateInstance(uint32 id, Player * player) +{ + Map* map = NULL; + Map * pNewMap = NULL; + uint32 NewInstanceId = 0; // instanceId of the resulting map + const MapEntry* entry = sMapStore.LookupEntry(id); + + if(entry->IsBattleGroundOrArena()) + { + // find existing bg map for player + NewInstanceId = player->GetBattleGroundId(); + MANGOS_ASSERT(NewInstanceId); + map = FindMap(id, NewInstanceId); + MANGOS_ASSERT(map); + } + else if (InstanceSave* pSave = player->GetBoundInstanceSaveForSelfOrGroup(id)) + { + // solo/perm/group + NewInstanceId = pSave->GetInstanceId(); + map = FindMap(id, NewInstanceId); + // it is possible that the save exists but the map doesn't + if (!map) + pNewMap = CreateInstanceMap(id, NewInstanceId, pSave->GetDifficulty(), pSave); + } + else + { + // if no instanceId via group members or instance saves is found + // the instance will be created for the first time + NewInstanceId = sObjectMgr.GenerateLowGuid(HIGHGUID_INSTANCE); + + Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(entry->IsRaid()) : player->GetDifficulty(entry->IsRaid()); + pNewMap = CreateInstanceMap(id, NewInstanceId, diff); + } + + //add a new map object into the registry + if(pNewMap) + { + i_maps[MapID(id, NewInstanceId)] = pNewMap; + map = pNewMap; + } + + return map; +} + +InstanceMap* MapManager::CreateInstanceMap(uint32 id, uint32 InstanceId, Difficulty difficulty, InstanceSave *save) +{ + // make sure we have a valid map id + if (!sMapStore.LookupEntry(id)) + { + sLog.outError("CreateInstanceMap: no entry for map %d", id); + MANGOS_ASSERT(false); + } + if (!ObjectMgr::GetInstanceTemplate(id)) + { + sLog.outError("CreateInstanceMap: no instance template for map %d", id); + MANGOS_ASSERT(false); + } + + // some instances only have one difficulty + if (!GetMapDifficultyData(id, difficulty)) + difficulty = DUNGEON_DIFFICULTY_NORMAL; + + DEBUG_LOG("MapInstanced::CreateInstanceMap: %s map instance %d for %d created with difficulty %d", save?"":"new ", InstanceId, id, difficulty); + + InstanceMap *map = new InstanceMap(id, i_gridCleanUpDelay, InstanceId, difficulty); + MANGOS_ASSERT(map->IsDungeon()); + + bool load_data = save != NULL; + map->CreateInstanceData(load_data); + + return map; +} + +BattleGroundMap* MapManager::CreateBattleGroundMap(uint32 id, uint32 InstanceId, BattleGround* bg) +{ + DEBUG_LOG("MapInstanced::CreateBattleGroundMap: instance:%d for map:%d and bgType:%d created.", InstanceId, id, bg->GetTypeID()); + + PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(),bg->GetMinLevel()); + + uint8 spawnMode = bracketEntry ? bracketEntry->difficulty : REGULAR_DIFFICULTY; + + BattleGroundMap *map = new BattleGroundMap(id, i_gridCleanUpDelay, InstanceId, spawnMode); + MANGOS_ASSERT(map->IsBattleGroundOrArena()); + map->SetBG(bg); + bg->SetBgMap(map); + + //add map into map container + i_maps[MapID(id, InstanceId)] = map; + + return map; +} + diff --git a/src/game/MapManager.h b/src/game/MapManager.h index a578c2f4b..e1f64da48 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -22,25 +22,45 @@ #include "Common.h" #include "Platform/Define.h" #include "Policies/Singleton.h" -#include "ace/Thread_Mutex.h" +#include "ace/Recursive_Thread_Mutex.h" #include "Map.h" #include "GridStates.h" class Transport; class BattleGround; -class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton > +struct MANGOS_DLL_DECL MapID { + explicit MapID(uint32 id) : nMapId(id), nInstanceId(0) {} + MapID(uint32 id, uint32 instid) : nMapId(id), nInstanceId(instid) {} + bool operator<(const MapID& val) const + { + if(nMapId == val.nMapId) + return nInstanceId < val.nInstanceId; + + return nMapId < val.nMapId; + } + + bool operator==(const MapID& val) const { return nMapId == val.nMapId && nInstanceId == val.nInstanceId; } + + uint32 nMapId; + uint32 nInstanceId; +}; + +class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton > +{ friend class MaNGOS::OperatorNew; - typedef UNORDERED_MAP MapMapType; - typedef std::pair::iterator, bool> MapMapPair; + + typedef ACE_Recursive_Thread_Mutex LOCK_TYPE; + typedef ACE_Guard LOCK_TYPE_GUARD; + typedef MaNGOS::ClassLevelLockable::Lock Guard; public: + typedef std::map MapMapType; Map* CreateMap(uint32, const WorldObject* obj); Map* CreateBgMap(uint32 mapid, BattleGround* bg); - Map const* CreateBaseMap(uint32 id) const { return const_cast(this)->_createBaseMap(id); } Map* FindMap(uint32 mapid, uint32 instanceId = 0) const; void UpdateGridState(grid_state_t state, Map& map, NGridType& ngrid, GridInfo& ginfo, const uint32 &x, const uint32 &y, const uint32 &t_diff); @@ -48,24 +68,6 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::SingletonGetAreaFlag(x, y, z); - } - uint32 GetAreaId(uint32 mapid, float x, float y, float z) const - { - return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); - } - uint32 GetZoneId(uint32 mapid, float x, float y, float z) const - { - return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); - } - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) - { - Map::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid); - } - void Initialize(void); void Update(uint32); @@ -144,6 +146,10 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singletonsecond); - } + Map* CreateInstance(uint32 id, Player * player); + InstanceMap* CreateInstanceMap(uint32 id, uint32 InstanceId, Difficulty difficulty, InstanceSave *save = NULL); + BattleGroundMap* CreateBattleGroundMap(uint32 id, uint32 InstanceId, BattleGround* bg); - typedef MaNGOS::ClassLevelLockable::Lock Guard; uint32 i_gridCleanUpDelay; MapMapType i_maps; IntervalTimer i_timer; diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 9355ca9ad..2fead25de 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -544,7 +544,7 @@ void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo, Unit* mover if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water - plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); + plMover->SetInWater( !plMover->IsInWater() || plMover->GetTerrain()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); } plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 18f27ec60..8f7fd9959 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1160,17 +1160,17 @@ void WorldObject::Relocate(float x, float y, float z) uint32 WorldObject::GetZoneId() const { - return GetBaseMap()->GetZoneId(m_positionX, m_positionY, m_positionZ); + return GetTerrain()->GetZoneId(m_positionX, m_positionY, m_positionZ); } uint32 WorldObject::GetAreaId() const { - return GetBaseMap()->GetAreaId(m_positionX, m_positionY, m_positionZ); + return GetTerrain()->GetAreaId(m_positionX, m_positionY, m_positionZ); } void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { - GetBaseMap()->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ); + GetTerrain()->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ); } InstanceData* WorldObject::GetInstanceData() const @@ -1458,7 +1458,7 @@ void WorldObject::GetRandomPoint( float x, float y, float z, float distance, flo void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const { - float new_z = GetBaseMap()->GetHeight(x,y,z,true); + float new_z = GetTerrain()->GetHeight(x,y,z,true); if(new_z > INVALID_HEIGHT) z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface } @@ -1476,8 +1476,8 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const bool CanSwim = ((Creature const*)this)->CanSwim(); float ground_z = z; float max_z = CanSwim - ? GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)) - : ((ground_z = GetBaseMap()->GetHeight(x, y, z, true))); + ? GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)) + : ((ground_z = GetTerrain()->GetHeight(x, y, z, true))); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -1488,7 +1488,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + float ground_z = GetTerrain()->GetHeight(x, y, z, true); if (z < ground_z) z = ground_z; } @@ -1500,7 +1500,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const if (!((Player const*)this)->CanFly()) { float ground_z = z; - float max_z = GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)); + float max_z = GetTerrain()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)); if (max_z > INVALID_HEIGHT) { if (z > max_z) @@ -1511,7 +1511,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } else { - float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + float ground_z = GetTerrain()->GetHeight(x, y, z, true); if (z < ground_z) z = ground_z; } @@ -1519,7 +1519,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } default: { - float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + float ground_z = GetTerrain()->GetHeight(x, y, z, true); if(ground_z > INVALID_HEIGHT) z = ground_z; break; @@ -1713,10 +1713,10 @@ void WorldObject::SetMap(Map * map) m_InstanceId = map->GetInstanceId(); } -Map const* WorldObject::GetBaseMap() const +TerrainInfo const* WorldObject::GetTerrain() const { MANGOS_ASSERT(m_currMap); - return m_currMap->GetParent(); + return m_currMap->GetTerrain(); } void WorldObject::AddObjectToRemoveList() diff --git a/src/game/Object.h b/src/game/Object.h index 653b169b4..795d21d5a 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -69,6 +69,7 @@ class Unit; class Map; class UpdateMask; class InstanceData; +class TerrainInfo; typedef UNORDERED_MAP UpdateDataMapType; @@ -480,8 +481,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object //used to check all object's GetMap() calls when object is not in world! void ResetMap() { m_currMap = NULL; } - //this function should be removed in nearest time... - Map const* GetBaseMap() const; + //obtain terrain data for map where this object belong... + TerrainInfo const* GetTerrain() const; void AddToClientUpdateList(); void RemoveFromClientUpdateList(); diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index a1a21df0e..56176ae39 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -34,7 +34,6 @@ #include "GridNotifiersImpl.h" #include "Opcodes.h" #include "ObjectGuid.h" -#include "MapInstanced.h" #include "World.h" #include diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index d43dd94b2..0368c4073 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -5942,7 +5942,7 @@ void ObjectMgr::LoadGraveyardZones() WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team) { // search for zone associated closest graveyard - uint32 zoneId = sMapMgr.GetZoneId(MapId,x,y,z); + uint32 zoneId = sTerrainMgr.GetZoneId(MapId,x,y,z); // Simulate std. algorithm: // found some graveyard associated to (ghost_zone,ghost_map) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 6b4dcdab5..0c50c56b2 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -34,7 +34,6 @@ #include "Channel.h" #include "ChannelMgr.h" #include "MapManager.h" -#include "MapInstanced.h" #include "InstanceSaveMgr.h" #include "InstanceData.h" #include "GridNotifiers.h" @@ -1444,7 +1443,7 @@ void Player::Update( uint32 p_time ) } // not auto-free ghost from body in instances - if(m_deathTimer > 0 && !GetBaseMap()->Instanceable()) + if(m_deathTimer > 0 && !GetMap()->Instanceable()) { if(p_time >= m_deathTimer) { @@ -2324,7 +2323,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo bool Player::IsUnderWater() const { - return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()+2); + return GetTerrain()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()+2); } void Player::SetInWater(bool apply) @@ -6139,7 +6138,7 @@ void Player::CheckAreaExploreAndOutdoor() return; bool isOutdoor; - uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ(), &isOutdoor); + uint16 areaFlag = GetTerrain()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ(), &isOutdoor); if (isOutdoor) { @@ -6665,7 +6664,7 @@ uint32 Player::GetZoneIdFromDB(ObjectGuid guid) float posz = fields[3].GetFloat(); delete result; - zone = sMapMgr.GetZoneId(map,posx,posy,posz); + zone = sTerrainMgr.GetZoneId(map,posx,posy,posz); if (zone > 0) CharacterDatabase.PExecute("UPDATE characters SET zone='%u' WHERE guid='%u'", zone, lowguid); @@ -20845,7 +20844,7 @@ void Player::SetOriginalGroup(Group *group, int8 subgroup) void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { GridMapLiquidData liquid_status; - GridMapLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + GridMapLiquidStatus res = m->GetTerrain()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); if (!res) { m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWATER_INDARKWATER); diff --git a/src/game/PoolManager.cpp b/src/game/PoolManager.cpp index b3df9e2c6..c6684ca53 100644 --- a/src/game/PoolManager.cpp +++ b/src/game/PoolManager.cpp @@ -368,7 +368,10 @@ void PoolGroup::Spawn1Object(PoolObject* obj, bool instantly) sObjectMgr.AddCreatureToGrid(obj->guid, data); // Spawn if necessary (loaded grids only) - Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); + Map* map = const_cast(sMapMgr.FindMap(data->mapid)); + if(!map) + return; + // We use spawn coords to spawn (avoid work for instances until implemented support) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { @@ -408,7 +411,10 @@ void PoolGroup::Spawn1Object(PoolObject* obj, bool instantly) sObjectMgr.AddGameobjectToGrid(obj->guid, data); // Spawn if necessary (loaded grids only) // this base map checked as non-instanced and then only existing - Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); + Map* map = const_cast(sMapMgr.FindMap(data->mapid)); + if(!map) + return; + // We use current coords to unspawn, not spawn coords since creature can have changed grid // (avoid work for instances until implemented support) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp index 8515ed975..1f0e25f93 100644 --- a/src/game/QueryHandler.cpp +++ b/src/game/QueryHandler.cpp @@ -296,7 +296,7 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recv_data*/) if (corpseMapEntry->IsDungeon() && corpseMapEntry->ghost_entrance_map >= 0) { // if corpse map have entrance - if (Map const* entranceMap = sMapMgr.CreateBaseMap(corpseMapEntry->ghost_entrance_map)) + if(TerrainInfo const* entranceMap = sTerrainMgr.LoadTerrain(corpseMapEntry->ghost_entrance_map)) { mapid = corpseMapEntry->ghost_entrance_map; x = corpseMapEntry->ghost_entrance_x; diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp index 892aeb17a..fbc0f0e00 100644 --- a/src/game/RandomMovementGenerator.cpp +++ b/src/game/RandomMovementGenerator.cpp @@ -32,7 +32,7 @@ RandomMovementGenerator::_setRandomLocation(Creature &creature) creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance); currZ = creature.GetPositionZ(); - Map const* map = creature.GetBaseMap(); + TerrainInfo const* map = creature.GetTerrain(); // For 2D/3D system selection //bool is_land_ok = creature.CanWalk(); // not used? diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 1e9afeac6..8c1e70e0b 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4243,11 +4243,11 @@ SpellCastResult Spell::CheckCast(bool strict) VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled()) { if (m_spellInfo->Attributes & SPELL_ATTR_OUTDOORS_ONLY && - !m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ())) + !m_caster->GetTerrain()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ())) return SPELL_FAILED_ONLY_OUTDOORS; if(m_spellInfo->Attributes & SPELL_ATTR_INDOORS_ONLY && - m_caster->GetMap()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ())) + m_caster->GetTerrain()->IsOutdoors(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ())) return SPELL_FAILED_ONLY_INDOORS; } // only check at first call, Stealth auras are already removed at second call @@ -5130,7 +5130,7 @@ SpellCastResult Spell::CheckCast(bool strict) float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); // teleport a bit above terrain level to avoid falling below it - float fz = m_caster->GetBaseMap()->GetHeight(fx, fy, m_caster->GetPositionZ(), true); + float fz = m_caster->GetTerrain()->GetHeight(fx, fy, m_caster->GetPositionZ(), true); if(fz <= INVALID_HEIGHT) // note: this also will prevent use effect in instances without vmaps height enabled return SPELL_FAILED_TRY_AGAIN; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index b65087a03..68e1efafa 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -7819,7 +7819,7 @@ void Spell::EffectTransmitted(SpellEffectIndex eff_idx) if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE) { GridMapLiquidData liqData; - if ( !cMap->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole + if ( !m_caster->GetTerrain()->IsInWater(fx, fy, fz + 1.f/* -0.5f */, &liqData)) // Hack to prevent fishing bobber from failing to land on fishing hole { // but this is not proper, we really need to ignore not materialized objects SendCastResult(SPELL_FAILED_NOT_HERE); SendChannelUpdate(0); @@ -8156,7 +8156,7 @@ void Spell::EffectBind(SpellEffectIndex eff_idx) loc.coord_y = st->target_Y; loc.coord_z = st->target_Y; loc.orientation = st->target_Orientation; - area_id = sMapMgr.GetAreaId(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z); + area_id = sTerrainMgr.GetAreaId(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z); } else { diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 97c0acb9a..b4af83d07 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1016,7 +1016,7 @@ void SpellMgr::LoadSpellTargetPositions() // additional requirements if (spellInfo->Effect[i]==SPELL_EFFECT_BIND && spellInfo->EffectMiscValue[i]) { - uint32 zone_id = sMapMgr.GetAreaId(st.target_mapId, st.target_X, st.target_Y, st.target_Z); + uint32 zone_id = sTerrainMgr.GetAreaId(st.target_mapId, st.target_X, st.target_Y, st.target_Z); if (int32(zone_id) != spellInfo->EffectMiscValue[i]) { sLog.outErrorDb("Spell (Id: %u) listed in `spell_target_position` expected point to zone %u bit point to zone %u.",Spell_ID, spellInfo->EffectMiscValue[i], zone_id); diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp index 0c3431d07..213d416ca 100644 --- a/src/game/Transports.cpp +++ b/src/game/Transports.cpp @@ -91,6 +91,14 @@ void MapManager::LoadTransports() uint32 mapid; x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1; + //current code does not support transports in dungeon! + const MapEntry* pMapInfo = sMapStore.LookupEntry(mapid); + if(!pMapInfo || pMapInfo->Instanceable()) + { + delete t; + continue; + } + // creates the Gameobject if (!t->Create(entry, mapid, x, y, z, o, GO_ANIMPROGRESS_DEFAULT, 0)) { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index aeba536de..5f6bc7aec 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3712,12 +3712,12 @@ bool Unit::isInAccessablePlaceFor(Creature const* c) const bool Unit::IsInWater() const { - return GetBaseMap()->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ()); + return GetTerrain()->IsInWater(GetPositionX(),GetPositionY(), GetPositionZ()); } bool Unit::IsUnderWater() const { - return GetBaseMap()->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ()); + return GetTerrain()->IsUnderWater(GetPositionX(),GetPositionY(),GetPositionZ()); } void Unit::DeMorph() diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp index 7ce3829a9..603a4eed1 100644 --- a/src/game/WaypointManager.cpp +++ b/src/game/WaypointManager.cpp @@ -152,7 +152,7 @@ void WaypointManager::Load() if (result1) { - node.z = MapManager::Instance ().CreateBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z); + node.z = sTerrainMgr.LoadTerrain(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z); delete result1; } diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp index ba55359ce..b07341446 100644 --- a/src/game/WaypointMovementGenerator.cpp +++ b/src/game/WaypointMovementGenerator.cpp @@ -335,7 +335,7 @@ void FlightPathMovementGenerator::Finalize(Player & player) player.clearUnitState(UNIT_STAT_TAXI_FLIGHT); float x, y, z; - i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z); + i_destinationHolder.GetLocationNow(player.GetMap(), x, y, z); player.SetPosition(x, y, z, player.GetOrientation()); player.Unmount(); diff --git a/src/game/World.cpp b/src/game/World.cpp index 8dc40472f..f04c39786 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1507,6 +1507,9 @@ void World::Update(uint32 diff) // And last, but not least handle the issued cli commands ProcessCliCommands(); + + //cleanup unused GridMap objects as well as VMaps + sTerrainMgr.Update(diff); } /// Send a packet to all players (except self if mentioned) diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index e0da12ad7..1abeafd25 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 "10726" + #define REVISION_NR "10727" #endif // __REVISION_NR_H__ diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 4525ed4b6..aa0969c6f 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -426,7 +426,6 @@ - @@ -472,7 +471,7 @@ - + @@ -573,7 +572,6 @@ - diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index 2cec6632e..e0850cef2 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -159,9 +159,6 @@ World/Handlers - - World/Handlers - World/Handlers @@ -552,9 +549,6 @@ World/Handlers - - World/Handlers - World/Handlers diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index d083dbdf2..2ffaaacfa 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -100,6 +100,90 @@ Name="VCPostBuildEventTool" /> + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - @@ -633,6 +625,14 @@ RelativePath="..\..\src\game\BattleGroundNA.h" > + + + + @@ -841,14 +841,6 @@ RelativePath="..\..\src\game\Map.h" > - - - - @@ -965,10 +957,6 @@ RelativePath="..\..\src\game\SpellAuras.h" > - - @@ -993,6 +981,10 @@ RelativePath="..\..\src\game\Transports.h" > + + @@ -1639,7 +1631,7 @@ /> - - - - @@ -958,10 +950,6 @@ RelativePath="..\..\src\game\SpellAuras.h" > - - @@ -986,6 +974,10 @@ RelativePath="..\..\src\game\Transports.h" > + +