diff --git a/sql/updates/auth/2015_03_15_00_auth.sql b/sql/updates/auth/2015_03_15_00_auth.sql new file mode 100644 index 0000000000..339524a509 --- /dev/null +++ b/sql/updates/auth/2015_03_15_00_auth.sql @@ -0,0 +1,12 @@ +DELETE FROM `rbac_permissions` WHERE `id`=776; +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES (776, 'Command: debug phase'); + +DELETE FROM `rbac_linked_permissions` WHERE `id`=192 AND linkedId=776; +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES (192, 776); + +DELETE FROM `rbac_permissions` WHERE `id`=776; +INSERT INTO `rbac_permissions` (`id`, `name`) VALUES (776, 'Command: debug phase'); + +DELETE FROM `rbac_linked_permissions` WHERE `id`=192 AND linkedId=776; +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES (192, 776); + diff --git a/sql/updates/characters/2015_03_29_00_characters.sql b/sql/updates/characters/2015_03_29_00_characters.sql new file mode 100644 index 0000000000..b9bb746c2f --- /dev/null +++ b/sql/updates/characters/2015_03_29_00_characters.sql @@ -0,0 +1,11 @@ +ALTER TABLE `corpse` DROP `phaseMask`; + +DROP TABLE IF EXISTS `corpse_phases`; +CREATE TABLE `corpse_phases` ( + `Guid` int(10) unsigned NOT NULL, + `PhaseId` int(10) unsigned NOT NULL, + `OwnerGuid` int(10) unsigned NOT NULL, + `Time` int(10) unsigned NOT NULL DEFAULT '0', + `CorpseType` tinyint(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`Guid`,`PhaseId`) +); \ No newline at end of file diff --git a/sql/updates/world/2015_03_29_01_world.sql b/sql/updates/world/2015_03_29_01_world.sql new file mode 100644 index 0000000000..88c2bbc4fc --- /dev/null +++ b/sql/updates/world/2015_03_29_01_world.sql @@ -0,0 +1,57 @@ +DROP TABLE IF EXISTS `phase_definitions`; +DROP TABLE IF EXISTS `phase_info`; +DROP TABLE IF EXISTS `terrain_phase_info`; +DROP TABLE IF EXISTS `terrain_map_info`; +DROP TABLE IF EXISTS `terrain_swap_defaults`; +DROP TABLE IF EXISTS `terrain_worldmap`; +DROP TABLE IF EXISTS `phase_area`; + +CREATE TABLE `terrain_phase_info`( + `Id` INT(10) unsigned NOT NULL, + `TerrainSwapMap` INT(10) unsigned NOT NULL, + `Comment` VARCHAR(255), + PRIMARY KEY (`Id`, `TerrainSwapMap`) +); + +CREATE TABLE `terrain_swap_defaults`( + `MapId` INT(10) unsigned NOT NULL, + `TerrainSwapMap` INT(10) unsigned NOT NULL, + `Comment` VARCHAR(255), + PRIMARY KEY (`MapId`, `TerrainSwapMap`) +); + +CREATE TABLE `terrain_worldmap`( + `TerrainSwapMap` INT(10) unsigned NOT NULL, + `WorldMapArea` INT(10) unsigned NOT NULL, + `Comment` VARCHAR(255), + PRIMARY KEY (`TerrainSwapMap`, `WorldMapArea`) +); + +CREATE TABLE `phase_area` ( + `AreaId` int(10) unsigned NOT NULL, + `PhaseId` int(10) unsigned NOT NULL, + `Comment` varchar(255) DEFAULT NULL, + PRIMARY KEY (`AreaId`,`PhaseId`) +); + +INSERT INTO `terrain_phase_info` (Id, TerrainSwapMap, Comment) VALUES +(182, 655, 'Quest Zone-Specific 07'), +(186, 656, 'Quest Zone-Specific 11'); + +INSERT INTO `terrain_worldmap` (TerrainSwapMap, WorldMapArea, Comment) VALUES +(638, 545, 'Gilneas'), +(655, 678, 'Gilneas_terrain1'), +(719, 683, 'Hyjal_terrain1'), +(656, 679, 'Gilneas_terrain2'); + +INSERT INTO `terrain_swap_defaults` (MapId, TerrainSwapMap, Comment) VALUES +(1, 719, 'Mount Hyjal default terrain'), +(654, 638, 'Gilneas default terrain'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=25 AND `SourceEntry`=719; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(25, 0, 719, 0, 0, 8, 0, 25372, 0, 0, 1, 0, 0, '', 'Hyjal terrain swap if Aessina''s Miracle quest is not rewarded'); + +ALTER TABLE `creature` DROP `phaseMask`; +ALTER TABLE `gameobject` DROP `phaseMask`; + diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index b9277d6082..914f919bf7 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -19,6 +19,8 @@ #include "MMapManager.h" #include "Log.h" #include "World.h" +#include "DBCStores.h" +#include "MMapFactory.h" namespace MMAP { @@ -76,8 +78,7 @@ namespace MMAP TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId); // store inside our map list - MMapData* mmap_data = new MMapData(mesh); - mmap_data->mmapLoadedTiles.clear(); + MMapData* mmap_data = new MMapData(mesh, mapId); loadedMMaps.insert(std::pair(mapId, mmap_data)); return true; @@ -100,7 +101,7 @@ namespace MMAP // check if we already have this tile loaded uint32 packedGridPos = packTileID(x, y); - if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end()) + if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end()) return false; // load this tile :: mmaps/MMMXXYY.mmtile @@ -152,19 +153,120 @@ namespace MMAP dtTileRef tileRef = 0; // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed - if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) + if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, NULL/*DT_TILE_FREE_DATA*/, 0, &tileRef))) { - mmap->mmapLoadedTiles.insert(std::pair(packedGridPos, tileRef)); + mmap->loadedTileRefs.insert(std::pair(packedGridPos, tileRef)); ++loadedTiles; TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y); + + LoadPhaseTiles(mapId, x, y); + return true; } + else + { + TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); + dtFree(data); + return false; + } - TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); - dtFree(data); return false; } + PhasedTile* MMapManager::LoadTile(uint32 mapId, int32 x, int32 y) + { + // load this tile :: mmaps/MMMXXYY.mmtile + uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1; + char *fileName = new char[pathLen]; + + snprintf(fileName, pathLen, (sWorld->GetDataPath() + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); + + FILE* file = fopen(fileName, "rb"); + if (!file) + { + // Not all tiles have phased versions, don't flood this msg + //TC_LOG_DEBUG("phase", "MMAP:LoadTile: Could not open mmtile file '%s'", fileName); + delete[] fileName; + return NULL; + } + delete[] fileName; + + PhasedTile* pTile = new PhasedTile(); + + // read header + if (fread(&pTile->fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || pTile->fileHeader.mmapMagic != MMAP_MAGIC) + { + TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y); + fclose(file); + return NULL; + } + + if (pTile->fileHeader.mmapVersion != MMAP_VERSION) + { + TC_LOG_ERROR("phase", "MMAP:LoadTile: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", + mapId, x, y, pTile->fileHeader.mmapVersion, MMAP_VERSION); + fclose(file); + return NULL; + } + + pTile->data = (unsigned char*)dtAlloc(pTile->fileHeader.size, DT_ALLOC_PERM); + ASSERT(pTile->data); + + size_t result = fread(pTile->data, pTile->fileHeader.size, 1, file); + if (!result) + { + TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y); + fclose(file); + return NULL; + } + + fclose(file); + + return pTile; + } + + void MMapManager::LoadPhaseTiles(uint32 mapId, int32 x, int32 y) + { + TC_LOG_DEBUG("phase", "MMAP:LoadPhaseTiles: Loading phased mmtiles for map %u, x: %i, y: %i", mapId, x, y); + + uint32 packedGridPos = packTileID(x, y); + + for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + { + if (const MapEntry* const map = sMapStore.LookupEntry(i)) + { + if (map->ParentMapID == mapId) + { + PhasedTile* data = LoadTile(map->ID, x, y); + // only a few tiles have terrain swaps, do not write error for them + if (data) + { + TC_LOG_DEBUG("phase", "MMAP:LoadPhaseTiles: Loaded phased %03u%02i%02i.mmtile for root phase map %u", map->ID, x, y, mapId); + _phaseTiles[map->ID][packedGridPos] = data; + } + } + } + } + } + + void MMapManager::UnloadPhaseTile(uint32 mapId, int32 x, int32 y) + { + TC_LOG_DEBUG("phase", "MMAP:UnloadPhaseTile: Unloading phased mmtile for map %u, x: %i, y: %i", mapId, x, y); + + uint32 packedGridPos = packTileID(x, y); + + const MapEntry* const map = sMapStore.LookupEntry(mapId); // map existence already checked when loading + uint32 rootMapId = map->ParentMapID; + + if (_phaseTiles[mapId][packedGridPos]) + { + TC_LOG_DEBUG("phase", "MMAP:UnloadPhaseTile: Unloaded phased %03u%02i%02i.mmtile for root phase map %u", mapId, x, y, rootMapId); + delete _phaseTiles[mapId][packedGridPos]->data; + delete _phaseTiles[mapId][packedGridPos]; + _phaseTiles[mapId].erase(packedGridPos); + } + } + bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y) { // check if we have this map loaded @@ -179,14 +281,14 @@ namespace MMAP // check if we have this tile loaded uint32 packedGridPos = packTileID(x, y); - if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end()) + if (mmap->loadedTileRefs.find(packedGridPos) == mmap->loadedTileRefs.end()) { // file may not exist, therefore not loaded TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y); return false; } - dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos]; + dtTileRef tileRef = mmap->loadedTileRefs[packedGridPos]; // unload, and mark as non loaded if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, NULL, NULL))) @@ -199,9 +301,11 @@ namespace MMAP } else { - mmap->mmapLoadedTiles.erase(packedGridPos); + mmap->loadedTileRefs.erase(packedGridPos); --loadedTiles; TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); + + UnloadPhaseTile(mapId, x, y); return true; } @@ -219,7 +323,7 @@ namespace MMAP // unload all tiles from given map MMapData* mmap = loadedMMaps[mapId]; - for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i) + for (MMapTileSet::iterator i = mmap->loadedTileRefs.begin(); i != mmap->loadedTileRefs.end(); ++i) { uint32 x = (i->first >> 16); uint32 y = (i->first & 0x0000FFFF); @@ -227,6 +331,7 @@ namespace MMAP TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); else { + UnloadPhaseTile(mapId, x, y); --loadedTiles; TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); } @@ -265,15 +370,15 @@ namespace MMAP return true; } - dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId) + dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId, TerrainSet swaps) { if (loadedMMaps.find(mapId) == loadedMMaps.end()) return NULL; - return loadedMMaps[mapId]->navMesh; + return loadedMMaps[mapId]->GetNavMesh(swaps); } - dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId) + dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId, TerrainSet swaps) { if (loadedMMaps.find(mapId) == loadedMMaps.end()) return NULL; @@ -284,7 +389,7 @@ namespace MMAP // allocate mesh query dtNavMeshQuery* query = dtAllocNavMeshQuery(); ASSERT(query); - if (dtStatusFailed(query->init(mmap->navMesh, 1024))) + if (dtStatusFailed(query->init(mmap->GetNavMesh(swaps), 1024))) { dtFreeNavMeshQuery(query); TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); @@ -297,4 +402,155 @@ namespace MMAP return mmap->navMeshQueries[instanceId]; } + + MMapData::MMapData(dtNavMesh* mesh, uint32 mapId) + { + navMesh = mesh; + _mapId = mapId; + } + + MMapData::~MMapData() + { + for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i) + dtFreeNavMeshQuery(i->second); + + dtFreeNavMesh(navMesh); + + for (PhaseTileContainer::iterator i = _baseTiles.begin(); i != _baseTiles.end(); ++i) + { + delete (*i).second->data; + delete (*i).second; + } + } + + void MMapData::RemoveSwap(PhasedTile* ptile, uint32 swap, uint32 packedXY) + { + uint32 x = (packedXY >> 16); + uint32 y = (packedXY & 0x0000FFFF); + + if (loadedPhasedTiles[swap].find(packedXY) == loadedPhasedTiles[swap].end()) + { + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: mmtile %03u[%02i, %02i] unload skipped, due to not loaded", swap, x, y); + return; + } + dtMeshHeader* header = (dtMeshHeader*)ptile->data; + + // remove old tile + if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], NULL, NULL))) + TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not unload phased %03u%02i%02i.mmtile from navmesh", swap, x, y); + else + { + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Unloaded phased %03u%02i%02i.mmtile from navmesh", swap, x, y); + + // restore base tile + if (dtStatusSucceed(navMesh->addTile(_baseTiles[packedXY]->data, _baseTiles[packedXY]->dataSize, NULL, 0, &loadedTileRefs[packedXY]))) + { + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Loaded base mmtile %03u[%02i, %02i] into %03i[%02i, %02i]", _mapId, x, y, _mapId, header->x, header->y); + } + else + TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not load base %03u%02i%02i.mmtile to navmesh", _mapId, x, y); + } + + loadedPhasedTiles[swap].erase(packedXY); + + if (loadedPhasedTiles[swap].empty()) + { + _activeSwaps.erase(swap); + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Fully removed swap %u from map %u", swap, _mapId); + } + } + + void MMapData::AddSwap(PhasedTile* ptile, uint32 swap, uint32 packedXY) + { + + uint32 x = (packedXY >> 16); + uint32 y = (packedXY & 0x0000FFFF); + + if (loadedTileRefs.find(packedXY) == loadedTileRefs.end()) + { + TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %03u[%02i, %02i] load skipped, due to not loaded base tile on map %u", swap, x, y, _mapId); + return; + } + if (loadedPhasedTiles[swap].find(packedXY) != loadedPhasedTiles[swap].end()) + { + TC_LOG_DEBUG("phase", "MMapData::AddSwap: WARNING! phased mmtile %03u[%02i, %02i] load skipped, due to already loaded on map %u", swap, x, y, _mapId); + return; + } + + + dtMeshHeader* header = (dtMeshHeader*)ptile->data; + + const dtMeshTile* oldTile = navMesh->getTileByRef(loadedTileRefs[packedXY]); + + if (!oldTile) + { + TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %03u[%02i, %02i] load skipped, due to not loaded base tile ref on map %u", swap, x, y, _mapId); + return; + } + + uint32 old_x = oldTile->header->x; + uint32 old_y = oldTile->header->y; + + // header xy is based on the swap map's tile set, wich doesn't have all the same tiles as root map, so copy the xy from the orignal header + memcpy(ptile->data + 8, (char*)&old_x, 4); + memcpy(ptile->data + 12, (char*)&old_y, 4); + + // the removed tile's data + PhasedTile* pt = new PhasedTile(); + // remove old tile + if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], &pt->data, &pt->dataSize))) + TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not unload %03u%02i%02i.mmtile from navmesh", _mapId, x, y); + else + { + TC_LOG_DEBUG("phase", "MMapData::AddSwap: Unloaded %03u%02i%02i.mmtile from navmesh", _mapId, x, y); + + // store the removed data first time, this is the origonal, non-phased tile + if (_baseTiles.find(packedXY) == _baseTiles.end()) + _baseTiles[packedXY] = pt; + + _activeSwaps.insert(swap); + loadedPhasedTiles[swap].insert(packedXY); + + // add new swapped tile + if (dtStatusSucceed(navMesh->addTile(ptile->data, ptile->fileHeader.size, NULL, 0, &loadedTileRefs[packedXY]))) + { + TC_LOG_DEBUG("phase", "MMapData::AddSwap: Loaded phased mmtile %03u[%02i, %02i] into %03i[%02i, %02i]", swap, x, y, _mapId, header->x, header->y); + } + else + TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not load %03u%02i%02i.mmtile to navmesh", swap, x, y); + } + } + + dtNavMesh* MMapData::GetNavMesh(TerrainSet swaps) + { + for (uint32 swap : _activeSwaps) + { + if (swaps.find(swap) == swaps.end()) // swap not active + { + PhaseTileContainer ptc = MMAP::MMapFactory::createOrGetMMapManager()->GetPhaseTileContainer(swap); + for (PhaseTileContainer::const_iterator itr = ptc.begin(); itr != ptc.end(); ++itr) + { + RemoveSwap(itr->second, swap, itr->first); // remove swap + } + } + } + + if (!swaps.empty()) + { + // for each of the calling unit's terrain swaps + for (uint32 swap : swaps) + { + // for each of the terrain swap's xy tiles + PhaseTileContainer ptc = MMAP::MMapFactory::createOrGetMMapManager()->GetPhaseTileContainer(swap); + for (PhaseTileContainer::const_iterator itr = ptc.begin(); itr != ptc.end(); ++itr) + { + if (_activeSwaps.find(swap) == _activeSwaps.end()) // swap not active + { + AddSwap(itr->second, swap, itr->first); // add swap + } + } + } + } + return navMesh; + } } diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h index 2169d82bb3..b7356716a9 100644 --- a/src/server/collision/Management/MMapManager.h +++ b/src/server/collision/Management/MMapManager.h @@ -23,8 +23,10 @@ #include "DetourAlloc.h" #include "DetourNavMesh.h" #include "DetourNavMeshQuery.h" +#include "World.h" #include #include +#include // move map related classes namespace MMAP @@ -32,24 +34,54 @@ namespace MMAP typedef std::unordered_map MMapTileSet; typedef std::unordered_map NavMeshQuerySet; - // dummy struct to hold map's mmap data - struct MMapData + + typedef std::set TerrainSet; + + struct NavMeshHolder { - MMapData(dtNavMesh* mesh) : navMesh(mesh) { } - ~MMapData() - { - for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i) - dtFreeNavMeshQuery(i->second); - - if (navMesh) - dtFreeNavMesh(navMesh); - } - + // Pre-built navMesh dtNavMesh* navMesh; + // List of terrain swap map ids used to build the navMesh + TerrainSet terrainIds; + + MMapTileSet loadedTileRefs; + }; + + struct PhasedTile + { + unsigned char* data; + MmapTileHeader fileHeader; + int32 dataSize; + }; + + typedef std::unordered_map PhaseTileContainer; + typedef std::unordered_map PhaseTileMap; + + + typedef std::unordered_map TerrainSetMap; + + class MMapData + { + public: + MMapData(dtNavMesh* mesh, uint32 mapId); + ~MMapData(); + + dtNavMesh* GetNavMesh(TerrainSet swaps); + // we have to use single dtNavMeshQuery for every instance, since those are not thread safe NavMeshQuerySet navMeshQueries; // instanceId to query - MMapTileSet mmapLoadedTiles; // maps [map grid coords] to [dtTile] + + dtNavMesh* navMesh; + MMapTileSet loadedTileRefs; + TerrainSetMap loadedPhasedTiles; + + private: + uint32 _mapId; + PhaseTileContainer _baseTiles; + std::set _activeSwaps; + void RemoveSwap(PhasedTile* ptile, uint32 swap, uint32 packedXY); + void AddSwap(PhasedTile* tile, uint32 swap, uint32 packedXY); }; @@ -69,17 +101,25 @@ namespace MMAP bool unloadMapInstance(uint32 mapId, uint32 instanceId); // the returned [dtNavMeshQuery const*] is NOT threadsafe - dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId); - dtNavMesh const* GetNavMesh(uint32 mapId); + dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId, TerrainSet swaps); + dtNavMesh const* GetNavMesh(uint32 mapId, TerrainSet swaps); uint32 getLoadedTilesCount() const { return loadedTiles; } - uint32 getLoadedMapsCount() const { return uint32(loadedMMaps.size()); } + uint32 getLoadedMapsCount() const { return loadedMMaps.size(); } + + void LoadPhaseTiles(uint32 mapId, int32 x, int32 y); + void UnloadPhaseTile(uint32 mapId, int32 x, int32 y); + PhaseTileContainer GetPhaseTileContainer(uint32 mapId) { return _phaseTiles[mapId]; } + private: bool loadMapData(uint32 mapId); uint32 packTileID(int32 x, int32 y); MMapDataSet loadedMMaps; uint32 loadedTiles; + + PhasedTile* LoadTile(uint32 mapId, int32 x, int32 y); + PhaseTileMap _phaseTiles; }; } diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index b0a878aff3..c5e3d26b00 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -424,6 +424,11 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = true; break; } + case CONDITION_TERRAIN_SWAP: + { + condMeets = object->IsInTerrainSwap(ConditionValue1); + break; + } default: condMeets = false; break; @@ -596,6 +601,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case CONDITION_REALM_ACHIEVEMENT: mask |= GRID_MAP_TYPE_MASK_ALL; break; + case CONDITION_TERRAIN_SWAP: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -795,7 +803,6 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || - sourceType == CONDITION_SOURCE_TYPE_PHASE_DEFINITION || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); } @@ -871,22 +878,6 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int64 entryOrGuid, uint32 return cond; } -ConditionList const* ConditionMgr::GetConditionsForPhaseDefinition(uint32 zone, uint32 entry) -{ - PhaseDefinitionConditionContainer::const_iterator itr = PhaseDefinitionsConditionStore.find(zone); - if (itr != PhaseDefinitionsConditionStore.end()) - { - ConditionTypeContainer::const_iterator i = itr->second.find(entry); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForPhaseDefinition: found conditions for zone %u entry %u", zone, entry); - return &i->second; - } - } - - return NULL; -} - ConditionList ConditionMgr::GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId) { ConditionList cond; @@ -1126,13 +1117,6 @@ void ConditionMgr::LoadConditions(bool isReload) ++count; continue; } - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: - { - PhaseDefinitionsConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - valid = true; - ++count; - continue; - } case CONDITION_SOURCE_TYPE_NPC_VENDOR: { NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); @@ -1661,13 +1645,6 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) return false; } break; - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: - /*if (!PhaseMgr::IsConditionTypeSupported(cond->ConditionType)) - { - TC_LOG_ERROR("sql.sql", "Condition source type `CONDITION_SOURCE_TYPE_PHASE_DEFINITION` does not support condition type %u, ignoring.", cond->ConditionType); - return false; - }*/ - break; case CONDITION_SOURCE_TYPE_NPC_VENDOR: { if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) @@ -1687,6 +1664,8 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: case CONDITION_SOURCE_TYPE_NONE: + case CONDITION_SOURCE_TYPE_TERRAIN_SWAP: + case CONDITION_SOURCE_TYPE_PHASE: default: break; } @@ -2086,6 +2065,14 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } break; } + case CONDITION_TERRAIN_SWAP: + { + if (cond->ConditionValue2) + TC_LOG_ERROR("sql.sql", "Terrain swap condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + TC_LOG_ERROR("sql.sql", "Terrain swap condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } case CONDITION_TITLE: { CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1); @@ -2219,19 +2206,6 @@ void ConditionMgr::Clean() SpellClickEventConditionStore.clear(); - for (PhaseDefinitionConditionContainer::iterator itr = PhaseDefinitionsConditionStore.begin(); itr != PhaseDefinitionsConditionStore.end(); ++itr) - { - for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - { - for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - it->second.clear(); - } - itr->second.clear(); - } - - PhaseDefinitionsConditionStore.clear(); - for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index d96a1aaf83..26c958cd92 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -73,7 +73,8 @@ enum ConditionTypes CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete - CONDITION_MAX = 40 // MAX + CONDITION_TERRAIN_SWAP = 40, // terrainSwap 0 0 true if object is in terrainswap + CONDITION_MAX = 41 // MAX }; /*! Documentation on implementing a new ConditionSourceType: @@ -130,8 +131,9 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_SMART_EVENT = 22, CONDITION_SOURCE_TYPE_NPC_VENDOR = 23, CONDITION_SOURCE_TYPE_SPELL_PROC = 24, - CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 25, // only 4.3.4 - CONDITION_SOURCE_TYPE_MAX = 26 // MAX + CONDITION_SOURCE_TYPE_TERRAIN_SWAP = 25, + CONDITION_SOURCE_TYPE_PHASE = 26, + CONDITION_SOURCE_TYPE_MAX = 27 // MAX }; enum RelationType @@ -222,7 +224,6 @@ typedef std::map ConditionContainer typedef std::map CreatureSpellConditionContainer; typedef std::map NpcVendorConditionContainer; typedef std::map, ConditionTypeContainer> SmartEventConditionContainer; -typedef std::map PhaseDefinitionConditionContainer; typedef std::map ConditionReferenceContainer;//only used for references @@ -253,7 +254,6 @@ class ConditionMgr ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int64 entryOrGuid, uint32 eventId, uint32 sourceType); ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId); - ConditionList const* GetConditionsForPhaseDefinition(uint32 zone, uint32 entry); ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId); struct ConditionTypeInfo @@ -285,7 +285,6 @@ class ConditionMgr CreatureSpellConditionContainer SpellClickEventConditionStore; NpcVendorConditionContainer NpcVendorConditionContainerStore; SmartEventConditionContainer SmartEventConditionStore; - PhaseDefinitionConditionContainer PhaseDefinitionsConditionStore; }; #define sConditionMgr ConditionMgr::instance() diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 67c245ac04..8850392a13 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -78,8 +78,7 @@ bool AreaTrigger::CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerE SetUInt32Value(AREATRIGGER_SPELLVISUALID, spell->SpellVisual[0]); SetUInt32Value(AREATRIGGER_DURATION, spell->GetDuration()); - for (auto phase : caster->GetPhases()) - SetInPhase(phase, false, true); + CopyPhaseFrom(caster); if (!GetMap()->AddToMap(this)) return false; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 99cbd75cb2..6be200b888 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -94,6 +94,8 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner) _gridCoord = Trinity::ComputeGridCoord(GetPositionX(), GetPositionY()); + CopyPhaseFrom(owner); + return true; } @@ -121,9 +123,20 @@ void Corpse::SaveToDB() stmt->setUInt32(index++, uint32(m_time)); // time stmt->setUInt8 (index++, GetType()); // corpseType stmt->setUInt32(index++, GetInstanceId()); // instanceId - stmt->setUInt32(index++, GetPhaseMask()); // phaseMask trans->Append(stmt); + for (uint32 phaseId : GetPhases()) + { + index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE_PHASES); + stmt->setUInt32(index++, GetGUID().GetCounter()); // Guid (corpse's) + stmt->setUInt32(index++, phaseId); // PhaseId + stmt->setUInt32(index++, GetOwnerGUID().GetCounter()); // OwnerGuid + stmt->setUInt32(index++, uint32(m_time)); // Time + stmt->setUInt8(index++, GetType()); // CorpseType + trans->Append(stmt); + } + CharacterDatabase.CommitTransaction(trans); } @@ -148,21 +161,31 @@ void Corpse::DeleteFromDB(SQLTransaction& trans) { // Only specific bones stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE); - stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(0, GetGUID().GetCounter()); + trans->Append(stmt); + + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE_PHASES); + stmt->setUInt32(0, GetGUID().GetCounter()); + trans->Append(stmt); } else { // all corpses (not bones) stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CORPSES); - stmt->setUInt64(0, GetOwnerGUID().GetCounter()); + stmt->setUInt32(0, GetOwnerGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CORPSES_PHASES); + stmt->setUInt32(0, GetOwnerGUID().GetCounter()); + trans->Append(stmt); } - trans->Append(stmt); } bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0 float posX = fields[0].GetFloat(); float posY = fields[1].GetFloat(); @@ -178,12 +201,11 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); SetUInt32Value(CORPSE_FIELD_FLAGS, fields[9].GetUInt8()); SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, fields[10].GetUInt8()); - SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Create(fields[16].GetUInt64())); + SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Create(fields[15].GetUInt64())); m_time = time_t(fields[11].GetUInt32()); uint32 instanceId = fields[13].GetUInt32(); - //uint32 phaseMask = fields[14].GetUInt32(); // place SetLocationInstanceId(instanceId); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 11c88d4922..c27fc6e208 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1011,6 +1011,9 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) data.npcflag = npcflag; data.unit_flags = unit_flags; data.dynamicflags = dynamicflags; + + data.phaseid = GetDBPhase() > 0 ? GetDBPhase() : 0; + data.phaseGroup = GetDBPhase() < 0 ? abs(GetDBPhase()) : 0; // update in DB SQLTransaction trans = WorldDatabase.BeginTransaction(); @@ -1026,7 +1029,8 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) stmt->setUInt32(index++, GetEntry()); stmt->setUInt16(index++, uint16(mapid)); stmt->setUInt32(index++, spawnMask); - stmt->setUInt32(index++, GetPhaseMask()); + stmt->setUInt32(index++, data.phaseid); + stmt->setUInt32(index++, data.phaseGroup); stmt->setUInt32(index++, displayId); stmt->setUInt8(index++, GetCurrentEquipmentId()); stmt->setFloat(index++, GetPositionX()); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b1a8ae1bbb..1914b641c5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -819,7 +819,6 @@ void GameObject::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) stmt->setUInt32(index++, GetEntry()); stmt->setUInt16(index++, uint16(mapid)); stmt->setUInt8(index++, spawnMask); - stmt->setUInt32(index++, GetPhaseMask()); stmt->setFloat(index++, GetPositionX()); stmt->setFloat(index++, GetPositionY()); stmt->setFloat(index++, GetPositionZ()); @@ -2164,11 +2163,13 @@ void GameObject::SetDisplayId(uint32 displayid) UpdateModel(); } -void GameObject::SetInPhase(uint32 id, bool update, bool apply) +bool GameObject::SetInPhase(uint32 id, bool update, bool apply) { - WorldObject::SetInPhase(id, update, apply); + bool res = WorldObject::SetInPhase(id, update, apply); if (m_model && m_model->isEnabled()) EnableCollision(true); + + return res; } void GameObject::EnableCollision(bool enable) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 42b1977138..8ff2a94190 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -952,7 +952,7 @@ class GameObject : public WorldObject, public GridObject, public Map void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); } static void SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0)); - void SetInPhase(uint32 id, bool update, bool apply); + bool SetInPhase(uint32 id, bool update, bool apply); void EnableCollision(bool enable); void Use(Unit* user); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index a9b314357f..3fbe9fbf63 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1557,7 +1557,7 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0) +m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -2463,10 +2463,6 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } } - std::set phases; - if (summoner) - phases = summoner->GetPhases(); - TempSummon* summon = NULL; switch (mask) { @@ -2494,8 +2490,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } // Set the summon to the summoner's phase - for (auto phaseId : phases) - summon->SetInPhase(phaseId, false, true); + summon->CopyPhaseFrom(summoner); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); @@ -2591,8 +2586,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float return NULL; } - for (auto phase : GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(this); go->SetRespawnTime(respawnTime); if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this @@ -3003,12 +2997,138 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) UpdateObjectVisibility(); } -void WorldObject::SetInPhase(uint32 id, bool update, bool apply) +bool WorldObject::HasInPhaseList(uint32 phase) { - if (apply) - _phases.insert(id); - else - _phases.erase(id); + return _phases.find(phase) != _phases.end(); +} + +// Updates Area based phases, does not remove phases from auras +// Phases from gm commands are not taken into calculations, they can be lost!! +void WorldObject::UpdateAreaPhase() +{ + bool updateNeeded = false; + PhaseInfo phases = sObjectMgr->GetAreaPhases(); + for (PhaseInfo::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + { + uint32 areaId = itr->first; + for (uint32 phaseId : itr->second) + { + if (areaId == GetAreaId()) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_PHASE, phaseId); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + // add new phase if condition passed, true if it wasnt added before + bool up = SetInPhase(phaseId, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + else + { + // condition failed, remove phase, true if there was something removed + bool up = SetInPhase(phaseId, false, false); + if (!updateNeeded && up) + updateNeeded = true; + } + } + else + { + // not in area, remove phase, true if there was something removed + bool up = SetInPhase(phaseId, false, false); + if (!updateNeeded && up) + updateNeeded = true; + } + } + } + + // do not remove a phase if it would be removed by an area but we have the same phase from an aura + if (Unit* unit = ToUnit()) + { + Unit::AuraEffectList const& auraPhaseList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE); + for (Unit::AuraEffectList::const_iterator itr = auraPhaseList.begin(); itr != auraPhaseList.end(); ++itr) + { + uint32 phase = uint32((*itr)->GetMiscValueB()); + bool up = SetInPhase(phase, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + Unit::AuraEffectList const& auraPhaseGroupList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP); + for (Unit::AuraEffectList::const_iterator itr = auraPhaseGroupList.begin(); itr != auraPhaseGroupList.end(); ++itr) + { + bool up = false; + uint32 phaseGroup = uint32((*itr)->GetMiscValueB()); + std::set const& phases = sDB2Manager.GetPhasesForGroup(phaseGroup); + for (uint32 phase : phases) + up = SetInPhase(phase, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + } + + // only update visibility and send packets if there was a change in the phase list + + if (updateNeeded && GetTypeId() == TYPEID_PLAYER && IsInWorld()) + ToPlayer()->GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); + + // only update visibilty once, to prevent objects appearing for a moment while adding in multiple phases + if (updateNeeded && IsInWorld()) + UpdateObjectVisibility(); +} + +bool WorldObject::SetInPhase(uint32 id, bool update, bool apply) +{ + if (id) + { + if (apply) + { + if (HasInPhaseList(id)) // do not run the updates if we are already in this phase + return false; + _phases.insert(id); + } + else + { + for (uint32 phaseId : sObjectMgr->GetPhasesForArea(GetAreaId())) + { + if (id == phaseId) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_PHASE, phaseId); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + // if area phase passes the condition we should not remove it (ie: if remove called from aura remove) + // this however breaks the .mod phase command, you wont be able to remove any area based phases with it + return false; + } + } + } + if (!HasInPhaseList(id)) // do not run the updates if we are not in this phase + return false; + _phases.erase(id); + } + } + RebuildTerrainSwaps(); + + if (update && IsInWorld()) + UpdateObjectVisibility(); + return true; +} + +void WorldObject::CopyPhaseFrom(WorldObject* obj, bool update) +{ + if (!obj) + return; + + for (uint32 phase : obj->GetPhases()) + SetInPhase(phase, false, true); + + if (update && IsInWorld()) + UpdateObjectVisibility(); +} + +void WorldObject::ClearPhases(bool update) +{ + _phases.clear(); + + RebuildTerrainSwaps(); if (update && IsInWorld()) UpdateObjectVisibility(); @@ -3020,21 +3140,18 @@ bool WorldObject::IsInPhase(WorldObject const* obj) const if (_phases.empty() && obj->GetPhases().empty()) return true; - if (_phases.empty() && obj->IsInPhase(169)) + if (_phases.empty() && obj->IsInPhase(DEFAULT_PHASE)) return true; - if (obj->GetPhases().empty() && IsInPhase(169)) + if (obj->GetPhases().empty() && IsInPhase(DEFAULT_PHASE)) + return true; + + if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster()) return true; return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), obj->GetPhases().begin(), obj->GetPhases().end()); } -bool WorldObject::InSamePhase(WorldObject const* obj) const -{ - return IsInPhase(obj); - // return InSamePhase(obj->GetPhaseMask()); -} - void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/) { WorldPacket data(SMSG_PLAY_SPEAKERBOT_SOUND, 4 + 8); @@ -3181,3 +3298,86 @@ ObjectGuid WorldObject::GetTransGUID() const return GetTransport()->GetGUID(); return ObjectGuid::Empty; } + +void WorldObject::RebuildTerrainSwaps() +{ + // Clear all terrain swaps, will be rebuilt below + // Reason for this is, multiple phases can have the same terrain swap, we should not remove the swap if another phase still use it + _terrainSwaps.clear(); + ConditionList conditions; + + // Check all applied phases for terrain swap and add it only once + for (uint32 phaseId : _phases) + { + std::list& swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId); + + for (uint32 swap : swaps) + { + // only add terrain swaps for current map + MapEntry const* mapEntry = sMapStore.LookupEntry(swap); + if (!mapEntry || mapEntry->ParentMapID != GetMapId()) + continue; + + conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + _terrainSwaps.insert(swap); + } + } + + // get default terrain swaps, only for current map always + std::list& mapSwaps = sObjectMgr->GetDefaultTerrainSwaps(GetMapId()); + + for (uint32 swap : mapSwaps) + { + conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + _terrainSwaps.insert(swap); + } + + // online players have a game client with world map display + if (GetTypeId() == TYPEID_PLAYER) + RebuildWorldMapAreaSwaps(); +} + +void WorldObject::RebuildWorldMapAreaSwaps() +{ + // Clear all world map area swaps, will be rebuilt below + _worldMapAreaSwaps.clear(); + + // get ALL default terrain swaps, if we are using it (condition is true) + // send the worldmaparea for it, to see swapped worldmaparea in client from other maps too, not just from our current + TerrainPhaseInfo defaults = sObjectMgr->GetDefaultTerrainSwapStore(); + for (TerrainPhaseInfo::const_iterator itr = defaults.begin(); itr != defaults.end(); ++itr) + { + for (uint32 swap : itr->second) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + for (uint32 map : sObjectMgr->GetTerrainWorldMaps(swap)) + _worldMapAreaSwaps.insert(map); + } + } + } + + // Check all applied phases for world map area swaps + for (uint32 phaseId : _phases) + { + std::list& swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId); + + for (uint32 swap : swaps) + { + // add world map swaps for ANY map + + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + for (uint32 map : sObjectMgr->GetTerrainWorldMaps(swap)) + _worldMapAreaSwaps.insert(map); + } + } + } +} diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index e8022df546..ab0c6f0da7 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -46,6 +46,8 @@ #define NOMINAL_MELEE_RANGE 5.0f #define MELEE_RANGE (NOMINAL_MELEE_RANGE - MIN_MELEE_REACH * 2) //center to center for players +#define DEFAULT_PHASE 169 + enum TempSummonType { TEMPSUMMON_TIMED_OR_DEAD_DESPAWN = 1, // despawns after a specified time OR when the creature disappears @@ -612,13 +614,24 @@ class WorldObject : public Object, public WorldLocation uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); - virtual void SetInPhase(uint32 id, bool update, bool apply); + virtual bool SetInPhase(uint32 id, bool update, bool apply); + void CopyPhaseFrom(WorldObject* obj, bool update = false); + void UpdateAreaPhase(); + void ClearPhases(bool update = false); + void RebuildTerrainSwaps(); + void RebuildWorldMapAreaSwaps(); + bool HasInPhaseList(uint32 phase); uint32 GetPhaseMask() const { return m_phaseMask; } - bool InSamePhase(WorldObject const* obj) const; - bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask) != 0; } bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } bool IsInPhase(WorldObject const* obj) const; + bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); } std::set const& GetPhases() const { return _phases; } + std::set const& GetTerrainSwaps() const { return _terrainSwaps; } + std::set const& GetWorldMapAreaSwaps() const { return _worldMapAreaSwaps; } + int32 GetDBPhase() { return _dbPhase; } + + // if negative it is used as PhaseGroupId + void SetDBPhase(int32 p) { _dbPhase = p; } uint32 GetZoneId() const; uint32 GetAreaId() const; @@ -791,6 +804,9 @@ class WorldObject : public Object, public WorldLocation uint32 m_InstanceId; // in map copy with instance id uint32 m_phaseMask; // in area phase state std::set _phases; + std::set _terrainSwaps; + std::set _worldMapAreaSwaps; + int32 _dbPhase; uint16 m_notifyflags; uint16 m_executed_notifies; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 7b732ade82..87ca9110e2 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -176,11 +176,10 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c } Map* map = owner->GetMap(); - if (!Create(sObjectMgr->GetGenerator()->Generate(), map, owner->GetPhaseMask(), petEntry)) + if (!Create(sObjectMgr->GetGenerator()->Generate(), map, petEntry)) return false; - for (auto itr : owner->GetPhases()) - SetInPhase(itr, false, true); + CopyPhaseFrom(owner); setPetType(petType); setFaction(owner->getFaction()); @@ -732,7 +731,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) { ASSERT(creature); - if (!CreateBaseAtTamed(creature->GetCreatureTemplate(), creature->GetMap(), creature->GetPhaseMask())) + if (!CreateBaseAtTamed(creature->GetCreatureTemplate(), creature->GetMap())) return false; Relocate(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation()); @@ -763,7 +762,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner) { - if (!CreateBaseAtTamed(cinfo, owner->GetMap(), owner->GetPhaseMask())) + if (!CreateBaseAtTamed(cinfo, owner->GetMap())) return false; if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) @@ -774,10 +773,10 @@ bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner) return true; } -bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask) +bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map) { TC_LOG_DEBUG("entities.pet", "Pet::CreateBaseForTamed"); - if (!Create(sObjectMgr->GetGenerator()->Generate(), map, phaseMask, cinfo->Entry)) + if (!Create(sObjectMgr->GetGenerator()->Generate(), map, cinfo->Entry)) return false; setPowerType(POWER_FOCUS); @@ -1800,12 +1799,11 @@ bool Pet::IsPermanentPetFor(Player* owner) const } } -bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry) +bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry) { ASSERT(map); SetMap(map); - SetPhaseMask(phaseMask, false); Object::_Create(ObjectGuid::Create(map->GetId(), Entry, guidlow)); m_DBTableGuid = guidlow; diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index b349b79a6b..494db54208 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -55,10 +55,10 @@ class Pet : public Guardian bool IsPermanentPetFor(Player* owner) const; // pet have tab in character windows and set UNIT_FIELD_PETNUMBER - bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry); + bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry); bool CreateBaseAtCreature(Creature* creature); bool CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner); - bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask); + bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map); bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false); bool IsLoading() const override { return m_loading;} void SavePetToDB(PetSaveMode mode); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e06535c0c3..b594e69441 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7431,6 +7431,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateLocalChannels(newZone); UpdateZoneDependentAuras(newZone); + + UpdateAreaPhase(); } //If players are too far away from the duel flag... they lose the duel @@ -15445,6 +15447,7 @@ void Player::SendQuestUpdate(uint32 questId) } UpdateForQuestWorldObjects(); + SendUpdatePhasing(); } QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) @@ -26201,15 +26204,15 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy Map* map = GetMap(); uint32 pet_number = sObjectMgr->GeneratePetNumber(); - if (!pet->Create(sObjectMgr->GetGenerator()->Generate(), map, GetPhaseMask(), entry)) + + if (!pet->Create(sObjectMgr->GetGenerator()->Generate(), map, entry)) { TC_LOG_ERROR("misc", "no such creature entry %u", entry); delete pet; return NULL; } - for (auto itr : GetPhases()) - pet->SetInPhase(itr, false, true); + pet->CopyPhaseFrom(this); pet->SetCreatorGUID(GetGUID()); pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); @@ -26579,25 +26582,14 @@ void Player::ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::Ext #undef REMOVE_VIOLATING_FLAGS } -void Player::UpdatePhasing() +void Player::SendUpdatePhasing() { if (!IsInWorld()) return; - std::set phaseIds; - std::set terrainswaps; - std::set worldAreaSwaps; + RebuildTerrainSwaps(); // to set default map swaps - for (auto phase : GetPhases()) - { - PhaseInfo const* info = sObjectMgr->GetPhaseInfo(phase); - if (!info) - continue; - terrainswaps.insert(info->terrainSwapMap); - worldAreaSwaps.insert(info->worldMapAreaSwap); - } - - GetSession()->SendSetPhaseShift(GetPhases(), terrainswaps, worldAreaSwaps); + GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); } void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 596693e5da..cdd12792fd 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2449,7 +2449,7 @@ class Player : public Unit, public GridObject void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); - void UpdatePhasing(); + void SendUpdatePhasing(); template void UpdateVisibilityOf(T* target, UpdateData& data, std::set& visibleNow); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 68d50b1861..6ad2bd5213 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -318,8 +318,7 @@ Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData c for (auto phase : sDB2Manager.GetPhasesForGroup(data->phaseGroup)) creature->SetInPhase(phase, false, true); else - for (auto phase : GetPhases()) // Set the creature to the transport's phases - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(this); if (!map->AddToMap(creature)) { @@ -463,8 +462,8 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu return NULL; } - for (auto itr : phases) - summon->SetInPhase(itr, false, true); + for (uint32 phase : phases) + summon->SetInPhase(phase, false, true); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2ecb456a6d..324cd209af 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3660,7 +3660,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) else { Unit* caster = aura->GetCaster(); - if (!caster || (newPhase && !caster->InSamePhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) + if (!caster || (newPhase && !caster->IsInPhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) RemoveAura(iter); else ++iter; @@ -3675,7 +3675,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) { Aura* aura = *iter; - if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase)) + if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->IsInPhase(newPhase)) { aura->Remove(); iter = scAuras.begin(); @@ -11563,6 +11563,7 @@ void Unit::AddToWorld() { WorldObject::AddToWorld(); } + RebuildTerrainSwaps(); } void Unit::RemoveFromWorld() @@ -13091,6 +13092,8 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return false; } + pet->CopyPhaseFrom(this); + pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true); // this enables pet details window (Shift+P) pet->InitPetCreateSpells(); @@ -14421,12 +14424,12 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u return missChance; } -void Unit::SetInPhase(uint32 id, bool update, bool apply) +bool Unit::SetInPhase(uint32 id, bool update, bool apply) { - WorldObject::SetInPhase(id, update, apply); + bool res = WorldObject::SetInPhase(id, update, apply); if (!IsInWorld()) - return; + return res; if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) { @@ -14469,6 +14472,8 @@ void Unit::SetInPhase(uint32 id, bool update, bool apply) summon->SetInPhase(id, true, apply); RemoveNotOwnSingleTargetAuras(0, true); + + return res; } void Unit::UpdateObjectVisibility(bool forced) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 2b88083dfa..080dd7e322 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1957,7 +1957,7 @@ class Unit : public WorldObject void SetVisible(bool x); // common function for visibility checks for player/creatures with detection code - void SetInPhase(uint32 id, bool update, bool apply); + bool SetInPhase(uint32 id, bool update, bool apply); void UpdateObjectVisibility(bool forced = true) override; SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index e38c14046c..44e7271ca7 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -411,6 +411,8 @@ Corpse* ObjectAccessor::ConvertCorpseForPlayer(ObjectGuid player_guid, bool insi bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0); } + bones->CopyPhaseFrom(corpse); + // add bones in grid store if grid loaded where corpse placed map->AddToMap(bones); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 2523f316ce..d042fd31e2 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1650,8 +1650,8 @@ void ObjectMgr::LoadCreatures() // 0 1 2 3 4 5 6 7 8 9 10 QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, " - // 11 12 13 14 15 16 17 18 19 20 21 22 23 - "currentwaypoint, curhealth, curmana, MovementType, spawnMask, phaseMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseid, creature.phasegroup " + // 11 12 13 14 15 16 17 18 19 20 21 22 + "currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseid, creature.phasegroup " "FROM creature " "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); @@ -1701,14 +1701,13 @@ void ObjectMgr::LoadCreatures() data.curmana = fields[13].GetUInt32(); data.movementType = fields[14].GetUInt8(); data.spawnMask = fields[15].GetUInt32(); - data.phaseMask = fields[16].GetUInt32(); - int16 gameEvent = fields[17].GetInt8(); - uint32 PoolId = fields[18].GetUInt32(); - data.npcflag = fields[19].GetUInt32(); - data.unit_flags = fields[20].GetUInt32(); - data.dynamicflags = fields[21].GetUInt32(); - data.phaseid = fields[22].GetUInt32(); - data.phaseGroup = fields[23].GetUInt32(); + int16 gameEvent = fields[16].GetInt8(); + uint32 PoolId = fields[17].GetUInt32(); + data.npcflag = fields[18].GetUInt32(); + data.unit_flags = fields[19].GetUInt32(); + data.dynamicflags = fields[20].GetUInt32(); + data.phaseid = fields[21].GetUInt32(); + data.phaseGroup = fields[22].GetUInt32(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); if (!mapEntry) @@ -1778,11 +1777,7 @@ void ObjectMgr::LoadCreatures() data.orientation = Position::NormalizeOrientation(data.orientation); } - if (data.phaseMask == 0) - { - TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.", guid, data.id); - data.phaseMask = 1; - } + data.phaseMask = 1; if (data.phaseGroup && data.phaseid) { @@ -1984,8 +1979,8 @@ void ObjectMgr::LoadGameobjects() // 0 1 2 3 4 5 6 QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " - // 7 8 9 10 11 12 13 14 15 16 17 18 19 - "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseMask, eventEntry, pool_entry, phaseid, phasegroup " + // 7 8 9 10 11 12 13 14 15 16 17 18 + "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, eventEntry, pool_entry, phaseid, phasegroup " "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); @@ -2081,11 +2076,10 @@ void ObjectMgr::LoadGameobjects() if (!IsTransportMap(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid]) TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) that has wrong spawn mask %u including unsupported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); - data.phaseMask = fields[15].GetUInt32(); - int16 gameEvent = fields[16].GetInt8(); - uint32 PoolId = fields[17].GetUInt32(); - data.phaseid = fields[18].GetUInt32(); - data.phaseGroup = fields[19].GetUInt32(); + int16 gameEvent = fields[15].GetInt8(); + uint32 PoolId = fields[16].GetUInt32(); + data.phaseid = fields[17].GetUInt32(); + data.phaseGroup = fields[18].GetUInt32(); if (data.phaseGroup && data.phaseid) { @@ -2117,11 +2111,7 @@ void ObjectMgr::LoadGameobjects() continue; } - if (data.phaseMask == 0) - { - TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) with `phaseMask`=0 (not visible for anyone), set to 1.", guid, data.id); - data.phaseMask = 1; - } + data.phaseMask = 1; if (sWorld->getBoolConfig(CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA)) { @@ -6448,11 +6438,28 @@ uint64 ObjectMgr::GenerateVoidStorageItemId() void ObjectMgr::LoadCorpses() { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 - uint32 oldMSTime = getMSTime(); + std::unordered_map> phases; + + // 0 1 + // SELECT Guid, PhaseId FROM corpse_phases + PreparedQueryResult phaseResult = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_PHASES)); + if (phaseResult) + { + do + { + Field* fields = phaseResult->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 phaseId = fields[1].GetUInt32(); + + phases[guid].push_back(phaseId); + + } while (phaseResult->NextRow()); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0 PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSES)); if (!result) { @@ -6464,11 +6471,11 @@ void ObjectMgr::LoadCorpses() do { Field* fields = result->Fetch(); - ObjectGuid::LowType guid = fields[15].GetUInt64(); + uint32 guid = fields[14].GetUInt32(); CorpseType type = CorpseType(fields[12].GetUInt8()); if (type >= MAX_CORPSE_TYPE) { - TC_LOG_ERROR("misc", "Corpse (guid: " UI64FMTD ") have wrong corpse type (%u), not loading.", guid, type); + TC_LOG_ERROR("misc", "Corpse (guid: %u) have wrong corpse type (%u), not loading.", guid, type); continue; } @@ -6479,6 +6486,9 @@ void ObjectMgr::LoadCorpses() continue; } + for (auto phaseId : phases[guid]) + corpse->SetInPhase(phaseId, false, true); + sObjectAccessor->AddCorpse(corpse); ++count; } @@ -8527,60 +8537,18 @@ void ObjectMgr::LoadFactionChangeTitles() TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadPhaseDefinitions() +void ObjectMgr::LoadTerrainSwapDefaults() { - _PhaseDefinitionStore.clear(); + _terrainMapDefaultStore.clear(); uint32 oldMSTime = getMSTime(); - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT zoneId, entry, phaseId, phaseGroup FROM `phase_definitions` ORDER BY `entry` ASC"); + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty."); - return; - } - - uint32 count = 0; - - do - { - Field* fields = result->Fetch(); - - PhaseDefinition PhaseDefinition; - - PhaseDefinition.zoneId = fields[0].GetUInt32(); - PhaseDefinition.entry = fields[1].GetUInt32(); - PhaseDefinition.phaseId = fields[2].GetUInt32(); - PhaseDefinition.phaseGroup = fields[3].GetUInt32(); - - if (PhaseDefinition.phaseGroup && PhaseDefinition.phaseId) - { - TC_LOG_ERROR("sql.sql", "Phase definition for zone %u (Entry: %u) has phaseGroup and phaseId set, phaseGroup set to 0", PhaseDefinition.zoneId, PhaseDefinition.entry); - PhaseDefinition.phaseGroup = 0; - } - _PhaseDefinitionStore[PhaseDefinition.zoneId].push_back(PhaseDefinition); - - ++count; - } - while (result->NextRow()); - - TC_LOG_INFO("server.loading", ">> Loaded %u phasing definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); -} - -void ObjectMgr::LoadPhaseInfo() -{ - _PhaseInfoStore.clear(); - - uint32 oldMSTime = getMSTime(); - - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT id, worldmapareaswap, terrainswapmap FROM `phase_info`"); - - if (!result) - { - TC_LOG_INFO("server.loading", ">> Loaded 0 phase infos. DB table `phase_info` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty."); return; } @@ -8589,25 +8557,139 @@ void ObjectMgr::LoadPhaseInfo() { Field* fields = result->Fetch(); - PhaseInfo phaseInfo; - phaseInfo.phaseId = fields[0].GetUInt32(); + uint32 mapId = fields[0].GetUInt32(); - PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseInfo.phaseId); - if (!phase) + MapEntry const* map = sMapStore.LookupEntry(mapId); + if (!map) { - TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_info` does not exists, skipped.", phaseInfo.phaseId); + TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId); continue; } - phaseInfo.worldMapAreaSwap = fields[1].GetUInt32(); - phaseInfo.terrainSwapMap = fields[2].GetUInt32(); + uint32 terrainSwap = fields[1].GetUInt32(); - _PhaseInfoStore[phaseInfo.phaseId] = phaseInfo; + map = sMapStore.LookupEntry(terrainSwap); + if (!map) + { + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap); + continue; + } + + _terrainMapDefaultStore[mapId].push_back(terrainSwap); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadTerrainPhaseInfo() +{ + _terrainPhaseInfoStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 phaseId = fields[0].GetUInt32(); + + PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId); + continue; + } + + uint32 terrainSwap = fields[1].GetUInt32(); + + _terrainPhaseInfoStore[phaseId].push_back(terrainSwap); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadTerrainWorldMaps() +{ + _terrainWorldMapStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 mapId = fields[0].GetUInt32(); + + if (!sMapStore.LookupEntry(mapId)) + { + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); + continue; + } + + uint32 worldMapArea = fields[1].GetUInt32(); + + _terrainWorldMapStore[mapId].push_back(worldMapArea); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadAreaPhases() +{ + _phases.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 area = fields[0].GetUInt32(); + uint32 phase = fields[1].GetUInt32(); + + _phases[area].push_back(phase); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e9ec98f3e9..dca58857f9 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -129,34 +129,6 @@ typedef std::map PageTextContainer; // Benchmarked: Faster than std::map (insert/find) typedef std::unordered_map InstanceTemplateContainer; -// Phasing (visibility) -enum PhasingFlags -{ - PHASE_FLAG_OVERWRITE_EXISTING = 0x01, // don't stack with existing phases, overwrites existing phases - PHASE_FLAG_NO_MORE_PHASES = 0x02, // stop calculating phases after this phase was applied (no more phases will be applied) - PHASE_FLAG_NEGATE_PHASE = 0x04 // negate instead to add the phasemask -}; - -struct PhaseInfo -{ - uint32 phaseId; - uint32 worldMapAreaSwap; - uint32 terrainSwapMap; -}; - -typedef std::unordered_map PhaseInfoContainer; - -struct PhaseDefinition -{ - uint32 zoneId; - uint32 entry; - uint32 phaseId; - uint32 phaseGroup; -}; - -typedef std::list PhaseDefinitionContainer; -typedef std::unordered_map PhaseDefinitionStore; - struct GameTele { float position_x; @@ -672,6 +644,9 @@ struct DungeonEncounter typedef std::list DungeonEncounterList; typedef std::unordered_map DungeonEncounterContainer; +typedef std::unordered_map> TerrainPhaseInfo; +typedef std::unordered_map> PhaseInfo; + class PlayerDumpReader; class ObjectMgr @@ -1008,8 +983,10 @@ class ObjectMgr void LoadTrainerSpell(); void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel); - void LoadPhaseDefinitions(); - void LoadPhaseInfo(); + void LoadTerrainPhaseInfo(); + void LoadTerrainSwapDefaults(); + void LoadTerrainWorldMaps(); + void LoadAreaPhases(); std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); @@ -1243,7 +1220,12 @@ class ObjectMgr return _gossipMenuItemsStore.equal_range(uiMenuId); } - PhaseInfo const* GetPhaseInfo(uint32 phase) { return _PhaseInfoStore.find(phase) != _PhaseInfoStore.end() ? &_PhaseInfoStore[phase] : nullptr; } + std::list& GetPhaseTerrainSwaps(uint32 phaseid) { return _terrainPhaseInfoStore[phaseid]; } + std::list& GetDefaultTerrainSwaps(uint32 mapid) { return _terrainMapDefaultStore[mapid]; } + std::list& GetTerrainWorldMaps(uint32 terrainId) { return _terrainWorldMapStore[terrainId]; } + TerrainPhaseInfo& GetDefaultTerrainSwapStore() { return _terrainMapDefaultStore; } + std::list& GetPhasesForArea(uint32 area) { return _phases[area]; } + PhaseInfo& GetAreaPhases() { return _phases; } // for wintergrasp only GraveYardContainer GraveYardStore; @@ -1369,8 +1351,10 @@ class ObjectMgr PageTextContainer _pageTextStore; InstanceTemplateContainer _instanceTemplateStore; - PhaseDefinitionStore _PhaseDefinitionStore; - PhaseInfoContainer _PhaseInfoStore; + TerrainPhaseInfo _terrainPhaseInfoStore; + TerrainPhaseInfo _terrainMapDefaultStore; + TerrainPhaseInfo _terrainWorldMapStore; + PhaseInfo _phases; private: void LoadScripts(ScriptsType type); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 8554a027e7..e8e6febbe3 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1399,50 +1399,13 @@ void WorldSession::HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*requ void WorldSession::SendSetPhaseShift(std::set const& phaseIds, std::set const& terrainswaps, std::set const& worldMapAreaSwaps) { - ObjectGuid guid = _player->GetGUID(); - - WorldPacket data(SMSG_PHASE_SHIFT_CHANGE, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); - data.WriteBit(guid[2]); - data.WriteBit(guid[3]); - data.WriteBit(guid[1]); - data.WriteBit(guid[6]); - data.WriteBit(guid[4]); - data.WriteBit(guid[5]); - data.WriteBit(guid[0]); - data.WriteBit(guid[7]); - - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[4]); - - data << uint32(worldMapAreaSwaps.size()); - for (auto mapSwap : worldMapAreaSwaps) - data << uint16(mapSwap); // WorldMapArea.dbc id (controls map display) - - data.WriteByteSeq(guid[1]); - - data << uint32(phaseIds.size() ? 0 : 8); // flags (not phasemask) - - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[6]); - - data << uint32(0); // Inactive terrain swaps - //for (uint8 i = 0; i < inactiveSwapsCount; ++i) - // data << uint16(0); - - data << uint32(phaseIds.size()) * 2; // Phase.dbc ids - for (std::set::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) - data << uint16(*itr); - - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[0]); - - data << uint32(terrainswaps.size()) * 2; // Active terrain swaps - for (std::set::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) - data << uint16(*itr); - - data.WriteByteSeq(guid[5]); - - SendPacket(&data); + WorldPackets::Misc::PhaseShift phaseShift; + phaseShift.ClientGUID = _player->GetGUID(); + phaseShift.PersonalGUID = _player->GetGUID(); + phaseShift.PhaseShifts = phaseIds; + phaseShift.VisibleMapIDs = terrainswaps; + phaseShift.UiWorldMapAreaIDSwaps = worldMapAreaSwaps; + SendPacket(phaseShift.Write()); } // Battlefield and Battleground diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index ab5943ac48..c151183da8 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -633,5 +633,5 @@ void InstanceScript::UpdatePhasing() Map::PlayerList const& players = instance->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) if (Player* player = itr->GetSource()) - player->UpdatePhasing(); + player->SendUpdatePhasing(); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 076daa969d..c2bec06322 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -498,6 +498,8 @@ bool Map::AddPlayerToMap(Player* player) player->m_clientGUIDs.clear(); player->UpdateObjectVisibility(false); + player->SendUpdatePhasing(); + sScriptMgr->OnPlayerEnterMap(this, player); return true; } @@ -556,6 +558,8 @@ bool Map::AddToMap(T* obj) if (obj->isActiveObject()) AddToActive(obj); + obj->RebuildTerrainSwaps(); + //something, such as vehicle, needs to be update immediately //also, trigger needs to cast spell, if not update, cannot see visual obj->UpdateObjectVisibility(true); diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index e041ed9c6e..0e43671562 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -42,8 +42,8 @@ PathGenerator::PathGenerator(const Unit* owner) : if (DisableMgr::IsPathfindingEnabled(mapId)) { MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager(); - _navMesh = mmap->GetNavMesh(mapId); - _navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId()); + _navMesh = mmap->GetNavMesh(mapId, _sourceUnit->GetTerrainSwaps()); + _navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId(), _sourceUnit->GetTerrainSwaps()); } CreateFilter(); diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index 1905ab3e3c..009f1d901d 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -379,3 +379,30 @@ WorldPacket const* WorldPackets::Misc::RandomRoll::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Misc::PhaseShift::Write() +{ + _worldPacket << ClientGUID; // CLientGUID + _worldPacket << uint32(PhaseShifts.size() ? 0 : 8); // PhaseShiftFlags + _worldPacket << uint32(PhaseShifts.size()); // PhaseShiftCount + _worldPacket << PersonalGUID; // PersonalGUID + for (uint32 phase : PhaseShifts) + { + _worldPacket << uint16(1); // PhaseFlags + _worldPacket << uint16(phase); // PhaseID + } + + _worldPacket << uint32(VisibleMapIDs.size() * 2); // Active terrain swaps size + for (uint32 map : VisibleMapIDs) + _worldPacket << uint16(map); // Active terrain swap map id + + _worldPacket << uint32(PreloadMapIDs.size() * 2); // Inactive terrain swaps size + for (uint32 map : PreloadMapIDs) + _worldPacket << uint16(map); // Inactive terrain swap map id + + _worldPacket << uint32(UiWorldMapAreaIDSwaps.size() * 2); // UI map swaps size + for (uint32 map : UiWorldMapAreaIDSwaps) + _worldPacket << uint16(map); // UI map id, WorldMapArea.dbc, controls map display + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index 15dd164f99..b41e1cb8b5 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -538,6 +538,21 @@ namespace WorldPackets WorldPacket const* Write() override { return &_worldPacket; } }; + + class PhaseShift final : public ServerPacket + { + public: + PhaseShift() : ServerPacket(SMSG_PHASE_SHIFT_CHANGE, 4) { } + + WorldPacket const* Write() override; + + ObjectGuid ClientGUID; + ObjectGuid PersonalGUID; + std::set PhaseShifts; + std::set PreloadMapIDs; + std::set UiWorldMapAreaIDSwaps; + std::set VisibleMapIDs; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a254c32854..5c844f1e3a 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1522,7 +1522,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_STABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_TAME_FAILURE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_UNLEARNED_SPELLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PHASE_SHIFT_CHANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PHASE_SHIFT_CHANGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYED_TIME, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_BOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PLAYER_SAVE_GUILD_EMBLEM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 82a6913773..83e9dcbc2e 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1738,7 +1738,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app { if (player->IsInWorld()) player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->UpdatePhasing(); + player->SendUpdatePhasing(); } // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) @@ -1770,7 +1770,7 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo { if (player->IsInWorld()) player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->UpdatePhasing(); + player->SendUpdatePhasing(); } // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 67ef2c7381..61634e2be7 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3218,8 +3218,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -3242,8 +3241,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (linkedGO->Create(sObjectMgr->GetGenerator()->Generate(), linkedEntry, map, m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { - for (auto phase : m_caster->GetPhases()) - linkedGO->SetInPhase(phase, false, true); + linkedGO->CopyPhaseFrom(m_caster); linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); linkedGO->SetSpellId(m_spellInfo->Id); @@ -3877,8 +3875,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); @@ -4250,8 +4247,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(m_caster); //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); int32 duration = m_spellInfo->GetDuration(); @@ -4888,8 +4884,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -4953,8 +4948,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (linkedGO->Create(sObjectMgr->GetGenerator()->Generate(), linkedEntry, cMap, 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { - for (auto phase : m_caster->GetPhases()) - linkedGO->SetInPhase(phase, false, true); + linkedGO->CopyPhaseFrom(m_caster); linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c34ce2640c..6eb11499a4 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1460,6 +1460,10 @@ void World::SetInitialWorldSettings() stmt->setUInt32(0, 3 * DAY); CharacterDatabase.Execute(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_CORPSE_PHASES); + stmt->setUInt32(0, 3 * DAY); + CharacterDatabase.Execute(stmt); + ///- Load the DBC files TC_LOG_INFO("server.loading", "Initialize data stores..."); LoadDBCStores(m_dataPath); @@ -1550,9 +1554,6 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Spell Group Stack Rules..."); sSpellMgr->LoadSpellGroupStackRules(); - TC_LOG_INFO("server.loading", "Loading Spell Phase Dbc Info..."); - sObjectMgr->LoadPhaseInfo(); - TC_LOG_INFO("server.loading", "Loading NPC Texts..."); sObjectMgr->LoadGossipText(); @@ -1801,8 +1802,17 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions LoadWorldStates(); - TC_LOG_INFO("server.loading", "Loading Phase definitions..."); - sObjectMgr->LoadPhaseDefinitions(); + TC_LOG_INFO("server.loading", "Loading Terrain Phase definitions..."); + sObjectMgr->LoadTerrainPhaseInfo(); + + TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions..."); + sObjectMgr->LoadTerrainSwapDefaults(); + + TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions..."); + sObjectMgr->LoadTerrainWorldMaps(); + + TC_LOG_INFO("server.loading", "Loading Phase Area definitions..."); + sObjectMgr->LoadAreaPhases(); TC_LOG_INFO("server.loading", "Loading Conditions..."); sConditionMgr->LoadConditions(); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 809557c90b..7a98d1c0c1 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -935,8 +935,7 @@ public: return false; } - for (auto phase : handler->GetSession()->GetPlayer()->GetPhases()) - v->SetInPhase(phase, false, true); + v->CopyPhaseFrom(handler->GetSession()->GetPlayer()); map->AddToMap(v->ToCreature()); @@ -960,6 +959,7 @@ public: char* t = strtok((char*)args, " "); char* p = strtok(NULL, " "); + char* m = strtok(NULL, " "); if (!t) return false; @@ -968,10 +968,16 @@ public: std::set phaseId; std::set worldMapSwap; - terrainswap.insert((uint32)atoi(t)); + if (uint32 ut = (uint32)atoi(t)) + terrainswap.insert(ut); if (p) - phaseId.insert((uint32)atoi(p)); + if (uint32 up = (uint32)atoi(p)) + phaseId.insert(up); + + if (m) + if (uint32 um = (uint32)atoi(m)) + worldMapSwap.insert(um); handler->GetSession()->SendSetPhaseShift(phaseId, terrainswap, worldMapSwap); return true; @@ -1391,14 +1397,28 @@ public: return true; } - static bool HandleDebugPhaseCommand(ChatHandler* /*handler*/, char const* /*args*/) + static bool HandleDebugPhaseCommand(ChatHandler* handler, char const* /*args*/) { - /*/ - Unit* unit = handler->getSelectedUnit(); - Player* player = handler->GetSession()->GetPlayer(); - if (unit && unit->GetTypeId() == TYPEID_PLAYER) - player = unit->ToPlayer(); - */ + Unit* target = handler->getSelectedUnit(); + + if (!target) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + std::stringstream phases; + + for (uint32 phase : target->GetPhases()) + { + phases << phase << " "; + } + + if (!phases.str().empty()) + handler->PSendSysMessage("Target's current phases: %s", phases.str().c_str()); + else + handler->SendSysMessage("Target is not phased"); return true; } }; diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 59d32f9e41..36876a9be3 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -158,8 +158,7 @@ public: return false; } - for (auto phase : player->GetPhases()) - object->SetInPhase(phase, false, true); + object->CopyPhaseFrom(player); if (spawntimeSecs) { diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 8e646629e9..b57efc07a7 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -219,7 +219,7 @@ public: uint32 haveMap = Map::ExistMap(mapId, gridX, gridY) ? 1 : 0; uint32 haveVMap = Map::ExistVMap(mapId, gridX, gridY) ? 1 : 0; - uint32 haveMMap = (DisableMgr::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0; + uint32 haveMMap = (DisableMgr::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps())) ? 1 : 0; if (haveVMap) { @@ -248,6 +248,21 @@ public: if (status) handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status); + + if (!object->GetTerrainSwaps().empty()) + { + std::stringstream ss; + for (uint32 swap : object->GetTerrainSwaps()) + ss << swap << " "; + handler->PSendSysMessage("Target's active terrain swaps: %s", ss.str().c_str()); + } + if (!object->GetWorldMapAreaSwaps().empty()) + { + std::stringstream ss; + for (uint32 swap : object->GetWorldMapAreaSwaps()) + ss << swap << " "; + handler->PSendSysMessage("Target's active world map area swaps: %s", ss.str().c_str()); + } return true; } @@ -408,8 +423,7 @@ public: target->GetContactPoint(_player, x, y, z); _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE); - for (auto phase : target->GetPhases()) - _player->SetInPhase(phase, true, true); + _player->CopyPhaseFrom(target, true); } else { @@ -533,8 +547,7 @@ public: float x, y, z; handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize()); target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation()); - for (auto phase : handler->GetSession()->GetPlayer()->GetPhases()) - target->SetInPhase(phase, true, true); + target->CopyPhaseFrom(handler->GetSession()->GetPlayer(), true); } else { diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index 16edb91873..166afec6b3 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -64,7 +64,7 @@ public: static bool HandleMmapPathCommand(ChatHandler* handler, char const* args) { - if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) + if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps())) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; @@ -132,8 +132,8 @@ public: handler->PSendSysMessage("gridloc [%i, %i]", gy, gx); // calculate navmesh tile location - dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); - dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId()); + dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps()); + dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); @@ -184,8 +184,8 @@ public: static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/) { uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId(); - dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid); - dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId()); + dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid, handler->GetSession()->GetPlayer()->GetTerrainSwaps()); + dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); @@ -215,7 +215,7 @@ public: MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager(); handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); - dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); + dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId(), handler->GetSession()->GetPlayer()->GetTerrainSwaps()); if (!navmesh) { handler->PSendSysMessage("NavMesh not loaded for current map."); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index e6fa8037d3..c1f90c7ac9 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1279,10 +1279,13 @@ public: uint32 phase = (uint32)atoi((char*)args); Unit* target = handler->getSelectedUnit(); - if (target) - target->SetInPhase(phase, true, !target->IsInPhase(phase)); - else - handler->GetSession()->GetPlayer()->SetInPhase(phase, true, !handler->GetSession()->GetPlayer()->IsInPhase(phase)); + if (!target) + target = handler->GetSession()->GetPlayer(); + + target->SetInPhase(phase, true, !target->IsInPhase(phase)); + + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->SendUpdatePhasing(); return true; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 70086c9498..9ee32d0c6e 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -206,6 +206,7 @@ public: { "model", rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, false, &HandleNpcSetModelCommand, "", NULL }, { "movetype", rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, false, &HandleNpcSetMoveTypeCommand, "", NULL }, { "phase", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseCommand, "", NULL }, + { "phasegroup", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseGroup, "", NULL }, { "spawndist", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, false, &HandleNpcSetSpawnDistCommand, "", NULL }, { "spawntime", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, false, &HandleNpcSetSpawnTimeCommand, "", NULL }, { "data", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetDataCommand, "", NULL }, @@ -285,9 +286,6 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); - creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); ObjectGuid::LowType db_guid = creature->GetDBTableGUIDLow(); @@ -1100,7 +1098,37 @@ public: } //npc phase handling - //change phase of creature or pet + //change phase of creature + static bool HandleNpcSetPhaseGroup(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + uint32 phaseGroupId = (uint32)atoi((char*)args); + + Creature* creature = handler->getSelectedCreature(); + if (!creature || creature->IsPet()) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + creature->ClearPhases(); + + for (uint32 id : sDB2Manager.GetPhasesForGroup(phaseGroupId)) + creature->SetInPhase(id, false, true); // don't send update here for multiple phases, only send it once after adding all phases + + creature->UpdateObjectVisibility(); + creature->SetDBPhase(-int(phaseGroupId)); + + creature->SaveToDB(); + + return true; + } + + //npc phase handling + //change phase of creature static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args) { if (!*args) @@ -1109,17 +1137,18 @@ public: uint32 phase = (uint32) atoi((char*)args); Creature* creature = handler->getSelectedCreature(); - if (!creature) + if (!creature || creature->IsPet()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } - creature->SetInPhase(phase, true, !creature->IsInPhase(phase)); + creature->ClearPhases(); + creature->SetInPhase(phase, true, true); + creature->SetDBPhase(phase); - if (!creature->IsPet()) - creature->SaveToDB(); + creature->SaveToDB(); return true; } diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 99cec7bed9..78f23ceab2 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -1104,10 +1104,10 @@ public: static bool HandleReloadPhaseDefinitionsCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Reloading phase_definitions table..."); - sObjectMgr->LoadPhaseDefinitions(); + TC_LOG_INFO("misc", "Reloading terrain_phase_info table..."); + sObjectMgr->LoadTerrainPhaseInfo(); sWorld->UpdatePhaseDefinitions(); - handler->SendGlobalGMSysMessage("Phase Definitions reloaded."); + handler->SendGlobalGMSysMessage("Terrain phase infos reloaded."); return true; } diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 35b142e9e5..a4e0ce3af6 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -682,8 +682,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - wpCreature2->SetInPhase(phase, false, true); + wpCreature2->CopyPhaseFrom(chr); wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); @@ -902,8 +901,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - wpCreature->SetInPhase(phase, false, true); + wpCreature->CopyPhaseFrom(chr); // Set "wpguid" column to the visual waypoint stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID); @@ -967,8 +965,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) @@ -1019,8 +1016,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index dd261d4014..a8da4ff743 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -172,8 +172,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - for (auto phase : player->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(player); go->SetRespawnTime(0); @@ -209,8 +208,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - for (auto phase : player->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(player); go->SetRespawnTime(0); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 6369429236..352854636d 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -336,11 +336,16 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PLAYER_HOMEBIND, "DELETE FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); // Corpse - PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (corpseGuid, guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (corpseGuid, guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE corpseGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PLAYER_CORPSES, "DELETE FROM corpse WHERE guid = ? AND corpseType <> 0", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_OLD_CORPSES, "DELETE FROM corpse WHERE corpseType = 0 OR time < (UNIX_TIMESTAMP(NOW()) - ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSE_PHASES, "SELECT Guid, PhaseId FROM corpse_phases", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE Guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_CORPSES_PHASES, "DELETE FROM corpse_phases WHERE OwnerGuid = ? AND CorpseType <> 0", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_OLD_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE CorpseType = 0 OR Time < (UNIX_TIMESTAMP(NOW()) - ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CORPSE_PHASES, "INSERT INTO corpse_phases (Guid, PhaseId, OwnerGuid, Time, CorpseType) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Creature respawn PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index b10591f0e5..e6c0a0db48 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -294,6 +294,11 @@ enum CharacterDatabaseStatements CHAR_DEL_CORPSE, CHAR_DEL_PLAYER_CORPSES, CHAR_DEL_OLD_CORPSES, + CHAR_SEL_CORPSE_PHASES, + CHAR_DEL_CORPSE_PHASES, + CHAR_DEL_PLAYER_CORPSES_PHASES, + CHAR_DEL_OLD_CORPSE_PHASES, + CHAR_INS_CORPSE_PHASES, CHAR_SEL_CREATURE_RESPAWNS, CHAR_REP_CREATURE_RESPAWN, diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index 4c2f6fb933..eeecc56385 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -81,10 +81,10 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); - PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, PhaseId, PhaseGroup, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_DISABLES, "DELETE FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_ASYNC); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index cc04bf9990..ba4bcd765e 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3347,6 +3347,7 @@ Logger.sql.updates=3,Console Server #Logger.network.opcode=3,Console Server #Logger.network.soap=3,Console Server #Logger.outdoorpvp=3,Console Server +#Logger.phase=3,Console Server #Logger.pool=3,Console Server #Logger.rbac=3,Console Server #Logger.scripts=3,Console Server