diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ea659ebfe1..ed955ab619 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -33,7 +33,8 @@ "mhutchie.git-graph", "github.vscode-pull-request-github", "eamodio.gitlens", - "cschlosser.doxdocgen" + "cschlosser.doxdocgen", + "sanaajani.taskrunnercode" ], // Use 'forwardPorts' to make a list of ports inside the container available locally. diff --git a/.dockerignore b/.dockerignore index 44c4511bc4..ea6c901b71 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,13 +1,20 @@ /cmake-build-debug/* /build*/ /var/* +!/var/build/.gitkeep +!/var/ccache/.gitkeep /env/dist/* +!/env/dist/.gitkeep /env/user/* -/env/docker/data/* -/env/docker/logs/* -/env/docker/etc/* +/env/docker/* +!/env/docker/bin/.gitkeep +!/env/docker/data/.gitkeep !/env/docker/etc/authserver.conf.dockerdist !/env/docker/etc/worldserver.conf.dockerdist +!/env/docker/logs/.gitkeep /.env* .idea !.gitkeep + +# do not ignore the ccache folder (used by the ci) +!/var/docker/ccache diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 89d0cd999c..11bd83499c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,91 +7,40 @@ assignees: '' --- - + - +**CURRENT BEHAVIOUR:** + +**EXPECTED BLIZZLIKE BEHAVIOUR:** + -## CURRENT BEHAVIOUR: - +**SOURCE:** + - - - -## EXPECTED BLIZZLIKE BEHAVIOUR: - - - - - -## SOURCE: - - - - - -## STEPS TO REPRODUCE THE PROBLEM: - +**STEPS TO REPRODUCE THE PROBLEM:** + 1. 2. 3. -## EXTRA NOTES: - +**EXTRA NOTES:** + +**AC HASH/COMMIT:** + +**OPERATING SYSTEM:** + +**MODULES:** + -## AC HASH/COMMIT: - - - - - -## OPERATING SYSTEM: - - - - - -## MODULES: - - - - - -## CUSTOMIZATIONS: - - - - +**CUSTOMIZATIONS:** + - + ## Changes Proposed: - - - ## Issues Addressed: + - Closes - - ## SOURCE: - - + ## Tests Performed: - + - - ## How to Test the Changes: - + +1. +2. +3. ## Known Issues and TODO List: - + + +- [ ] - [ ] -- [ ] - -## Target Branch(es): -- [x] Master - - - - - - - - + ## How to Test AzerothCore PRs When a PR is ready to be tested, it will be marked as **[WAITING TO BE TESTED]**. diff --git a/src/cmake/compiler/clang/settings.cmake b/src/cmake/compiler/clang/settings.cmake index fecfb2edc4..b3eb165f60 100644 --- a/src/cmake/compiler/clang/settings.cmake +++ b/src/cmake/compiler/clang/settings.cmake @@ -3,6 +3,12 @@ # Copyright (C) 2008-2019 TrinityCore # +if ((USE_COREPCH OR USE_SCRIPTPCH) AND (CMAKE_C_COMPILER_LAUNCHER STREQUAL "ccache" OR CMAKE_CXX_COMPILER_LAUNCHER STREQUAL "ccache")) + message(STATUS "Clang: disable pch timestamp when ccache and pch enabled") + # TODO: for ccache https://github.com/ccache/ccache/issues/539 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -fno-pch-timestamp") +endif() + # Set build-directive (used in core to tell which buildtype we used) target_compile_definitions(acore-compile-option-interface INTERFACE diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d06edcaf3b..ebd34fe98f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -49,8 +49,6 @@ target_include_directories(common ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(common - PRIVATE - game-interface PUBLIC acore-core-interface ace diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp index c7f8c87d2e..2af4d36587 100644 --- a/src/common/Collision/DynamicTree.cpp +++ b/src/common/Collision/DynamicTree.cpp @@ -5,16 +5,12 @@ */ #include "DynamicTree.h" -//#include "QuadTree.h" -//#include "RegularGrid.h" #include "BoundingIntervalHierarchyWrapper.h" - #include "Log.h" #include "RegularGrid.h" #include "Timer.h" #include "GameObjectModel.h" #include "ModelInstance.h" - #include #include #include @@ -23,10 +19,8 @@ using VMAP::ModelInstance; namespace { - int CHECK_TREE_PERIOD = 200; - -} // namespace +} template<> struct HashTrait< GameObjectModel> { @@ -44,15 +38,9 @@ template<> struct BoundsTrait< GameObjectModel> static void getBounds2(const GameObjectModel* g, G3D::AABox& out) { out = g->getBounds();} }; -/* -static bool operator == (const GameObjectModel& mdl, const GameObjectModel& mdl2){ - return &mdl == &mdl2; -} -*/ - typedef RegularGrid2D> ParentTree; -struct DynTreeImpl : public ParentTree/*, public Intersectable*/ +struct DynTreeImpl : public ParentTree { typedef GameObjectModel Model; typedef ParentTree base; diff --git a/src/common/Collision/Management/IMMAPManager.h b/src/common/Collision/Management/IMMAPManager.h index ec05fc0bdd..a558ab2c0b 100644 --- a/src/common/Collision/Management/IMMAPManager.h +++ b/src/common/Collision/Management/IMMAPManager.h @@ -35,4 +35,4 @@ namespace MMAP }; } -#endif \ No newline at end of file +#endif diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index aa5cd6037e..7d999c779b 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -18,7 +18,6 @@ This is the minimum interface to the VMapMamager. namespace VMAP { - enum VMAP_LOAD_RESULT { VMAP_LOAD_RESULT_ERROR, @@ -83,6 +82,6 @@ namespace VMAP virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const = 0; virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type) const = 0; }; - } + #endif diff --git a/src/common/Collision/Management/MMapFactory.cpp b/src/common/Collision/Management/MMapFactory.cpp index b5ea34a506..78dd941f87 100644 --- a/src/common/Collision/Management/MMapFactory.cpp +++ b/src/common/Collision/Management/MMapFactory.cpp @@ -5,7 +5,6 @@ */ #include "MMapFactory.h" -#include "World.h" #include namespace MMAP @@ -23,12 +22,6 @@ namespace MMAP return g_MMapManager; } - bool MMapFactory::IsPathfindingEnabled(const Map* map) - { - if (!map) return false; - return !forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena()); - } - void MMapFactory::InitializeDisabledMaps() { memset(&forbiddenMaps, 0, sizeof(forbiddenMaps)); @@ -46,4 +39,4 @@ namespace MMAP g_MMapManager = nullptr; } } -} \ No newline at end of file +} diff --git a/src/common/Collision/Management/MMapFactory.h b/src/common/Collision/Management/MMapFactory.h index 30d440870d..b25ccce698 100644 --- a/src/common/Collision/Management/MMapFactory.h +++ b/src/common/Collision/Management/MMapFactory.h @@ -10,8 +10,7 @@ #include "MMapManager.h" #include "DetourAlloc.h" #include "DetourNavMesh.h" -#include "Navigation/DetourExtended.h" -#include "Map.h" +#include "DetourExtended.h" #include namespace MMAP @@ -31,7 +30,6 @@ namespace MMAP public: static MMapManager* createOrGetMMapManager(); static void clear(); - static bool IsPathfindingEnabled(const Map* map); static void InitializeDisabledMaps(); static bool forbiddenMaps[1000]; }; diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp index 1ccb133229..40fa342779 100644 --- a/src/common/Collision/Management/MMapManager.cpp +++ b/src/common/Collision/Management/MMapManager.cpp @@ -4,9 +4,10 @@ * Copyright (C) 2005-2009 MaNGOS */ -#include "Config.h" -#include "MapManager.h" #include "MMapManager.h" +#include "Config.h" +#include "Errors.h" +#include "MapDefines.h" #include "Log.h" #include "StringFormat.h" @@ -25,11 +26,41 @@ namespace MMAP // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost! } + void MMapManager::InitializeThreadUnsafe(const std::vector& mapIds) + { + // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime + for (const uint32& mapId : mapIds) + loadedMMaps.emplace(mapId, nullptr); + + thread_safe_environment = false; + } + + MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const + { + // return the iterator if found or end() if not found/NULL + MMapDataSet::const_iterator itr = loadedMMaps.find(mapId); + if (itr != loadedMMaps.cend() && !itr->second) + itr = loadedMMaps.cend(); + + return itr; + } + bool MMapManager::loadMapData(uint32 mapId) { // we already have this map loaded? - if (loadedMMaps.find(mapId) != loadedMMaps.end()) - return true; + MMapDataSet::iterator itr = loadedMMaps.find(mapId); + if (itr != loadedMMaps.end()) + { + if (itr->second) + return true; + } + else + { + if (thread_safe_environment) + itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first; + else + ASSERT(false, "Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId); + } // load and init dtNavMesh - read parameters from file std::string fileName = acore::StringFormat(MAP_FILE_NAME_FORMAT, sConfigMgr->GetOption("DataDir", ".").c_str(), mapId); @@ -37,18 +68,16 @@ namespace MMAP FILE* file = fopen(fileName.c_str(), "rb"); if (!file) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName.c_str()); -#endif return false; } dtNavMeshParams params; - int count = fread(¶ms, sizeof(dtNavMeshParams), 1, file); + uint32 count = uint32(fread(¶ms, sizeof(dtNavMeshParams), 1, file)); fclose(file); if (count != 1) { - ;//TC_LOG_DEBUG(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName); + LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName.c_str()); return false; } @@ -61,15 +90,11 @@ namespace MMAP return false; } -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) - LOG_DEBUG("server", "MMAP:loadMapData: Loaded %03i.mmap", mapId); -#endif + LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId); // store inside our map list MMapData* mmap_data = new MMapData(mesh); - mmap_data->mmapLoadedTiles.clear(); - - loadedMMaps.insert(std::pair(mapId, mmap_data)); + itr->second = mmap_data; return true; } @@ -78,22 +103,8 @@ namespace MMAP return uint32(x << 16 | y); } - std::shared_mutex& MMapManager::GetMMapLock(uint32 mapId) - { - Map* map = sMapMgr->FindBaseMap(mapId); - if (!map) - { - LOG_INFO("misc", "ZOMG! MoveMaps: BaseMap not found!"); - return this->MMapLock; - } - - return map->GetMMapLock(); - } - bool MMapManager::loadMap(uint32 mapId, int32 x, int32 y) { - std::unique_lock guard(MMapManagerLock); - // make sure the mmap is loaded and ready to load tiles if (!loadMapData(mapId)) return false; @@ -104,7 +115,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()) { LOG_ERROR("server", "MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y); return false; @@ -151,26 +162,18 @@ namespace MMAP dtTileRef tileRef = 0; - dtStatus stat; - { - std::unique_lock guard(GetMMapLock(mapId)); - stat = mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef); - } - // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed - if (stat == DT_SUCCESS) + if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) { - mmap->mmapLoadedTiles.insert(std::pair(packedGridPos, tileRef)); + mmap->loadedTileRefs.insert(std::pair(packedGridPos, tileRef)); ++loadedTiles; -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) dtMeshHeader* header = (dtMeshHeader*)data; - LOG_DEBUG("server", "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y); -#endif + LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y); return true; } else { - LOG_ERROR("server", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); + LOG_ERROR("maps", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); dtFree(data); return false; } @@ -180,10 +183,9 @@ namespace MMAP bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y) { - std::unique_lock guard(MMapManagerLock); - // check if we have this map loaded - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) { // file may not exist, therefore not loaded #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) @@ -192,11 +194,11 @@ namespace MMAP return false; } - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; // 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 #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) @@ -205,16 +207,10 @@ namespace MMAP return false; } - dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos]; - - dtStatus status; - { - std::unique_lock guard(GetMMapLock(mapId)); - status = mmap->navMesh->removeTile(tileRef, nullptr, nullptr); - } + dtTileRef tileRef = mmap->loadedTileRefs[packedGridPos]; // unload, and mark as non loaded - if (status != DT_SUCCESS) + if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, nullptr, nullptr))) { // this is technically a memory leak // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used @@ -224,11 +220,9 @@ namespace MMAP } else { - mmap->mmapLoadedTiles.erase(packedGridPos); + mmap->loadedTileRefs.erase(packedGridPos); --loadedTiles; -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) - LOG_DEBUG("server", "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); -#endif + LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); return true; } @@ -237,70 +231,52 @@ namespace MMAP bool MMapManager::unloadMap(uint32 mapId) { - std::unique_lock guard(MMapManagerLock); - - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::iterator itr = loadedMMaps.find(mapId); + if (itr == loadedMMaps.end() || !itr->second) { // file may not exist, therefore not loaded -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId); -#endif return false; } // unload all tiles from given map - MMapData* mmap = loadedMMaps[mapId]; - for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i) + MMapData* mmap = itr->second; + for (auto i : mmap->loadedTileRefs) { - uint32 x = (i->first >> 16); - uint32 y = (i->first & 0x0000FFFF); + uint32 x = (i.first >> 16); + uint32 y = (i.first & 0x0000FFFF); - dtStatus status; - { - std::unique_lock guard(GetMMapLock(mapId)); - status = mmap->navMesh->removeTile(i->second, nullptr, nullptr); - } - - if (status != DT_SUCCESS) + if (dtStatusFailed(mmap->navMesh->removeTile(i.second, nullptr, nullptr))) LOG_ERROR("server", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); else { --loadedTiles; -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("server", "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); -#endif } } delete mmap; - loadedMMaps.erase(mapId); -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) - LOG_DEBUG("server", "MMAP:unloadMap: Unloaded %03i.mmap", mapId); -#endif + itr->second = nullptr; + LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId); return true; } bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId) { - std::unique_lock guard(MMapManagerLock); - // check if we have this map loaded - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) { // file may not exist, therefore not loaded -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId); -#endif return false; } - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId); -#endif return false; } @@ -308,47 +284,44 @@ namespace MMAP dtFreeNavMeshQuery(query); mmap->navMeshQueries.erase(instanceId); -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) - LOG_DEBUG("server", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId); -#endif + LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId); return true; } dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId) { - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) return nullptr; - return loadedMMaps[mapId]->navMesh; + return itr->second->navMesh; } dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId) { - if (loadedMMaps.find(mapId) == loadedMMaps.end()) + MMapDataSet::const_iterator itr = GetMMapData(mapId); + if (itr == loadedMMaps.end()) return nullptr; - MMapData* mmap = loadedMMaps[mapId]; + MMapData* mmap = itr->second; if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { - // pussywizard: different instances of the same map shouldn't access this simultaneously - std::unique_lock guard(GetMMapLock(mapId)); // check again after acquiring mutex if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { // allocate mesh query dtNavMeshQuery* query = dtAllocNavMeshQuery(); ASSERT(query); - if (DT_SUCCESS != query->init(mmap->navMesh, 1024)) + + if (dtStatusFailed(query->init(mmap->navMesh, 1024))) { dtFreeNavMeshQuery(query); LOG_ERROR("server", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); return nullptr; } -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) - LOG_DEBUG("server", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); -#endif + LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); mmap->navMeshQueries.insert(std::pair(instanceId, query)); } } diff --git a/src/common/Collision/Management/MMapManager.h b/src/common/Collision/Management/MMapManager.h index d71e35b18e..d2ebb3b0d8 100644 --- a/src/common/Collision/Management/MMapManager.h +++ b/src/common/Collision/Management/MMapManager.h @@ -34,7 +34,8 @@ namespace MMAP // dummy struct to hold map's mmap data struct MMapData { - MMapData(dtNavMesh* mesh) : navMesh(mesh) {} + MMapData(dtNavMesh* mesh) : navMesh(mesh) { } + ~MMapData() { for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i) @@ -44,11 +45,10 @@ namespace MMAP dtFreeNavMesh(navMesh); } - dtNavMesh* navMesh; - // 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] + NavMeshQuerySet navMeshQueries; // instanceId to query + dtNavMesh* navMesh; + MMapTileSet loadedTileRefs; // maps [map grid coords] to [dtTile] }; typedef std::unordered_map MMapDataSet; @@ -58,9 +58,10 @@ namespace MMAP class MMapManager { public: - MMapManager() : loadedTiles(0) {} + MMapManager() : loadedTiles(0), thread_safe_environment(true) { } ~MMapManager(); + void InitializeThreadUnsafe(const std::vector& mapIds); bool loadMap(uint32 mapId, int32 x, int32 y); bool unloadMap(uint32 mapId, int32 x, int32 y); bool unloadMap(uint32 mapId); @@ -73,18 +74,14 @@ namespace MMAP uint32 getLoadedTilesCount() const { return loadedTiles; } uint32 getLoadedMapsCount() const { return loadedMMaps.size(); } - std::shared_mutex& GetMMapLock(uint32 mapId); - std::shared_mutex& GetMMapGeneralLock() { return MMapLock; } // pussywizard: in case a per-map mutex can't be found, should never happen - std::shared_mutex& GetManagerLock() { return MMapManagerLock; } private: bool loadMapData(uint32 mapId); uint32 packTileID(int32 x, int32 y); + MMapDataSet::const_iterator GetMMapData(uint32 mapId) const; MMapDataSet loadedMMaps; uint32 loadedTiles; - - std::shared_mutex MMapManagerLock; - std::shared_mutex MMapLock; // pussywizard: in case a per-map mutex can't be found, should never happen + bool thread_safe_environment; }; } diff --git a/src/common/Collision/Management/VMapFactory.cpp b/src/common/Collision/Management/VMapFactory.cpp index 36d22ac5b5..5e9a65eda2 100644 --- a/src/common/Collision/Management/VMapFactory.cpp +++ b/src/common/Collision/Management/VMapFactory.cpp @@ -9,14 +9,15 @@ namespace VMAP { - IVMapManager* gVMapManager = nullptr; + VMapManager2* gVMapManager = nullptr; //=============================================== // just return the instance - IVMapManager* VMapFactory::createOrGetVMapManager() + VMapManager2* VMapFactory::createOrGetVMapManager() { - if (gVMapManager == 0) - gVMapManager = new VMapManager2(); // should be taken from config ... Please change if you like :-) + if (!gVMapManager) + gVMapManager = new VMapManager2(); + return gVMapManager; } diff --git a/src/common/Collision/Management/VMapFactory.h b/src/common/Collision/Management/VMapFactory.h index d752ae50cc..03fe569766 100644 --- a/src/common/Collision/Management/VMapFactory.h +++ b/src/common/Collision/Management/VMapFactory.h @@ -9,20 +9,16 @@ #include "IVMapManager.h" -/** -This is the access point to the VMapManager. -*/ - +// This is the access point to the VMapManager. namespace VMAP { - //=========================================================== + class VMapManager2; class VMapFactory { public: - static IVMapManager* createOrGetVMapManager(); + static VMapManager2* createOrGetVMapManager(); static void clear(); }; - } #endif diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp index 7284762861..ff819e1336 100644 --- a/src/common/Collision/Management/VMapManager2.cpp +++ b/src/common/Collision/Management/VMapManager2.cpp @@ -15,21 +15,19 @@ * with this program. If not, see . */ -#include -#include -#include -#include #include "VMapManager2.h" #include "MapTree.h" #include "ModelInstance.h" #include "WorldModel.h" -#include -#include -#include "DisableMgr.h" -#include "DBCStores.h" +#include "MapDefines.h" #include "Log.h" #include "VMapDefinitions.h" -#include "GridDefines.h" +#include "Errors.h" +#include +#include +#include +#include +#include using G3D::Vector3; @@ -38,20 +36,32 @@ namespace VMAP VMapManager2::VMapManager2() { GetLiquidFlagsPtr = &GetLiquidFlagsDummy; + IsVMAPDisabledForPtr = &IsVMAPDisabledForDummy; + thread_safe_environment = true; } - VMapManager2::~VMapManager2(void) + VMapManager2::~VMapManager2() { for (InstanceTreeMap::iterator i = iInstanceMapTrees.begin(); i != iInstanceMapTrees.end(); ++i) { delete i->second; } + for (ModelFileMap::iterator i = iLoadedModelFiles.begin(); i != iLoadedModelFiles.end(); ++i) { delete i->second.getModel(); } } + void VMapManager2::InitializeThreadUnsafe(const std::vector& mapIds) + { + // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime + for (const uint32& mapId : mapIds) + iInstanceMapTrees.emplace(mapId, nullptr); + + thread_safe_environment = false; + } + Vector3 VMapManager2::convertPositionToInternalRep(float x, float y, float z) const { Vector3 pos; @@ -63,6 +73,16 @@ namespace VMAP return pos; } + InstanceTreeMap::const_iterator VMapManager2::GetMapTree(uint32 mapId) const + { + // return the iterator if found or end() if not found/NULL + InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId); + if (itr != iInstanceMapTrees.cend() && !itr->second) + itr = iInstanceMapTrees.cend(); + + return itr; + } + // move to MapTree too? std::string VMapManager2::getMapFileName(unsigned int mapId) { @@ -92,6 +112,15 @@ namespace VMAP { InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); if (instanceTree == iInstanceMapTrees.end()) + { + if (thread_safe_environment) + instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first; + else + ASSERT(false, "Invalid mapId %u tile [%u, %u] passed to VMapManager2 after startup in thread unsafe environment", + mapId, tileX, tileY); + } + + if (!instanceTree->second) { std::string mapFileName = getMapFileName(mapId); StaticMapTree* newTree = new StaticMapTree(mapId, basePath); @@ -100,7 +129,7 @@ namespace VMAP delete newTree; return false; } - instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, newTree)).first; + instanceTree->second = newTree; } return instanceTree->second->LoadMapTile(tileX, tileY, this); @@ -109,13 +138,13 @@ namespace VMAP void VMapManager2::unloadMap(unsigned int mapId) { InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); - if (instanceTree != iInstanceMapTrees.end()) + if (instanceTree != iInstanceMapTrees.end() && instanceTree->second) { instanceTree->second->UnloadMap(this); if (instanceTree->second->numLoadedTiles() == 0) { delete instanceTree->second; - iInstanceMapTrees.erase(mapId); + instanceTree->second = nullptr; } } } @@ -123,25 +152,25 @@ namespace VMAP void VMapManager2::unloadMap(unsigned int mapId, int x, int y) { InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); - if (instanceTree != iInstanceMapTrees.end()) + if (instanceTree != iInstanceMapTrees.end() && instanceTree->second) { instanceTree->second->UnloadMapTile(x, y, this); if (instanceTree->second->numLoadedTiles() == 0) { delete instanceTree->second; - iInstanceMapTrees.erase(mapId); + instanceTree->second = nullptr; } } } bool VMapManager2::isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_VMAP_CHECKS) - if (!isLineOfSightCalcEnabled() || DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, nullptr, VMAP_DISABLE_LOS)) +#if defined(ENABLE_VMAP_CHECKS) + if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS)) return true; #endif - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1); @@ -161,11 +190,11 @@ namespace VMAP */ bool VMapManager2::getObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_VMAP_CHECKS) - if (isLineOfSightCalcEnabled() && !DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, nullptr, VMAP_DISABLE_LOS)) +#if defined(ENABLE_VMAP_CHECKS) + if (isLineOfSightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS)) #endif { - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1); @@ -193,11 +222,11 @@ namespace VMAP float VMapManager2::getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_VMAP_CHECKS) - if (isHeightCalcEnabled() && !DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, nullptr, VMAP_DISABLE_HEIGHT)) +#if defined(ENABLE_VMAP_CHECKS) + if (isHeightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_HEIGHT)) #endif { - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { Vector3 pos = convertPositionToInternalRep(x, y, z); @@ -214,11 +243,11 @@ namespace VMAP bool VMapManager2::getAreaInfo(unsigned int mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_VMAP_CHECKS) - if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, nullptr, VMAP_DISABLE_AREAFLAG)) +#if defined(ENABLE_VMAP_CHECKS) + if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) #endif { - InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId); + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { Vector3 pos = convertPositionToInternalRep(x, y, z); @@ -234,11 +263,11 @@ namespace VMAP bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_VMAP_CHECKS) - if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_VMAP, mapId, nullptr, VMAP_DISABLE_LIQUIDSTATUS)) +#if defined(ENABLE_VMAP_CHECKS) + if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) #endif { - InstanceTreeMap::const_iterator instanceTree = iInstanceMapTrees.find(mapId); + InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); if (instanceTree != iInstanceMapTrees.end()) { LocationInfo info; @@ -262,7 +291,7 @@ namespace VMAP WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename) { //! Critical section, thread safe access to iLoadedModelFiles - std::lock_guard guard(LoadedModelFilesLock); + std::lock_guard lock(LoadedModelFilesLock); ModelFileMap::iterator model = iLoadedModelFiles.find(filename); if (model == iLoadedModelFiles.end()) @@ -274,20 +303,19 @@ namespace VMAP delete worldmodel; return nullptr; } -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str()); -#endif model = iLoadedModelFiles.insert(std::pair(filename, ManagedModel())).first; model->second.setModel(worldmodel); } - //model->second.incRefCount(); + return model->second.getModel(); } void VMapManager2::releaseModelInstance(const std::string& filename) { //! Critical section, thread safe access to iLoadedModelFiles - std::lock_guard guard(LoadedModelFilesLock); + std::lock_guard lock(LoadedModelFilesLock); + ModelFileMap::iterator model = iLoadedModelFiles.find(filename); if (model == iLoadedModelFiles.end()) { @@ -296,9 +324,7 @@ namespace VMAP } if (model->second.decRefCount() == 0) { -#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) LOG_DEBUG("maps", "VMapManager2: unloading file '%s'", filename.c_str()); -#endif delete model->second.getModel(); iLoadedModelFiles.erase(model); } @@ -309,4 +335,9 @@ namespace VMAP return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y); } + void VMapManager2::getInstanceMapTree(InstanceTreeMap& instanceMapTree) + { + instanceMapTree = iInstanceMapTrees; + } + } // namespace VMAP diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index 71fcbeaa33..514f03600c 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -19,9 +19,10 @@ #define _VMAPMANAGER2_H #include "IVMapManager.h" -#include "Define.h" +#include "Common.h" #include #include +#include //=========================================================== @@ -65,12 +66,22 @@ namespace VMAP typedef std::unordered_map InstanceTreeMap; typedef std::unordered_map ModelFileMap; + enum DisableTypes + { + VMAP_DISABLE_AREAFLAG = 0x1, + VMAP_DISABLE_HEIGHT = 0x2, + VMAP_DISABLE_LOS = 0x4, + VMAP_DISABLE_LIQUIDSTATUS = 0x8 + }; + class VMapManager2 : public IVMapManager { protected: // Tree to check collision ModelFileMap iLoadedModelFiles; InstanceTreeMap iInstanceMapTrees; + bool thread_safe_environment; + // Mutex for iLoadedModelFiles std::mutex LoadedModelFilesLock; @@ -78,6 +89,9 @@ namespace VMAP /* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */ static uint32 GetLiquidFlagsDummy(uint32) { return 0; } + static bool IsVMAPDisabledForDummy(uint32 /*entry*/, uint8 /*flags*/) { return false; } + + InstanceTreeMap::const_iterator GetMapTree(uint32 mapId) const; public: // public for debug @@ -87,6 +101,8 @@ namespace VMAP VMapManager2(); ~VMapManager2() override; + void InitializeThreadUnsafe(const std::vector& mapIds); + int loadMap(const char* pBasePath, unsigned int mapId, int x, int y) override; void unloadMap(unsigned int mapId, int x, int y) override; @@ -113,12 +129,14 @@ namespace VMAP return getMapFileName(mapId); } bool existsMap(const char* basePath, unsigned int mapId, int x, int y) override; - public: void getInstanceMapTree(InstanceTreeMap& instanceMapTree); typedef uint32(*GetLiquidFlagsFn)(uint32 liquidType); GetLiquidFlagsFn GetLiquidFlagsPtr; + + typedef bool(*IsVMAPDisabledForFn)(uint32 entry, uint8 flags); + IsVMAPDisabledForFn IsVMAPDisabledForPtr; }; } -#endif \ No newline at end of file +#endif diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h new file mode 100644 index 0000000000..e323dfcdea --- /dev/null +++ b/src/common/Collision/Maps/MapDefines.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2008+ TrinityCore + */ + +#ifndef _MAPDEFINES_H +#define _MAPDEFINES_H + +#include "Define.h" +#include "DetourNavMesh.h" + +#define MAX_NUMBER_OF_GRIDS 64 +#define SIZE_OF_GRIDS 533.3333f + +#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' +#define MMAP_VERSION 11 + +struct MmapTileHeader +{ + uint32 mmapMagic{MMAP_MAGIC}; + uint32 dtVersion; + uint32 mmapVersion{MMAP_VERSION}; + uint32 size{0}; + char usesLiquids{true}; + char padding[3]{}; + + MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) { } +}; + +// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files +static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size"); +static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) + + sizeof(MmapTileHeader::dtVersion) + + sizeof(MmapTileHeader::mmapVersion) + + sizeof(MmapTileHeader::size) + + sizeof(MmapTileHeader::usesLiquids) + + sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields"); + +enum NavTerrain +{ + NAV_EMPTY = 0x00, + NAV_GROUND = 0x01, + NAV_MAGMA = 0x02, + NAV_SLIME = 0x04, + NAV_WATER = 0x08, + NAV_UNUSED1 = 0x10, + NAV_UNUSED2 = 0x20, + NAV_UNUSED3 = 0x40, + NAV_UNUSED4 = 0x80 + // we only have 8 bits +}; + +#endif diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index 520ad8cc33..38e4f97d22 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -462,4 +462,10 @@ namespace VMAP } iLoadedTiles.erase(tile); } + + void StaticMapTree::getModelInstances(ModelInstance*& models, uint32& count) + { + models = iTreeValues; + count = iNTreeValues; + } } diff --git a/src/common/Collision/Maps/TileAssembler.cpp b/src/common/Collision/Maps/TileAssembler.cpp index dd4f2621e0..c4fbed2019 100644 --- a/src/common/Collision/Maps/TileAssembler.cpp +++ b/src/common/Collision/Maps/TileAssembler.cpp @@ -8,7 +8,7 @@ #include "MapTree.h" #include "BoundingIntervalHierarchy.h" #include "VMapDefinitions.h" -#include "SharedDefines.h" +#include "MapDefines.h" #include #include #include diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index 9a0e294a01..56b91c49d5 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -4,19 +4,13 @@ * Copyright (C) 2005-2009 MaNGOS */ +#include "GameObjectModel.h" #include "VMapFactory.h" #include "VMapManager2.h" #include "VMapDefinitions.h" #include "WorldModel.h" - -#include "GameObjectModel.h" #include "Log.h" -#include "GameObject.h" -#include "Creature.h" -#include "TemporarySummon.h" -#include "Object.h" -#include "DBCStores.h" -#include "World.h" +#include "Timer.h" using G3D::Vector3; using G3D::Ray; @@ -35,16 +29,14 @@ struct GameobjectModelData typedef std::unordered_map ModelList; ModelList model_list; -void LoadGameObjectModelList() +void LoadGameObjectModelList(std::string const& dataPath) { - //#ifndef NO_CORE_FUNCS uint32 oldMSTime = getMSTime(); - //#endif - FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); + FILE* model_list_file = fopen((dataPath + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); if (!model_list_file) { - LOG_ERROR("server", "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS); + LOG_ERROR("maps", "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS); return; } @@ -72,7 +64,8 @@ void LoadGameObjectModelList() || fread(&v1, sizeof(Vector3), 1, model_list_file) != 1 || fread(&v2, sizeof(Vector3), 1, model_list_file) != 1) { - LOG_ERROR("server", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); + LOG_ERROR("maps", "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); + fclose(model_list_file); break; } @@ -95,12 +88,12 @@ void LoadGameObjectModelList() GameObjectModel::~GameObjectModel() { if (iModel) - ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->releaseModelInstance(name); + VMAP::VMapFactory::createOrGetVMapManager()->releaseModelInstance(name); } -bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info) +bool GameObjectModel::initialize(std::unique_ptr modelOwner, std::string const& dataPath) { - ModelList::const_iterator it = model_list.find(info.Displayid); + ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId()); if (it == model_list.end()) return false; @@ -112,24 +105,18 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn return false; } - iModel = ((VMAP::VMapManager2*)VMAP::VMapFactory::createOrGetVMapManager())->acquireModelInstance(sWorld->GetDataPath() + "vmaps/", it->second.name); + iModel = VMAP::VMapFactory::createOrGetVMapManager()->acquireModelInstance(dataPath + "vmaps/", it->second.name); if (!iModel) return false; name = it->second.name; - //flags = VMAP::MOD_M2; - //adtId = 0; - //ID = 0; - iPos = Vector3(go.GetPositionX(), go.GetPositionY(), go.GetPositionZ()); - - // pussywizard: - phasemask = (go.GetGoState() == GO_STATE_READY || go.IsTransport()) ? go.GetPhaseMask() : 0; - - iScale = go.GetFloatValue(OBJECT_FIELD_SCALE_X); + iPos = modelOwner->GetPosition(); + phasemask = modelOwner->GetPhaseMask(); + iScale = modelOwner->GetScale(); iInvScale = 1.f / iScale; - G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(go.GetOrientation(), 0, 0); + G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(modelOwner->GetOrientation(), 0, 0); iInvRot = iRotation.inverse(); // transform bounding box: mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale); @@ -138,27 +125,24 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn rotated_bounds.merge(iRotation * mdl_box.corner(i)); iBound = rotated_bounds + iPos; + #ifdef SPAWN_CORNERS // test: for (int i = 0; i < 8; ++i) { Vector3 pos(iBound.corner(i)); - const_cast(go).SummonCreature(1, pos.x, pos.y, pos.z, 0, TEMPSUMMON_MANUAL_DESPAWN); + modelOwner->DebugVisualizeCorner(pos); } #endif - owner = &go; + owner = std::move(modelOwner); return true; } -GameObjectModel* GameObjectModel::Create(const GameObject& go) +GameObjectModel* GameObjectModel::Create(std::unique_ptr modelOwner, std::string const& dataPath) { - const GameObjectDisplayInfoEntry* info = sGameObjectDisplayInfoStore.LookupEntry(go.GetDisplayId()); - if (!info) - return nullptr; - GameObjectModel* mdl = new GameObjectModel(); - if (!mdl->initialize(go, *info)) + if (!mdl->initialize(std::move(modelOwner), dataPath)) { delete mdl; return nullptr; @@ -169,7 +153,7 @@ GameObjectModel* GameObjectModel::Create(const GameObject& go) bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const { - if (!(phasemask & ph_mask) || !owner->isSpawned()) + if (!(phasemask & ph_mask) || !owner->IsSpawned()) return false; float time = ray.intersectionTime(iBound); @@ -199,6 +183,7 @@ bool GameObjectModel::UpdatePosition() return false; G3D::AABox mdl_box(it->second.bound); + // ignore models with no bounds if (mdl_box == G3D::AABox::zero()) { @@ -206,12 +191,14 @@ bool GameObjectModel::UpdatePosition() return false; } - iPos = Vector3(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ()); + iPos = owner->GetPosition(); G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(owner->GetOrientation(), 0, 0); iInvRot = iRotation.inverse(); + // transform bounding box: mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale); AABox rotated_bounds; + for (int i = 0; i < 8; ++i) rotated_bounds.merge(iRotation * mdl_box.corner(i)); @@ -221,7 +208,7 @@ bool GameObjectModel::UpdatePosition() for (int i = 0; i < 8; ++i) { Vector3 pos(iBound.corner(i)); - owner->SummonCreature(1, pos.x, pos.y, pos.z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000); + owner->DebugVisualizeCorner(pos); } #endif diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h index 6e10df44a3..3051ba1605 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -7,13 +7,12 @@ #ifndef _GAMEOBJECT_MODEL_H #define _GAMEOBJECT_MODEL_H +#include "Define.h" #include #include #include #include -#include "Define.h" - namespace VMAP { class WorldModel; @@ -22,20 +21,23 @@ namespace VMAP class GameObject; struct GameObjectDisplayInfoEntry; -class GameObjectModel /*, public Intersectable*/ +class GameObjectModelOwnerBase { - uint32 phasemask{0}; - G3D::AABox iBound; - G3D::Matrix3 iInvRot; - G3D::Vector3 iPos; - //G3D::Vector3 iRot; - float iInvScale{0}; - float iScale{0}; - VMAP::WorldModel* iModel; - GameObject const* owner; +public: + virtual ~GameObjectModelOwnerBase() = default; - GameObjectModel() : iModel(nullptr), owner(nullptr) { } - bool initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info); + virtual bool IsSpawned() const = 0; + virtual uint32 GetDisplayId() const = 0; + virtual uint32 GetPhaseMask() const = 0; + virtual G3D::Vector3 GetPosition() const = 0; + virtual float GetOrientation() const = 0; + virtual float GetScale() const = 0; + virtual void DebugVisualizeCorner(G3D::Vector3 const& /*corner*/) const = 0; +}; + +class GameObjectModel +{ + GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(nullptr) { } public: std::string name; @@ -44,19 +46,33 @@ public: ~GameObjectModel(); - [[nodiscard]] const G3D::Vector3& getPosition() const { return iPos;} + [[nodiscard]] const G3D::Vector3& getPosition() const { return iPos; } - /** Enables\disables collision. */ - void disable() { phasemask = 0;} - void enable(uint32 ph_mask) { phasemask = ph_mask;} + /** Enables\disables collision. */ + void disable() { phasemask = 0; } + void enable(uint32 ph_mask) { phasemask = ph_mask; } - [[nodiscard]] bool isEnabled() const {return phasemask != 0;} + [[nodiscard]] bool isEnabled() const { return phasemask != 0; } bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const; - static GameObjectModel* Create(const GameObject& go); + static GameObjectModel* Create(std::unique_ptr modelOwner, std::string const& dataPath); bool UpdatePosition(); + +private: + bool initialize(std::unique_ptr modelOwner, std::string const& dataPath); + + uint32 phasemask; + G3D::AABox iBound; + G3D::Matrix3 iInvRot; + G3D::Vector3 iPos; + float iInvScale; + float iScale; + VMAP::WorldModel* iModel; + std::unique_ptr owner; }; -#endif // _GAMEOBJECT_MODEL_H \ No newline at end of file +void LoadGameObjectModelList(std::string const& dataPath); + +#endif // _GAMEOBJECT_MODEL_H diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h index 43d38566a8..1d9a11f726 100644 --- a/src/common/Collision/Models/ModelInstance.h +++ b/src/common/Collision/Models/ModelInstance.h @@ -7,13 +7,12 @@ #ifndef _MODELINSTANCE_H_ #define _MODELINSTANCE_H_ +#include "Define.h" #include #include #include #include -#include "Define.h" - namespace VMAP { class WorldModel; @@ -58,12 +57,11 @@ namespace VMAP void intersectPoint(const G3D::Vector3& p, AreaInfo& info) const; bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const; bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const; + WorldModel* getWorldModel() { return iModel; } protected: G3D::Matrix3 iInvRot; float iInvScale{0.0f}; WorldModel* iModel{nullptr}; - public: - WorldModel* getWorldModel(); }; } // namespace VMAP diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index e8333e0f6f..a65f305b7c 100644 --- a/src/common/Collision/Models/WorldModel.cpp +++ b/src/common/Collision/Models/WorldModel.cpp @@ -241,6 +241,13 @@ namespace VMAP return result; } + void WmoLiquid::getPosInfo(uint32& tilesX, uint32& tilesY, G3D::Vector3& corner) const + { + tilesX = iTilesX; + tilesY = iTilesY; + corner = iCorner; + } + // ===================== GroupModel ================================== GroupModel::GroupModel(const GroupModel& other): @@ -401,6 +408,13 @@ namespace VMAP return 0; } + void GroupModel::getMeshData(std::vector& outVertices, std::vector& outTriangles, WmoLiquid*& liquid) + { + outVertices = vertices; + outTriangles = triangles; + liquid = iLiquid; + } + // ===================== WorldModel ================================== void WorldModel::setGroupModels(std::vector& models) @@ -575,4 +589,9 @@ namespace VMAP fclose(rf); return result; } + + void WorldModel::getGroupModels(std::vector& outGroupModels) + { + outGroupModels = groupModels; + } } diff --git a/src/common/Collision/Models/WorldModel.h b/src/common/Collision/Models/WorldModel.h index 88558a03e1..75a809c27b 100644 --- a/src/common/Collision/Models/WorldModel.h +++ b/src/common/Collision/Models/WorldModel.h @@ -7,13 +7,12 @@ #ifndef _WORLDMODEL_H #define _WORLDMODEL_H +#include "Define.h" +#include "BoundingIntervalHierarchy.h" #include #include #include #include -#include "BoundingIntervalHierarchy.h" - -#include "Define.h" namespace VMAP { @@ -46,6 +45,7 @@ namespace VMAP uint32 GetFileSize(); bool writeToFile(FILE* wf); static bool readFromFile(FILE* rf, WmoLiquid*& liquid); + void getPosInfo(uint32& tilesX, uint32& tilesY, G3D::Vector3& corner) const; private: WmoLiquid() { } uint32 iTilesX{0}; //!< number of tiles in x direction, each @@ -54,8 +54,6 @@ namespace VMAP uint32 iType{0}; //!< liquid type float* iHeight{nullptr}; //!< (tilesX + 1)*(tilesY + 1) height values uint8* iFlags{nullptr}; //!< info if liquid tile is used - public: - void getPosInfo(uint32& tilesX, uint32& tilesY, G3D::Vector3& corner) const; }; /*! holding additional info for WMO group files */ @@ -80,6 +78,7 @@ namespace VMAP [[nodiscard]] const G3D::AABox& GetBound() const { return iBound; } [[nodiscard]] uint32 GetMogpFlags() const { return iMogpFlags; } [[nodiscard]] uint32 GetWmoID() const { return iGroupWMOID; } + void getMeshData(std::vector& outVertices, std::vector& outTriangles, WmoLiquid*& liquid); protected: G3D::AABox iBound; uint32 iMogpFlags{0};// 0x8 outdor; 0x2000 indoor @@ -88,8 +87,6 @@ namespace VMAP std::vector triangles; BIH meshTree; WmoLiquid* iLiquid{nullptr}; - public: - void getMeshData(std::vector& vertices, std::vector& triangles, WmoLiquid*& liquid); }; /*! Holds a model (converted M2 or WMO) in its original coordinate space */ class WorldModel @@ -105,12 +102,11 @@ namespace VMAP bool GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const; bool writeFile(const std::string& filename); bool readFile(const std::string& filename); + void getGroupModels(std::vector& outGroupModels); protected: uint32 RootWMOID{0}; std::vector groupModels; BIH groupTree; - public: - void getGroupModels(std::vector& groupModels); }; } // namespace VMAP diff --git a/src/common/Collision/VMapTools.h b/src/common/Collision/VMapTools.h index d29c4c50e8..5826941268 100644 --- a/src/common/Collision/VMapTools.h +++ b/src/common/Collision/VMapTools.h @@ -7,11 +7,10 @@ #ifndef _VMAPTOOLS_H #define _VMAPTOOLS_H +#include "Define.h" #include #include -#include "NodeValueAccess.h" - /** The Class is mainly taken from G3D/AABSPTree.h but modified to be able to use our internal data structure. This is an iterator that helps us analysing the BSP-Trees. @@ -40,7 +39,6 @@ namespace VMAP class MyCollisionDetection { - private: public: static bool collisionLocationForMovingPointFixedAABox( const G3D::Vector3& origin, diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index c191f1be9c..777d59bedd 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -45,9 +45,11 @@ namespace throw ConfigException(acore::StringFormat("Config::LoadFile: Failed open file '%s'", file.c_str())); uint32 count = 0; + uint32 lineNumber = 0; while (in.good()) { + lineNumber++; std::string line; std::getline(in, line); @@ -67,7 +69,9 @@ namespace auto const equal_pos = line.find('='); if (equal_pos == std::string::npos || equal_pos == line.length()) - return; + { + ABORT_MSG("> Config::LoadFile: Failure to read line number %u. Don't use only whitespace lines", lineNumber); + } auto entry = acore::String::Trim(line.substr(0, equal_pos), in.getloc()); auto value = acore::String::Trim(line.substr(equal_pos + 1), in.getloc()); diff --git a/src/common/PrecompiledHeaders/commonPCH.h b/src/common/PrecompiledHeaders/commonPCH.h index d0c15b17f0..27707525f9 100644 --- a/src/common/PrecompiledHeaders/commonPCH.h +++ b/src/common/PrecompiledHeaders/commonPCH.h @@ -2,7 +2,5 @@ #include "Common.h" #include "Log.h" -#include "DatabaseWorker.h" -#include "SQLOperation.h" #include "Errors.h" #include "TypeList.h" diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 0aca756ec9..d69f8b6155 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -8,10 +8,9 @@ #include "Common.h" #include "utf8.h" #include "Log.h" -#include "DatabaseWorker.h" -#include "SQLOperation.h" #include "Errors.h" #include "TypeList.h" +#include #include "SFMT.h" #include "Errors.h" // for ASSERT #include diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index d5f015bbdc..398cd53f52 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -80,6 +80,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_DEL_DISABLES, "DELETE FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA, "UPDATE creature SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, "UPDATE gameobject SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_GAMEOBJECT_ADDON, "INSERT INTO gameobject_addon (guid, invisibilityType, invisibilityValue) VALUES (?, 0, 0)", CONNECTION_ASYNC); // 0: uint8 PrepareStatement(WORLD_SEL_REQ_XP, "SELECT Experience FROM player_xp_for_level WHERE Level = ?", CONNECTION_SYNCH); } diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index 7e3600f7dd..f00ef5b1c2 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -102,6 +102,7 @@ enum WorldDatabaseStatements WORLD_UPD_CREATURE_ZONE_AREA_DATA, WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, WORLD_SEL_REQ_XP, + WORLD_INS_GAMEOBJECT_ADDON, MAX_WORLDDATABASE_STATEMENTS }; diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 2fd9044642..a6e81dd920 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -76,6 +76,12 @@ void TotemAI::UpdateAI(uint32 /*diff*/) me->VisitNearbyObject(max_range, checker); } + + if (!victim && me->GetCharmerOrOwnerOrSelf()->IsInCombat()) + { + victim = me->GetCharmerOrOwnerOrSelf()->GetVictim(); + } + // If have target if (victim) { diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index fe741f0026..f23a908207 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -787,7 +787,14 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl if (!map) { LOG_ERROR("server", "Battlefield::SpawnCreature: Can't create creature entry: %u map not found", entry); - return 0; + return nullptr; + } + + CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); + if (!cinfo) + { + LOG_ERROR("sql.sql", "Battlefield::SpawnCreature: entry %u does not exist.", entry); + return nullptr; } Creature* creature = new Creature(true); @@ -801,12 +808,6 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl creature->setFaction(BattlefieldFactions[teamId]); creature->SetHomePosition(x, y, z, o); - CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); - if (!cinfo) - { - LOG_ERROR("sql.sql", "Battlefield::SpawnCreature: entry %u does not exist.", entry); - return nullptr; - } // force using DB speeds -- do we really need this? creature->SetSpeed(MOVE_WALK, cinfo->speed_walk); creature->SetSpeed(MOVE_RUN, cinfo->speed_run); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index 3399feb48d..f7907b7350 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -142,6 +142,26 @@ void BattlegroundWS::RespawnFlagAfterDrop(TeamId teamId) _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15); RemoveAssaultAuras(); + + CheckFlagKeeperInArea(teamId == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE); +} + +void BattlegroundWS::CheckFlagKeeperInArea(TeamId teamId) +{ + if (GetStatus() != STATUS_IN_PROGRESS || GetFlagState(teamId) != BG_WS_FLAG_STATE_ON_PLAYER) + { + return; + } + + uint32 triggerId = teamId == TEAM_ALLIANCE ? BG_WS_TRIGGER_HORDE_FLAG_SPAWN : BG_WS_TRIGGER_ALLIANCE_FLAG_SPAWN; + AreaTrigger const* areaTrigger = sObjectMgr->GetAreaTrigger(triggerId); + if (Player* player = ObjectAccessor::GetPlayer(FindBgMap(), GetFlagPickerGUID(teamId))) + { + if (areaTrigger && player->IsInAreaTriggerRadius(areaTrigger)) + { + HandleAreaTrigger(player, triggerId); + } + } } void BattlegroundWS::EventPlayerCapturedFlag(Player* player) @@ -287,6 +307,8 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15); RemoveAssaultAuras(); + + CheckFlagKeeperInArea(TEAM_HORDE); return; } else @@ -318,6 +340,8 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* gameOb _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT10); _bgEvents.CancelEvent(BG_WS_EVENT_BOTH_FLAGS_KEPT15); RemoveAssaultAuras(); + + CheckFlagKeeperInArea(TEAM_ALLIANCE); return; } else @@ -354,11 +378,11 @@ void BattlegroundWS::HandleAreaTrigger(Player* player, uint32 trigger) switch (trigger) { - case 3646: // Alliance Flag spawn + case BG_WS_TRIGGER_ALLIANCE_FLAG_SPAWN: // Alliance Flag spawn if (GetFlagState(TEAM_ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE && GetFlagPickerGUID(TEAM_HORDE) == player->GetGUID()) EventPlayerCapturedFlag(player); break; - case 3647: // Horde Flag spawn + case BG_WS_TRIGGER_HORDE_FLAG_SPAWN: // Horde Flag spawn if (GetFlagState(TEAM_HORDE) == BG_WS_FLAG_STATE_ON_BASE && GetFlagPickerGUID(TEAM_ALLIANCE) == player->GetGUID()) EventPlayerCapturedFlag(player); break; @@ -366,12 +390,12 @@ void BattlegroundWS::HandleAreaTrigger(Player* player, uint32 trigger) case 3688: // Not used case 4628: // Not used case 4629: // Not used - case 3686: // Alliance elixir of speed spawn - case 3687: // Horde elixir of speed spawn - case 3706: // Alliance elixir of regeneration spawn - case 3708: // Horde elixir of regeneration spawn - case 3707: // Alliance elixir of berserk spawn - case 3709: // Horde elixir of berserk spawn + case BG_WS_TRIGGER_ALLIANCE_ELIXIR_SPEED_SPAWN: // Alliance elixir of speed spawn + case BG_WS_TRIGGER_HORDE_ELIXIR_SPEED_SPAWN: // Horde elixir of speed spawn + case BG_WS_TRIGGER_ALLIANCE_ELIXIR_REGEN_SPAWN: // Alliance elixir of regeneration spawn + case BG_WS_TRIGGER_HORDE_ELIXIR_REGEN_SPAWN: // Horde elixir of regeneration spawn + case BG_WS_TRIGGER_ALLIANCE_ELIXIR_BERSERK_SPAWN: // Alliance elixir of berserk spawn + case BG_WS_TRIGGER_HORDE_ELIXIR_BERSERK_SPAWN: // Horde elixir of berserk spawn break; } } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index 31c55431c8..46f9d91dd5 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -135,6 +135,21 @@ enum BG_WS_Objectives WS_EVENT_START_BATTLE = 8563 }; +enum BG_WS_Trigger +{ + BG_WS_TRIGGER_ALLIANCE_FLAG_SPAWN = 3646, + BG_WS_TRIGGER_HORDE_FLAG_SPAWN = 3647, + + BG_WS_TRIGGER_ALLIANCE_ELIXIR_SPEED_SPAWN = 3686, + BG_WS_TRIGGER_HORDE_ELIXIR_SPEED_SPAWN = 3687, + + BG_WS_TRIGGER_ALLIANCE_ELIXIR_REGEN_SPAWN = 3706, + BG_WS_TRIGGER_HORDE_ELIXIR_REGEN_SPAWN = 3708, + + BG_WS_TRIGGER_ALLIANCE_ELIXIR_BERSERK_SPAWN = 3707, + BG_WS_TRIGGER_HORDE_ELIXIR_BERSERK_SPAWN = 3709, +}; + struct BattlegroundWGScore : public BattlegroundScore { BattlegroundWGScore(Player* player): BattlegroundScore(player), FlagCaptures(0), FlagReturns(0) { } @@ -163,6 +178,7 @@ public: void SetFlagPicker(ObjectGuid guid, TeamId teamId) { _flagKeepers[teamId] = guid; } void RespawnFlagAfterDrop(TeamId teamId); uint8 GetFlagState(TeamId teamId) const { return _flagState[teamId]; } + void CheckFlagKeeperInArea(TeamId teamId); /* Battleground Events */ void EventPlayerDroppedFlag(Player* player) override; diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index 7aaff1d3e7..85b6b3f541 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -5,16 +5,16 @@ */ #include "DisableMgr.h" +#include "MMapFactory.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" #include "Player.h" #include "SpellInfo.h" #include "SpellMgr.h" -#include "VMapManager2.h" +#include "World.h" namespace DisableMgr { - namespace { struct DisableData @@ -197,28 +197,28 @@ namespace DisableMgr switch (mapEntry->map_type) { case MAP_COMMON: - if (flags & VMAP_DISABLE_AREAFLAG) + if (flags & VMAP::VMAP_DISABLE_AREAFLAG) LOG_INFO("server", "Areaflag disabled for world map %u.", entry); - if (flags & VMAP_DISABLE_LIQUIDSTATUS) + if (flags & VMAP::VMAP_DISABLE_LIQUIDSTATUS) LOG_INFO("server", "Liquid status disabled for world map %u.", entry); break; case MAP_INSTANCE: case MAP_RAID: - if (flags & VMAP_DISABLE_HEIGHT) + if (flags & VMAP::VMAP_DISABLE_HEIGHT) LOG_INFO("server", "Height disabled for instance map %u.", entry); - if (flags & VMAP_DISABLE_LOS) + if (flags & VMAP::VMAP_DISABLE_LOS) LOG_INFO("server", "LoS disabled for instance map %u.", entry); break; case MAP_BATTLEGROUND: - if (flags & VMAP_DISABLE_HEIGHT) + if (flags & VMAP::VMAP_DISABLE_HEIGHT) LOG_INFO("server", "Height disabled for battleground map %u.", entry); - if (flags & VMAP_DISABLE_LOS) + if (flags & VMAP::VMAP_DISABLE_LOS) LOG_INFO("server", "LoS disabled for battleground map %u.", entry); break; case MAP_ARENA: - if (flags & VMAP_DISABLE_HEIGHT) + if (flags & VMAP::VMAP_DISABLE_HEIGHT) LOG_INFO("server", "Height disabled for arena map %u.", entry); - if (flags & VMAP_DISABLE_LOS) + if (flags & VMAP::VMAP_DISABLE_LOS) LOG_INFO("server", "LoS disabled for arena map %u.", entry); break; default: @@ -360,4 +360,17 @@ namespace DisableMgr return false; } + bool IsVMAPDisabledFor(uint32 entry, uint8 flags) + { + return IsDisabledFor(DISABLE_TYPE_VMAP, entry, nullptr, flags); + } + + bool IsPathfindingEnabled(const Map* map) + { + if (!map) + return false; + + return !MMAP::MMapFactory::forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena()); + } + } // Namespace diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h index 9770c092ff..92c35d8c40 100644 --- a/src/server/game/Conditions/DisableMgr.h +++ b/src/server/game/Conditions/DisableMgr.h @@ -8,6 +8,8 @@ #define ACORE_DISABLEMGR_H #include "Define.h" +#include "Map.h" +#include "VMapManager2.h" class Unit; @@ -38,19 +40,13 @@ enum SpellDisableTypes SPELL_DISABLE_LOS) }; -enum VmapDisableTypes -{ - VMAP_DISABLE_AREAFLAG = 0x1, - VMAP_DISABLE_HEIGHT = 0x2, - VMAP_DISABLE_LOS = 0x4, - VMAP_DISABLE_LIQUIDSTATUS = 0x8, -}; - namespace DisableMgr { void LoadDisables(); bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags = 0); void CheckQuestDisables(); + bool IsVMAPDisabledFor(uint32 entry, uint8 flags); + bool IsPathfindingEnabled(const Map* map); } #endif //ACORE_DISABLEMGR_H diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index e00bfe2348..d40716982e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2236,8 +2236,8 @@ bool Creature::_IsTargetAcceptable(const Unit* target) const if (target->HasUnitState(UNIT_STATE_DIED)) { - // guards can detect fake death - if (IsGuard() && target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH)) + // some creatures can detect fake death + if (CanIgnoreFeignDeath() && target->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH)) return true; else return false; diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index de79c537db..3072e7ca59 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -44,7 +44,7 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_IGNORE_COMBAT = 0x00002000, CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging) CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard - CREATURE_FLAG_EXTRA_UNUSED_17 = 0x00010000, + CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH = 0x00010000, // creature ignores feign death CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes CREATURE_FLAG_EXTRA_NO_SKILL_GAINS = 0x00040000, // creature won't increase weapon skills CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS = 0x00080000, // Taunt is subject to diminishing returns on this creature @@ -62,7 +62,7 @@ enum CreatureFlagsExtra : uint32 CREATURE_FLAG_EXTRA_UNUSED_32 = 0x80000000, // Masks - CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_10 | CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_17 | + CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_10 | CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_22 | CREATURE_FLAG_EXTRA_UNUSED_25 | CREATURE_FLAG_EXTRA_UNUSED_26 | CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28 | CREATURE_FLAG_EXTRA_UNUSED_32), CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) @@ -635,6 +635,7 @@ public: bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; } bool CanAssistTo(const Unit* u, const Unit* enemy, bool checkfaction = true) const; bool _IsTargetAcceptable(const Unit* target) const; + bool CanIgnoreFeignDeath() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH) != 0; } bool _CanDetectFeignDeathOf(const Unit* target) const; // pussywizard // pussywizard: updated at faction change, disable move in line of sight if actual faction is not hostile to anyone diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index c3b17bb7d4..19041c6f0f 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -21,8 +21,8 @@ struct FormationInfo float follow_dist; float follow_angle; uint8 groupAI; - uint16 point_1; - uint16 point_2; + uint32 point_1; + uint32 point_2; }; typedef std::unordered_map CreatureGroupInfoType; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 1c0d4ea152..1d3b8c3306 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -58,6 +58,7 @@ GameObject::GameObject() : WorldObject(false), MovableMapObject(), m_lootGenerationTime = 0; ResetLootMode(); // restore default loot mode + loot.sourceGameObject = this; m_stationaryPosition.Relocate(0.0f, 0.0f, 0.0f, 0.0f); } @@ -310,7 +311,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u SetDisplayId(goinfo->displayId); if (!m_model) - m_model = GameObjectModel::Create(*this); + m_model = CreateModel(); switch (goinfo->type) { @@ -844,7 +845,7 @@ void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner) } } -void GameObject::SaveToDB() +void GameObject::SaveToDB(bool saveAddon /*= false*/) { // this should only be used when the gameobject has already been loaded // preferably after adding to map, because mapid may not be valid otherwise @@ -855,10 +856,10 @@ void GameObject::SaveToDB() return; } - SaveToDB(GetMapId(), data->spawnMask, data->phaseMask); + SaveToDB(GetMapId(), data->spawnMask, data->phaseMask, saveAddon); } -void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) +void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool saveAddon /*= false*/) { const GameObjectTemplate* goI = GetGOInfo(); @@ -913,6 +914,14 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) stmt->setUInt8(index++, uint8(GetGoState())); trans->Append(stmt); + if (saveAddon && !sObjectMgr->GetGameObjectAddon(m_spawnId)) + { + index = 0; + stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GAMEOBJECT_ADDON); + stmt->setUInt32(index++, m_spawnId); + trans->Append(stmt); + } + WorldDatabase.CommitTransaction(trans); } @@ -1952,7 +1961,7 @@ bool GameObject::IsInRange(float x, float y, float z, float radius) const if (G3D::fuzzyEq(dist, 0.0f)) return true; - float scale = GetFloatValue(OBJECT_FIELD_SCALE_X); + float scale = GetObjectScale(); float sinB = dx / dist; float cosB = dy / dist; dx = dist * (cosA * cosB + sinA * sinB); @@ -2289,7 +2298,7 @@ void GameObject::UpdateModel() if (GetMap()->ContainsGameObjectModel(*m_model)) GetMap()->RemoveGameObjectModel(*m_model); delete m_model; - m_model = GameObjectModel::Create(*this); + m_model = CreateModel(); if (m_model) GetMap()->InsertGameObjectModel(*m_model); } @@ -2508,4 +2517,26 @@ void GameObject::UpdateModelPosition() } } -std::unordered_map GameObject::gameObjectToEventFlag = {}; +std::unordered_map GameObject::gameObjectToEventFlag = { }; + +class GameObjectModelOwnerImpl : public GameObjectModelOwnerBase +{ +public: + explicit GameObjectModelOwnerImpl(GameObject* owner) : _owner(owner) { } + + bool IsSpawned() const override { return _owner->isSpawned(); } + uint32 GetDisplayId() const override { return _owner->GetDisplayId(); } + uint32 GetPhaseMask() const override { return (_owner->GetGoState() == GO_STATE_READY || _owner->IsTransport()) ? _owner->GetPhaseMask() : 0; } + G3D::Vector3 GetPosition() const override { return G3D::Vector3(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); } + float GetOrientation() const override { return _owner->GetOrientation(); } + float GetScale() const override { return _owner->GetObjectScale(); } + void DebugVisualizeCorner(G3D::Vector3 const& corner) const override { const_cast(_owner)->SummonCreature(1, corner.x, corner.y, corner.z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 10000); } + +private: + GameObject* _owner; +}; + +GameObjectModel* GameObject::CreateModel() +{ + return GameObjectModel::Create(std::make_unique(this), sWorld->GetDataPath()); +} diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index aa88c63bcf..e139f39f81 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -759,8 +759,8 @@ public: // overwrite WorldObject function for proper name localization [[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override; - void SaveToDB(); - void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask); + void SaveToDB(bool saveAddon = false); + void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool saveAddon = false); bool LoadFromDB(ObjectGuid::LowType guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); } bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true); void DeleteFromDB(); @@ -953,6 +953,7 @@ public: protected: bool AIM_Initialize(); + GameObjectModel* CreateModel(); void UpdateModel(); // updates model in case displayId were changed uint32 m_spellId; time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()), diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index adcdc73a26..992b0d8af7 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1824,6 +1824,8 @@ void Player::Update(uint32 p_time) m_zoneUpdateTimer -= p_time; } + sScriptMgr->OnPlayerUpdate(this, p_time); + if (IsAlive()) { m_regenTimer += p_time; @@ -2221,6 +2223,9 @@ void Player::SendTeleportAckPacket() bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options /*= 0*/, Unit* target /*= nullptr*/) { + // for except kick by antispeedhack + sScriptMgr->AnticheatSetSkipOnePacketForASH(this, true); + if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) { LOG_ERROR("server", "TeleportTo: invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player (%s, name: %s, map: %d, X: %f, Y: %f, Z: %f, O: %f).", @@ -24857,7 +24862,7 @@ void Player::ResurectUsingRequestData() void Player::SetClientControl(Unit* target, bool allowMove, bool packetOnly /*= false*/) { WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size() + 1); - data.append(target->GetPackGUID()); + data << target->GetPackGUID(); data << uint8((allowMove && !target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED)) ? 1 : 0); GetSession()->SendPacket(&data); @@ -25843,7 +25848,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) // Xinef: exploit protection, dont allow to loot normal items if player is not master loot and not below loot threshold // Xinef: only quest, ffa and conditioned items - if (!item->is_underthreshold && !GetLootGUID().IsItem() && GetGroup() && GetGroup()->GetLootMethod() == MASTER_LOOT && GetGUID() != GetGroup()->GetMasterLooterGuid()) + if (!item->is_underthreshold && loot->roundRobinPlayer && !GetLootGUID().IsItem() && GetGroup() && GetGroup()->GetLootMethod() == MASTER_LOOT && GetGUID() != GetGroup()->GetMasterLooterGuid()) if (qitem == nullptr && ffaitem == nullptr && conditem == nullptr) { SendLootRelease(GetLootGUID()); @@ -28125,6 +28130,8 @@ bool Player::SetDisableGravity(bool disable, bool packetOnly /*= false*/) bool Player::SetCanFly(bool apply, bool packetOnly /*= false*/) { + sScriptMgr->AnticheatSetCanFlybyServer(this, apply); + if (!packetOnly && !Unit::SetCanFly(apply)) return false; diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 1abbe77ecc..002906ab24 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -91,7 +91,7 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u // pussywizard: no PathRotation for MotionTransports SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f); - m_model = GameObjectModel::Create(*this); + m_model = CreateModel(); return true; } @@ -722,7 +722,7 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m SetDisplayId(goinfo->displayId); if (!m_model) - m_model = GameObjectModel::Create(*this); + m_model = CreateModel(); SetGoType(GameobjectTypes(goinfo->type)); SetGoState(go_state); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d79c8371fe..f9e63895e7 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -16,6 +16,7 @@ #include "CreatureAI.h" #include "CreatureAIImpl.h" #include "CreatureGroups.h" +#include "DisableMgr.h" #include "DynamicVisibility.h" #include "Formulas.h" #include "GridNotifiersImpl.h" @@ -1612,8 +1613,12 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) if (Unit* caster = (*dmgShieldItr)->GetCaster()) damage = this->SpellDamageBonusTaken(caster, i_spellProto, damage, SPELL_DIRECT_DAMAGE); - // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that - Unit::DealDamageMods(this, damage, nullptr); + uint32 absorb = 0; + uint32 resist = 0; + Unit::CalcAbsorbResist(victim, this, i_spellProto->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, i_spellProto); + damage -= absorb + resist; + + Unit::DealDamageMods(this, damage, &absorb); // TODO: Move this to a packet handler WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8 + 8 + 4 + 4 + 4 + 4)); @@ -1623,7 +1628,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) data << uint32(damage); // Damage int32 overkill = int32(damage) - int32(GetHealth()); data << uint32(overkill > 0 ? overkill : 0); // Overkill - data << uint32(i_spellProto->SchoolMask); + data << uint32(i_spellProto->GetSchoolMask()); victim->SendMessageToSet(&data, true); Unit::DealDamage(victim, this, damage, 0, SPELL_DIRECT_DAMAGE, i_spellProto->GetSchoolMask(), i_spellProto, true); @@ -2230,24 +2235,24 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr } } -Position* Unit::GetMeleeAttackPoint(Unit* attacker) +bool Unit::GetMeleeAttackPoint(Unit* attacker, Position& pos) { if (!attacker) { - return nullptr; + return false; } AttackerSet attackers = getAttackers(); if (attackers.size() <= 1) // if the attackers are not more than one { - return nullptr; + return false; } float meleeReach = GetExactDist2d(attacker); if (meleeReach <= 0) { - return nullptr; + return false; } float minAngle = 0; @@ -2259,17 +2264,13 @@ Position* Unit::GetMeleeAttackPoint(Unit* attacker) for (const auto& otherAttacker: attackers) { // if the otherAttacker is not valid, skip - if (!otherAttacker || - otherAttacker->GetGUID() == attacker->GetGUID() || - !otherAttacker->IsWithinMeleeRange(this) || - otherAttacker->isMoving() - ) + if (!otherAttacker || otherAttacker->GetGUID() == attacker->GetGUID() || + !otherAttacker->IsWithinMeleeRange(this) || otherAttacker->isMoving()) { continue; } float curretAngle = atan(attacker->GetExactDist2d(otherAttacker) / meleeReach); - if (minAngle == 0 || curretAngle < minAngle) { minAngle = curretAngle; @@ -2280,7 +2281,9 @@ Position* Unit::GetMeleeAttackPoint(Unit* attacker) } if (!validAttackers || !refUnit) - return nullptr; + { + return false; + } float contactDist = attackerSize + refUnit->GetCollisionRadius(); float requiredAngle = atan(contactDist / meleeReach); @@ -2292,7 +2295,7 @@ Position* Unit::GetMeleeAttackPoint(Unit* attacker) if (attackersAngle > angleTollerance) { - return nullptr; + return false; } double angle = atan(contactDist / meleeReach); @@ -2312,11 +2315,13 @@ Position* Unit::GetMeleeAttackPoint(Unit* attacker) if (!GetMap()->CanReachPositionAndGetValidCoords(this, x, y, z, true, true)) { - return nullptr; + return false; } } - return new Position(x,y,z); + pos.Relocate(x, y, z); + + return true; } void Unit::HandleProcExtraAttackFor(Unit* victim) @@ -11237,25 +11242,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui if (spellProto->ValidateAttribute6SpellDamageMods(caster, *i, damagetype == DOT)) AddPct(TakenTotalMod, (*i)->GetAmount()); - // .. taken pct: dummy auras - AuraEffectList const& mDummyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch ((*i)->GetSpellInfo()->SpellIconID) - { - // Cheat Death - case 2109: - if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap - // is 22.5% critical strike damage reduction, or 444 resilience. - // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%) - float mod = -1.0f * GetMeleeCritDamageReduction(400); - AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); - } - break; - } - } + TakenTotalMod = processDummyAuras(TakenTotalMod); // From caster spells if (caster) @@ -11350,6 +11337,41 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui return uint32(std::max(tmpDamage, 0.0f)); } +float Unit::processDummyAuras(float TakenTotalMod) const +{ + // note: old code coming from TC, just extracted here to remove the code duplication + solve potential crash + // see: https://github.com/TrinityCore/TrinityCore/commit/c85710e148d75450baedf6632b9ca6fd40b4148e + + // .. taken pct: dummy auras + auto const& mDummyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); + for (auto i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) + { + if (!(*i) || !(*i)->GetSpellInfo()) + { + continue; + } + + if (auto spellIconId = (*i)->GetSpellInfo()->SpellIconID) + { + switch (spellIconId) + { + // Cheat Death + case 2109: + if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) + { + // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap + // is 22.5% critical strike damage reduction, or 444 resilience. + // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%) + float mod = -1.0f * GetMeleeCritDamageReduction(400); + AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); + } + break; + } + } + } + return TakenTotalMod; +} + int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) { int32 DoneAdvertisedBenefit = 0; @@ -12587,25 +12609,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT } } - // .. taken pct: dummy auras - AuraEffectList const& mDummyAuras = GetAuraEffectsByType(SPELL_AURA_DUMMY); - for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i) - { - switch ((*i)->GetSpellInfo()->SpellIconID) - { - // Cheat Death - case 2109: - if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) - { - // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap - // is 22.5% critical strike damage reduction, or 444 resilience. - // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%) - float mod = -1.0f * GetMeleeCritDamageReduction(400); - AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount()))); - } - break; - } - } + TakenTotalMod = processDummyAuras(TakenTotalMod); // .. taken pct: class scripts /*AuraEffectList const& mclassScritAuras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); @@ -12755,6 +12759,8 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) if (Player* player = ToPlayer()) { + sScriptMgr->AnticheatSetUnderACKmount(player); + // mount as a vehicle if (VehicleId) { @@ -12843,6 +12849,8 @@ void Unit::Dismount() // (it could probably happen when logging in after a previous crash) if (Player* player = ToPlayer()) { + sScriptMgr->AnticheatSetUnderACKmount(player); + if (Pet* pPet = player->GetPet()) { if (pPet->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED)) @@ -17288,6 +17296,11 @@ void Unit::SetControlled(bool apply, UnitState state) default: break; } + + if (GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetRootACKUpd(ToPlayer()); + } } else { @@ -17379,7 +17392,10 @@ void Unit::SetStunned(bool apply) if (GetTypeId() != TYPEID_PLAYER) StopMoving(); else + { SetStandState(UNIT_STAND_STATE_STAND); + sScriptMgr->AnticheatSetSkipOnePacketForASH(ToPlayer(), true); + } CastStop(); } @@ -17443,6 +17459,8 @@ void Unit::SetRooted(bool apply) data << GetPackGUID(); data << m_rootTimes; SendMessageToSet(&data, true); + + sScriptMgr->AnticheatSetSkipOnePacketForASH(ToPlayer(), true); } else { @@ -17499,6 +17517,11 @@ void Unit::SetFeared(bool apply) if (!caster) caster = getAttackerForHelper(); GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY) : 0); // caster == nullptr processed in MoveFleeing + + if (GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(ToPlayer(), true); + } } else { @@ -17531,6 +17554,11 @@ void Unit::SetConfused(bool apply) { SetTarget(); GetMotionMaster()->MoveConfused(); + + if (GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(ToPlayer(), true); + } } else { @@ -17859,6 +17887,11 @@ void Unit::RemoveCharmedBy(Unit* charmer) } } + if (Player* player = ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(player); + } + // xinef: restore threat for (CharmThreatMap::const_iterator itr = _charmThreatInfo.begin(); itr != _charmThreatInfo.end(); ++itr) { @@ -18358,6 +18391,8 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) if (player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_FLY)) player->SetCanFly(true, true); + + sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true); } } @@ -18792,6 +18827,12 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) void Unit::EnterVehicle(Unit* base, int8 seatId) { CastCustomSpell(VEHICLE_SPELL_RIDE_HARDCODED, SPELLVALUE_BASE_POINT0, seatId + 1, base, TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE); + + if (Player* player = ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(player); + sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true); + } } void Unit::EnterVehicleUnattackable(Unit* base, int8 seatId) @@ -18836,6 +18877,9 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat()) return; + sScriptMgr->AnticheatSetUnderACKmount(player); + sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true); + InterruptNonMeleeSpells(false); player->StopCastingCharm(); player->StopCastingBindSight(); @@ -18899,6 +18943,12 @@ void Unit::ExitVehicle(Position const* /*exitPosition*/) //! init spline movement based on those coordinates in unapply handlers, and //! relocate exiting passengers based on Unit::moveSpline data. Either way, //! Coming Soon(TM) + + if (Player* player = ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(player); + sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true); + } } bool VehicleDespawnEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) @@ -18954,7 +19004,12 @@ void Unit::_ExitVehicle(Position const* exitPosition) AddUnitState(UNIT_STATE_MOVE); if (player) + { player->SetFallInformation(time(nullptr), GetPositionZ()); + + sScriptMgr->AnticheatSetUnderACKmount(player); + sScriptMgr->AnticheatSetSkipOnePacketForASH(player, true); + } else if (HasUnitMovementFlag(MOVEMENTFLAG_ROOT)) { WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); @@ -19515,7 +19570,7 @@ void Unit::PetSpellFail(const SpellInfo* spellInfo, Unit* target, uint32 result) if (!charmInfo || GetTypeId() != TYPEID_UNIT) return; - if ((MMAP::MMapFactory::IsPathfindingEnabled(GetMap()) || result != SPELL_FAILED_LINE_OF_SIGHT) && target) + if ((DisableMgr::IsPathfindingEnabled(GetMap()) || result != SPELL_FAILED_LINE_OF_SIGHT) && target) { if ((result == SPELL_FAILED_LINE_OF_SIGHT || result == SPELL_FAILED_OUT_OF_RANGE) || !ToCreature()->HasReactState(REACT_PASSIVE)) if (Unit* owner = GetOwner()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f7d25cdee1..4f61395fbd 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -500,17 +500,18 @@ enum UnitState | UNIT_STATE_EVADE | UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE | UNIT_STATE_IGNORE_PATHFINDING | UNIT_STATE_NO_ENVIRONMENT_UPD, - UNIT_STATE_UNATTACKABLE = UNIT_STATE_IN_FLIGHT, + UNIT_STATE_UNATTACKABLE = UNIT_STATE_IN_FLIGHT, // for real move using movegen check and stop (except unstoppable flight) - UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, - UNIT_STATE_CONTROLLED = (UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING), - UNIT_STATE_LOST_CONTROL = (UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING), - UNIT_STATE_SIGHTLESS = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE), - UNIT_STATE_CANNOT_AUTOATTACK = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_CASTING), - UNIT_STATE_CANNOT_TURN = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING | UNIT_STATE_ROOT), + UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, + UNIT_STATE_CONTROLLED = (UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING), + UNIT_STATE_LOST_CONTROL = (UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING), + UNIT_STATE_SIGHTLESS = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE), + UNIT_STATE_CANNOT_AUTOATTACK = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_CASTING), + UNIT_STATE_CANNOT_TURN = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_ROTATING | UNIT_STATE_ROOT), // stay by different reasons - UNIT_STATE_NOT_MOVE = UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DIED | UNIT_STATE_DISTRACTED, - UNIT_STATE_ALL_STATE = 0xffffffff //(UNIT_STATE_STOPPED | UNIT_STATE_MOVING | UNIT_STATE_IN_COMBAT | UNIT_STATE_IN_FLIGHT) + UNIT_STATE_NOT_MOVE = UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DIED | UNIT_STATE_DISTRACTED, + UNIT_STATE_IGNORE_ANTISPEEDHACK = UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED | UNIT_STATE_CHARGING | UNIT_STATE_DISTRACTED | UNIT_STATE_POSSESSED, + UNIT_STATE_ALL_STATE = 0xffffffff //(UNIT_STATE_STOPPED | UNIT_STATE_MOVING | UNIT_STATE_IN_COMBAT | UNIT_STATE_IN_FLIGHT) }; enum UnitMoveType @@ -1467,7 +1468,7 @@ public: bool AttackStop(); void RemoveAllAttackers(); [[nodiscard]] AttackerSet const& getAttackers() const { return m_attackers; } - [[nodiscard]] Position* GetMeleeAttackPoint(Unit* attacker); + [[nodiscard]] bool GetMeleeAttackPoint(Unit* attacker, Position& pos); [[nodiscard]] bool isAttackingPlayer() const; [[nodiscard]] Unit* GetVictim() const { return m_attacking; } @@ -2620,6 +2621,8 @@ private: uint32 _oldFactionId; ///< faction before charm bool m_petCatchUp; + + float processDummyAuras(float TakenTotalMod) const; }; namespace acore diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 759480b648..477c5e091e 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -423,14 +423,15 @@ void ObjectMgr::LoadGossipMenuItemsLocales() uint16 MenuID = fields[0].GetUInt16(); uint16 OptionID = fields[1].GetUInt16(); std::string LocaleName = fields[2].GetString(); - std::string OptionText = fields[3].GetString(); - std::string BoxText = fields[4].GetString(); - GossipMenuItemsLocale& data = _gossipMenuItemsLocaleStore[MAKE_PAIR32(MenuID, OptionID)]; LocaleConstant locale = GetLocaleByName(LocaleName); if (locale == LOCALE_enUS) continue; + std::string OptionText = fields[3].GetString(); + std::string BoxText = fields[4].GetString(); + + GossipMenuItemsLocale& data = _gossipMenuItemsLocaleStore[MAKE_PAIR32(MenuID, OptionID)]; AddLocaleString(OptionText, locale, data.OptionText); AddLocaleString(BoxText, locale, data.BoxText); } while (result->NextRow()); diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index deaf07835e..1f0b957547 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -9,6 +9,7 @@ #include "Common.h" #include "NGrid.h" +#include "MapDefines.h" #include // Forward class definitions @@ -22,10 +23,7 @@ class ObjectGuid; #define MAX_NUMBER_OF_CELLS 8 -#define MAX_NUMBER_OF_GRIDS 64 - -#define SIZE_OF_GRIDS 533.3333f -#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) +#define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) #define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 84f4b27610..1b97b7fe06 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -931,7 +931,7 @@ namespace acore bool operator()(Unit* u) { if (u->isTargetableForAttack(true, i_funit) && i_obj->IsWithinDistInMap(u, i_range) && - !i_funit->IsFriendlyTo(u) && i_funit->CanSeeOrDetect(u)) + (i_funit->IsInCombatWith(u) || i_funit->IsHostileTo(u)) && i_obj->CanSeeOrDetect(u)) { i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check return true; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index bc4f39d9ac..ba03535bac 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -557,10 +557,6 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R CharacterDatabase.Execute(stmt); } - // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline - if (!player || player->GetSkillValue(SKILL_ENCHANTING)) - ResetMaxEnchantingLevel(); - // Remove player from loot rolls for (Rolls::iterator it = RollId.begin(); it != RollId.end();) { @@ -602,6 +598,12 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R sWorld->UpdateGlobalPlayerGroup(guid.GetCounter(), 0); } + // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline + if (!player || player->GetSkillValue(SKILL_ENCHANTING)) + { + ResetMaxEnchantingLevel(); + } + // Pick new leader if necessary bool validLeader = true; if (m_leaderGuid == guid) @@ -1493,6 +1495,16 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap) item->is_blocked = false; } + if (Loot* loot = roll->getLoot(); loot && loot->isLooted() && loot->sourceGameObject) + { + const GameObjectTemplate* goInfo = loot->sourceGameObject->GetGOInfo(); + if (goInfo && goInfo->type == GAMEOBJECT_TYPE_CHEST) + { + // Deactivate chest if the last item was rolled in group + loot->sourceGameObject->SetLootState(GO_JUST_DEACTIVATED); + } + } + RollId.erase(rollI); delete roll; } @@ -2047,8 +2059,11 @@ void Group::ResetMaxEnchantingLevel() for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { pMember = ObjectAccessor::FindPlayer(citr->guid); - if (pMember && m_maxEnchantingLevel < pMember->GetSkillValue(SKILL_ENCHANTING)) + if (pMember && pMember->GetSession() && !pMember->GetSession()->IsSocketClosed() + && m_maxEnchantingLevel < pMember->GetSkillValue(SKILL_ENCHANTING)) + { m_maxEnchantingLevel = pMember->GetSkillValue(SKILL_ENCHANTING); + } } } diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 41b03c6a1c..5022cc61f6 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1517,7 +1517,7 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) if (pInvitee->GetSocial()->HasIgnore(player->GetGUID())) return; - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeamId() != player->GetTeamId()) + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeamId(true) != player->GetTeamId(true)) { SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_GUILD_NOT_ALLIED, name); return; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 15d70f4f23..67d9ecdc5d 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1623,8 +1623,7 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data) ObjectGuid guid; recv_data >> guid.ReadAsPacked(); - // pussywizard: typical check for incomming movement packets - if (!_player->m_mover || !_player->m_mover->IsInWorld() || _player->m_mover->IsDuringRemoveFromWorld() || guid != _player->m_mover->GetGUID()) + if (!_player) { recv_data.rfinish(); // prevent warnings spam return; @@ -1638,6 +1637,8 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data) recv_data.read_skip(); // unk2 + sScriptMgr->AnticheatSetCanFlybyServer(_player, movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY)); + _player->m_mover->m_movementInfo.flags = movementInfo.GetMovementFlags(); } diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index d30e1458b6..6c0992c2d0 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -13,6 +13,7 @@ #include "Corpse.h" #include "GameGraveyard.h" #include "InstanceSaveMgr.h" +#include "Language.h" #include "Log.h" #include "MathUtil.h" #include "MapManager.h" @@ -26,6 +27,7 @@ #include "WaypointMovementGenerator.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "Vehicle.h" #define MOVEMENT_PACKET_TIME_DELAY 0 @@ -328,8 +330,8 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) return; } - // pussywizard: typical check for incomming movement packets - if (!mover || !(mover->IsInWorld()) || mover->IsDuringRemoveFromWorld() || !(mover->movespline->Finalized())) + // pussywizard: typical check for incomming movement packets | prevent tampered movement data + if (!mover || !(mover->IsInWorld()) || mover->IsDuringRemoveFromWorld() || guid != mover->GetGUID()) { recvData.rfinish(); // prevent warnings spam return; @@ -341,30 +343,69 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) if (!movementInfo.pos.IsPositionValid()) { + if (plrMover) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(plrMover, true); + sScriptMgr->AnticheatUpdateMovementInfo(plrMover, movementInfo); + } + recvData.rfinish(); // prevent warnings spam return; } - recvData.rfinish(); // prevent warnings spam - - if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) + if (!mover->movespline->Finalized()) { - // T_POS ON VEHICLES! - if (mover->GetVehicle()) - movementInfo.transport.pos = mover->m_movementInfo.transport.pos; + recvData.rfinish(); // prevent warnings spam + return; + } - // transports size limited - // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) - if (movementInfo.transport.pos.GetPositionX() > 75.0f || movementInfo.transport.pos.GetPositionY() > 75.0f || movementInfo.transport.pos.GetPositionZ() > 75.0f || - movementInfo.transport.pos.GetPositionX() < -75.0f || movementInfo.transport.pos.GetPositionY() < -75.0f || movementInfo.transport.pos.GetPositionZ() < -75.0f) + // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE + if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) + { + // Xinef: skip moving packets + if (movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_MOVING)) { - recvData.rfinish(); // prevent warnings spam + if (plrMover) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(plrMover, true); + sScriptMgr->AnticheatUpdateMovementInfo(plrMover, movementInfo); + } + return; + } + movementInfo.pos.Relocate(mover->GetPositionX(), mover->GetPositionY(), mover->GetPositionZ()); + + if (mover->GetTypeId() == TYPEID_UNIT) + { + movementInfo.transport.guid = mover->m_movementInfo.transport.guid; + movementInfo.transport.pos.Relocate(mover->m_movementInfo.transport.pos.GetPositionX(), mover->m_movementInfo.transport.pos.GetPositionY(), mover->m_movementInfo.transport.pos.GetPositionZ()); + movementInfo.transport.seat = mover->m_movementInfo.transport.seat; + } + } + + if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) + { + // We were teleported, skip packets that were broadcast before teleport + if (movementInfo.pos.GetExactDist2d(mover) > SIZE_OF_GRIDS) + { + if (plrMover) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(plrMover, true); + sScriptMgr->AnticheatUpdateMovementInfo(plrMover, movementInfo); + //TC_LOG_INFO("anticheat", "MovementHandler:: 2 We were teleported, skip packets that were broadcast before teleport"); + } + recvData.rfinish(); // prevent warnings spam return; } if (!acore::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { + if (plrMover) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(plrMover, true); + sScriptMgr->AnticheatUpdateMovementInfo(plrMover, movementInfo); + } + recvData.rfinish(); // prevent warnings spam return; } @@ -382,6 +423,8 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { + sScriptMgr->AnticheatSetSkipOnePacketForASH(plrMover, true); + bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) @@ -400,42 +443,66 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) } if (!mover->GetTransport() && !mover->GetVehicle()) - movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; + { + GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); + if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) + { + movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + } + } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { + sScriptMgr->AnticheatSetUnderACKmount(plrMover); // just for safe + plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = nullptr; movementInfo.transport.Reset(); } + // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). + if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight()) + { + plrMover->HandleFall(movementInfo); + + sScriptMgr->AnticheatSetJumpingbyOpcode(plrMover, false); + } + + // interrupt parachutes upon falling or landing in water + if (opcode == MSG_MOVE_FALL_LAND || opcode == MSG_MOVE_START_SWIM) + { + mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // Parachutes + + if (plrMover) + { + sScriptMgr->AnticheatSetJumpingbyOpcode(plrMover, false); + } + } + if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } - if (plrMover)//Hook for OnPlayerMove - sScriptMgr->OnPlayerMove(plrMover, movementInfo, opcode); - // Dont allow to turn on walking if charming other player - if (mover->GetGUID() != _player->GetGUID()) - movementInfo.flags &= ~MOVEMENTFLAG_WALKING; - // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE - if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) + bool jumpopcode = false; + if (opcode == MSG_MOVE_JUMP) { - // Xinef: skip moving packets - if (movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_MOVING)) - return; - movementInfo.pos.Relocate(mover->GetPositionX(), mover->GetPositionY(), mover->GetPositionZ()); - - if (mover->GetTypeId() == TYPEID_UNIT) + jumpopcode = true; + if (plrMover && !sScriptMgr->AnticheatHandleDoubleJump(plrMover, mover)) { - movementInfo.transport.guid = mover->m_movementInfo.transport.guid; - movementInfo.transport.pos.Relocate(mover->m_movementInfo.transport.pos.GetPositionX(), mover->m_movementInfo.transport.pos.GetPositionY(), mover->m_movementInfo.transport.pos.GetPositionZ()); - movementInfo.transport.seat = mover->m_movementInfo.transport.seat; + plrMover->GetSession()->KickPlayer(); + return; } } + /* start some hack detection */ + if (plrMover && !sScriptMgr->AnticheatCheckMovementInfo(plrMover, movementInfo, mover, jumpopcode)) + { + plrMover->GetSession()->KickPlayer(); + return; + } + /* process position-change */ WorldPacket data(opcode, recvData.size()); int64 movementTime = (int64)movementInfo.time + _timeSyncClockDelta; @@ -455,32 +522,22 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) mover->m_movementInfo = movementInfo; - // this is almost never true (pussywizard: only one packet when entering vehicle), normally use mover->IsVehicle() - if (mover->GetVehicle()) + // Some vehicles allow the passenger to turn by himself + if (Vehicle* vehicle = mover->GetVehicle()) { - mover->SetOrientation(movementInfo.pos.GetOrientation()); - mover->UpdatePosition(movementInfo.pos); + if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(mover)) + { + if (seat->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING && movementInfo.pos.GetOrientation() != mover->GetOrientation()) + { + mover->SetOrientation(movementInfo.pos.GetOrientation()); + mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + } + } + return; } - // pussywizard: previously always mover->UpdatePosition(movementInfo.pos); - if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT && mover->GetTransport()) - { - float x, y, z, o; - movementInfo.transport.pos.GetPosition(x, y, z, o); - mover->GetTransport()->CalculatePassengerPosition(x, y, z, &o); - mover->UpdatePosition(x, y, z, o); - } - else - mover->UpdatePosition(movementInfo.pos); - - // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). - // Xinef: moved it here, previously StopMoving function called when player died relocated him to last saved coordinates (which were in air) - if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight() && (!plrMover->GetTransport() || plrMover->GetTransport()->IsStaticTransport())) - plrMover->HandleFall(movementInfo); - // Xinef: interrupt parachutes upon falling or landing in water - if (opcode == MSG_MOVE_FALL_LAND || opcode == MSG_MOVE_START_SWIM) - mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // Parachutes + mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { @@ -597,6 +654,8 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket& recvData) return; } + sScriptMgr->AnticheatSetUnderACKmount(_player); + // skip all forced speed changes except last and unexpected // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. if (_player->m_forced_speed_changes[force_move_type] > 0) diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 2368a21fce..1ec4644d49 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -7,6 +7,7 @@ #include "Chat.h" #include "Common.h" #include "CreatureAI.h" +#include "DisableMgr.h" #include "Group.h" #include "Log.h" #include "ObjectAccessor.h" @@ -559,7 +560,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint16 spe return; // Not let attack through obstructions - bool checkLos = !MMAP::MMapFactory::IsPathfindingEnabled(pet->GetMap()) || + bool checkLos = !DisableMgr::IsPathfindingEnabled(pet->GetMap()) || (TargetUnit->GetTypeId() == TYPEID_UNIT && (TargetUnit->ToCreature()->isWorldBoss() || TargetUnit->ToCreature()->IsDungeonBoss())); if (checkLos && !pet->IsWithinLOSInMap(TargetUnit)) diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index 73fdfc18b1..1e7e3031ba 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -10,6 +10,7 @@ #include "ObjectMgr.h" #include "Opcodes.h" #include "Player.h" +#include "ScriptMgr.h" #include "UpdateMask.h" #include "WaypointMovementGenerator.h" #include "WorldPacket.h" @@ -131,6 +132,8 @@ void WorldSession::SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathN GetPlayer()->Mount(mountDisplayId); GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path, pathNode); + + sScriptMgr->AnticheatSetSkipOnePacketForASH(GetPlayer(), true); } bool WorldSession::SendLearnNewTaxiNode(Creature* unit) diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index f55ca83e81..8f98c6b627 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -111,6 +111,7 @@ enum LootSlotType class Player; class LootStore; class ConditionMgr; +class GameObject; struct Loot; struct LootStoreItem @@ -313,6 +314,7 @@ struct Loot // GUID of container that holds this loot (item_instance.entry), set for items that can be looted ObjectGuid containerGUID; + GameObject* sourceGameObject{nullptr}; Loot(uint32 _gold = 0) : gold(_gold) { } ~Loot() { clear(); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 9797fbff68..641f18e2df 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -7,6 +7,7 @@ #include "Battleground.h" #include "CellImpl.h" #include "Chat.h" +#include "DisableMgr.h" #include "DynamicTree.h" #include "Geometry.h" #include "GridNotifiers.h" @@ -24,6 +25,7 @@ #include "Transport.h" #include "Vehicle.h" #include "VMapFactory.h" +#include "VMapManager2.h" #ifdef ELUNA #include "LuaEngine.h" @@ -111,7 +113,7 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy) void Map::LoadMMap(int gx, int gy) { - if (!MMAP::MMapFactory::IsPathfindingEnabled(this)) // pussywizard + if (!DisableMgr::IsPathfindingEnabled(this)) // pussywizard return; int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap(GetId(), gx, gy); @@ -138,7 +140,7 @@ void Map::LoadMMap(int gx, int gy) void Map::LoadVMap(int gx, int gy) { // x and y are swapped !! - int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), GetId(), gx, gy); + int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), GetId(), gx, gy); switch (vmapLoadResult) { case VMAP::VMAP_LOAD_RESULT_OK: @@ -3721,23 +3723,23 @@ bool Map::CheckCollisionAndGetValidCoords(const WorldObject* source, float start bool isWaterNext = IsInWater(destX, destY, destZ); - PathGenerator* path = new PathGenerator(source); + PathGenerator path(source); // Use a detour raycast to get our first collision point - path->SetUseRaycast(true); - bool result = path->CalculatePath(startX, startY, startZ, destX, destY, destZ, false); + path.SetUseRaycast(true); + bool result = path.CalculatePath(startX, startY, startZ, destX, destY, destZ, false); const Unit* unit = source->ToUnit(); - bool notOnGround = path->GetPathType() & PATHFIND_NOT_USING_PATH + bool notOnGround = path.GetPathType() & PATHFIND_NOT_USING_PATH || isWaterNext || (unit && unit->IsFlying()); // Check for valid path types before we proceed - if (!result || (!notOnGround && path->GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END))) + if (!result || (!notOnGround && path.GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END))) { return false; } - G3D::Vector3 endPos = path->GetPath().back(); + G3D::Vector3 endPos = path.GetPath().back(); destX = endPos.x; destY = endPos.y; destZ = endPos.z; @@ -3790,7 +3792,9 @@ bool Map::CheckCollisionAndGetValidCoords(const WorldObject* source, float start if (gridHeight > INVALID_HEIGHT) { destZ = gridHeight + unit->GetHoverHeight(); - } else { + } + else + { return false; } } diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index dd7e6d2035..faea05c80a 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1332,6 +1332,8 @@ enum AcoreStrings LANG_BG_READY_CHECK_ERROR = 30084, LANG_DEBUG_BG_CONF = 30085, - LANG_DEBUG_ARENA_CONF = 30086, + LANG_DEBUG_ARENA_CONF = 30086 + + // 30087-30095 reserved for passive anticheat }; #endif diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index b1e6b33a0f..146ef47fb2 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -364,14 +364,14 @@ void MotionMaster::MoveCircleTarget(Unit* target) return; } - Position* point = target->GetMeleeAttackPoint(_owner); - if (point == nullptr) + Position pos; + if (!target->GetMeleeAttackPoint(_owner, pos)) { return; } Movement::MoveSplineInit init(_owner); - init.MoveTo(point->m_positionX, point->m_positionY, point->m_positionZ, false); + init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false); init.SetWalk(true); init.SetFacing(target); init.Launch(); diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index 477bad32e7..cf0cb8b46b 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -4,9 +4,10 @@ * Copyright (C) 2005-2009 MaNGOS */ +#include "HomeMovementGenerator.h" #include "Creature.h" #include "CreatureAI.h" -#include "HomeMovementGenerator.h" +#include "DisableMgr.h" #include "MoveSpline.h" #include "MoveSplineInit.h" #include "WorldPacket.h" @@ -55,7 +56,7 @@ void HomeMovementGenerator::_setTargetLocation(Creature* owner) } owner->UpdateAllowedPositionZ(x, y, z); - init.MoveTo(x, y, z, MMAP::MMapFactory::IsPathfindingEnabled(owner->FindMap()), true); + init.MoveTo(x, y, z, DisableMgr::IsPathfindingEnabled(owner->FindMap()), true); init.SetWalk(false); init.Launch(); diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp index 861076455e..5e5636c593 100644 --- a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp @@ -24,7 +24,7 @@ PathGenerator::PathGenerator(WorldObject const* owner) : memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs)); uint32 mapId = _source->GetMapId(); - //if (MMAP::MMapFactory::IsPathfindingEnabled(_sourceUnit->FindMap())) + //if (DisableMgr::IsPathfindingEnabled(_sourceUnit->FindMap())) { MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager(); _navMesh = mmap->GetNavMesh(mapId); diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.h b/src/server/game/Movement/MovementGenerators/PathGenerator.h index 0386f7df3d..9f1d768a0c 100644 --- a/src/server/game/Movement/MovementGenerators/PathGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PathGenerator.h @@ -9,6 +9,7 @@ #include "DetourNavMesh.h" #include "DetourNavMeshQuery.h" +#include "MapDefines.h" #include "MMapFactory.h" #include "MMapManager.h" #include "MoveSplineInitArgs.h" diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 39ac661cd9..a106f0a428 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -13,6 +13,15 @@ #include "Spell.h" #include "Util.h" +template +RandomMovementGenerator::~RandomMovementGenerator() { } + +template<> +RandomMovementGenerator::~RandomMovementGenerator() +{ + delete _pathGenerator; +} + template<> void RandomMovementGenerator::_setRandomLocation(Creature* creature) { diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 8428ab2085..b768b48916 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -34,6 +34,7 @@ public: for (uint8 i = 0; i < RANDOM_POINTS_NUMBER; ++i) _validPointsVector[RANDOM_POINTS_NUMBER].push_back(i); } + ~RandomMovementGenerator(); void _setRandomLocation(T*); void DoInitialize(T*); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index 97f3834370..13b64ea707 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -29,7 +29,7 @@ class ChaseMovementGenerator : public MovementGeneratorMedium range = {}, std::optional angle = {}) : TargetedMovementGeneratorBase(target), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle) {} - ~ChaseMovementGenerator() {} + ~ChaseMovementGenerator() { delete i_path; } MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; } @@ -65,7 +65,7 @@ class FollowMovementGenerator : public MovementGeneratorMediumOnBeforeUpdate(player, p_time); } +void ScriptMgr::OnPlayerUpdate(Player* player, uint32 p_time) +{ + FOREACH_SCRIPT(PlayerScript)->OnUpdate(player, p_time); +} + void ScriptMgr::OnPlayerLogin(Player* player) { #ifdef ELUNA @@ -2632,6 +2637,58 @@ void ScriptMgr::OnSetServerSideVisibilityDetect(Player* player, ServerSideVisibi FOREACH_SCRIPT(PlayerScript)->OnSetServerSideVisibilityDetect(player, type, sec); } +void ScriptMgr::AnticheatSetSkipOnePacketForASH(Player* player, bool apply) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatSetSkipOnePacketForASH(player, apply); +} + +void ScriptMgr::AnticheatSetCanFlybyServer(Player* player, bool apply) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatSetCanFlybyServer(player, apply); +} + +void ScriptMgr::AnticheatSetUnderACKmount(Player* player) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatSetUnderACKmount(player); +} + +void ScriptMgr::AnticheatSetRootACKUpd(Player* player) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatSetRootACKUpd(player); +} + +void ScriptMgr::AnticheatSetJumpingbyOpcode(Player* player, bool jump) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatSetJumpingbyOpcode(player, jump); +} + +void ScriptMgr::AnticheatUpdateMovementInfo(Player* player, MovementInfo const& movementInfo) +{ + FOREACH_SCRIPT(PlayerScript)->AnticheatUpdateMovementInfo(player, movementInfo); +} + +bool ScriptMgr::AnticheatHandleDoubleJump(Player* player, Unit* mover) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->AnticheatHandleDoubleJump(player, mover)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + +bool ScriptMgr::AnticheatCheckMovementInfo(Player* player, MovementInfo const& movementInfo, Unit* mover, bool jump) +{ + bool ret = true; + + FOR_SCRIPTS_RET(PlayerScript, itr, end, ret) // return true by default if not scripts + if (!itr->second->AnticheatCheckMovementInfo(player, movementInfo, mover, jump)) + ret = false; // we change ret value only when scripts return true + + return ret; +} + bool ScriptMgr::CanGuildSendBankList(Guild const* guild, WorldSession* session, uint8 tabId, bool sendAllSlots) { bool ret = true; diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index bc4b1391b6..598b68c4f5 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -732,6 +732,7 @@ public: // Called for player::update virtual void OnBeforeUpdate(Player* /*player*/, uint32 /*p_time*/) { } + virtual void OnUpdate(Player* /*player*/, uint32 /*p_time*/) { } // Called when a player's money is modified (before the modification is done) virtual void OnMoneyChanged(Player* /*player*/, int32& /*amount*/) { } @@ -1014,6 +1015,16 @@ public: virtual void OnSetServerSideVisibility(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { } virtual void OnSetServerSideVisibilityDetect(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { } + + // Passive Anticheat System + virtual void AnticheatSetSkipOnePacketForASH(Player* /*player*/, bool /*apply*/) { } + virtual void AnticheatSetCanFlybyServer(Player* /*player*/, bool /*apply*/) { } + virtual void AnticheatSetUnderACKmount(Player* /*player*/) { } + virtual void AnticheatSetRootACKUpd(Player* /*player*/) { } + virtual void AnticheatSetJumpingbyOpcode(Player* /*player*/, bool /*jump*/) { } + virtual void AnticheatUpdateMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/) { } + [[nodiscard]] virtual bool AnticheatHandleDoubleJump(Player* /*player*/, Unit* /*mover*/) { return true; } + [[nodiscard]] virtual bool AnticheatCheckMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/, Unit* /*mover*/, bool /*jump*/) { return true; } }; class AccountScript : public ScriptObject @@ -1542,6 +1553,7 @@ public: /* AchievementCriteriaScript */ public: /* PlayerScript */ void OnBeforePlayerUpdate(Player* player, uint32 p_time); + void OnPlayerUpdate(Player* player, uint32 p_time); void OnSendInitialPacketsBeforeAddToMap(Player* player, WorldPacket& data); void OnPlayerReleasedGhost(Player* player); void OnPVPKill(Player* killer, Player* killed); @@ -1667,6 +1679,14 @@ public: /* PlayerScript */ bool CanInitTrade(Player* player, Player* target); void OnSetServerSideVisibility(Player* player, ServerSideVisibilityType& type, AccountTypes& sec); void OnSetServerSideVisibilityDetect(Player* player, ServerSideVisibilityType& type, AccountTypes& sec); + void AnticheatSetSkipOnePacketForASH(Player* player, bool apply); + void AnticheatSetCanFlybyServer(Player* player, bool apply); + void AnticheatSetUnderACKmount(Player* player); + void AnticheatSetRootACKUpd(Player* player); + void AnticheatUpdateMovementInfo(Player* player, MovementInfo const& movementInfo); + void AnticheatSetJumpingbyOpcode(Player* player, bool jump); + bool AnticheatHandleDoubleJump(Player* player, Unit* mover); + bool AnticheatCheckMovementInfo(Player* player, MovementInfo const& movementInfo, Unit* mover, bool jump); public: /* AccountScript */ void OnAccountLogin(uint32 accountId); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 2b9460005b..3e715fc0fa 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -450,6 +450,10 @@ bool WorldSession::HandleSocketClosed() return false; } +bool WorldSession::IsSocketClosed() const { + return !m_Socket || m_Socket->IsClosed(); +} + void WorldSession::HandleTeleportTimeout(bool updateInSessions) { // pussywizard: handle teleport ack timeout diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 45da8c8e38..3b2eee0ecb 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -926,6 +926,7 @@ public: // opcodes handlers void SetKicked(bool val) { _kicked = val; } void SetShouldSetOfflineInDB(bool val) { _shouldSetOfflineInDB = val; } bool GetShouldSetOfflineInDB() const { return _shouldSetOfflineInDB; } + bool IsSocketClosed() const; /*** CALLBACKS diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 780296a130..157e7967ca 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2339,7 +2339,7 @@ void AuraEffect::HandleAuraModScale(AuraApplication const* aurApp, uint8 mode, b Unit* target = aurApp->GetTarget(); - float scale = target->GetFloatValue(OBJECT_FIELD_SCALE_X); + float scale = target->GetObjectScale(); ApplyPercentModFloatVar(scale, float(GetAmount()), apply); target->SetObjectScale(scale); } @@ -2359,7 +2359,6 @@ void AuraEffect::HandleAuraCloneCaster(AuraApplication const* aurApp, uint8 mode // What must be cloned? at least display and scale target->SetDisplayId(caster->GetDisplayId()); - //target->SetObjectScale(caster->GetFloatValue(OBJECT_FIELD_SCALE_X)); // we need retail info about how scaling is handled (aura maybe?) target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); } else @@ -2383,6 +2382,11 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo if (target->GetTypeId() != TYPEID_PLAYER) return; + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } + if (apply) { /* @@ -2875,6 +2879,11 @@ void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, Unit* target = aurApp->GetTarget(); + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } + if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit @@ -2892,6 +2901,11 @@ void AuraEffect::HandleAuraFeatherFall(AuraApplication const* aurApp, uint8 mode Unit* target = aurApp->GetTarget(); + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } + if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit @@ -2913,6 +2927,11 @@ void AuraEffect::HandleAuraHover(AuraApplication const* aurApp, uint8 mode, bool Unit* target = aurApp->GetTarget(); + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } + if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit @@ -3227,6 +3246,11 @@ void AuraEffect::HandleAuraModIncreaseSpeed(AuraApplication const* aurApp, uint8 Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_RUN, true); + + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } } void AuraEffect::HandleAuraModIncreaseMountedSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3267,6 +3291,11 @@ void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 16314); } } + + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } } void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -3277,6 +3306,11 @@ void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, u Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_SWIM, true); + + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } } void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -3292,6 +3326,11 @@ void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 target->UpdateSpeed(MOVE_RUN_BACK, true); target->UpdateSpeed(MOVE_SWIM_BACK, true); target->UpdateSpeed(MOVE_FLIGHT_BACK, true); + + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } } void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const @@ -3304,6 +3343,11 @@ void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint target->UpdateSpeed(MOVE_RUN, true); target->UpdateSpeed(MOVE_SWIM, true); target->UpdateSpeed(MOVE_FLIGHT, true); + + if (Player* targetPlayer = target->ToPlayer()) + { + sScriptMgr->AnticheatSetUnderACKmount(targetPlayer); + } } /*********************************************************/ diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index feda1c46e7..f779cbec38 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5678,7 +5678,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_BAD_TARGETS; // Xinef: Pass only explicit unit target spells // pussywizard: - if (MMAP::MMapFactory::IsPathfindingEnabled(m_caster->FindMap()) && m_spellInfo->NeedsExplicitUnitTarget()) + if (DisableMgr::IsPathfindingEnabled(m_caster->FindMap()) && m_spellInfo->NeedsExplicitUnitTarget()) { Unit* target = m_targets.GetUnitTarget(); if (!target) @@ -7337,12 +7337,6 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const return false; } break; - /*case SPELL_EFFECT_CHARGE: - if (MMAP::MMapFactory::IsPathfindingEnabled(m_caster->FindMap())) - break; - [[fallthrough]]; - */ - case SPELL_EFFECT_SUMMON_RAF_FRIEND: if (m_caster->GetTypeId() != TYPEID_PLAYER || target->GetTypeId() != TYPEID_PLAYER) return false; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 4da2e908a8..1eac370943 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1113,6 +1113,11 @@ void Spell::EffectJump(SpellEffIndex effIndex) float speedXY, speedZ; CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(unitTarget), speedXY, speedZ); m_caster->GetMotionMaster()->MoveJump(*unitTarget, speedXY, speedZ); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } } void Spell::EffectJumpDest(SpellEffIndex effIndex) @@ -1142,6 +1147,12 @@ void Spell::EffectJumpDest(SpellEffIndex effIndex) { speedXY = pow(speedZ * 10, 8); m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ, 0, ObjectAccessor::GetUnit(*m_caster, m_caster->GetGuidValue(UNIT_FIELD_TARGET))); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } + return; } @@ -1156,6 +1167,11 @@ void Spell::EffectJumpDest(SpellEffIndex effIndex) speedXY = 1.0f; m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } } void Spell::CalculateJumpSpeeds(uint8 i, float dist, float& speedXY, float& speedZ) @@ -1177,6 +1193,11 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/) if (!unitTarget || unitTarget->IsInFlight()) return; + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(unitTarget->ToPlayer()); + } + // Pre effects switch (m_spellInfo->Id) { @@ -5056,6 +5077,11 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) if (!unitTarget) return; + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(m_caster->ToPlayer(), true); + } + // charge changes fall time if( m_caster->GetTypeId() == TYPEID_PLAYER ) m_caster->ToPlayer()->SetFallInformation(time(nullptr), m_caster->GetPositionZ()); @@ -5063,6 +5089,13 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) if (m_pathFinder) { m_caster->GetMotionMaster()->MoveCharge(m_pathFinder->GetEndPosition().x, m_pathFinder->GetEndPosition().y, m_pathFinder->GetEndPosition().z, 42.0f, EVENT_CHARGE, &m_pathFinder->GetPath()); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } + + m_caster->AddUnitState(UNIT_STATE_CHARGING); } else { @@ -5077,6 +5110,13 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) } m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + Z_OFFSET_FIND_HEIGHT); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } + + m_caster->AddUnitState(UNIT_STATE_CHARGING); } } @@ -5085,6 +5125,13 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) if (!unitTarget) return; + m_caster->ClearUnitState(UNIT_STATE_CHARGING); + + if (m_caster->ToPlayer()) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(m_caster->ToPlayer(), true); + } + // not all charge effects used in negative spells if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->Attack(unitTarget, true); @@ -5096,6 +5143,11 @@ void Spell::EffectChargeDest(SpellEffIndex /*effIndex*/) if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH) return; + if (m_caster->ToPlayer()) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(m_caster->ToPlayer(), true); + } + if (m_targets.HasDst()) { Position pos; @@ -5109,6 +5161,11 @@ void Spell::EffectChargeDest(SpellEffIndex /*effIndex*/) } m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ); + + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } } } @@ -5162,6 +5219,11 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex) } unitTarget->KnockbackFrom(x, y, speedxy, speedz); + + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(unitTarget->ToPlayer()); + } } void Spell::EffectLeapBack(SpellEffIndex effIndex) @@ -5177,6 +5239,11 @@ void Spell::EffectLeapBack(SpellEffIndex effIndex) //1891: Disengage m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellFamilyName != SPELLFAMILY_HUNTER); + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetUnderACKmount(m_caster->ToPlayer()); + } + // xinef: changes fall time if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->SetFallInformation(time(nullptr), m_caster->GetPositionZ()); @@ -5262,6 +5329,12 @@ void Spell::EffectPullTowards(SpellEffIndex effIndex) float speedZ = unitTarget->GetDistance(pos) / speedXY * 0.5f * Movement::gravity; unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); + + if (unitTarget->GetTypeId() == TYPEID_PLAYER) + { + sScriptMgr->AnticheatSetSkipOnePacketForASH(unitTarget->ToPlayer(), true); + sScriptMgr->AnticheatSetUnderACKmount(unitTarget->ToPlayer()); + } } void Spell::EffectDispelMechanic(SpellEffIndex effIndex) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 44fb101b3b..a05c534110 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1415,8 +1415,6 @@ void World::LoadConfigSettings(bool reload) sScriptMgr->OnAfterConfigLoad(reload); } -extern void LoadGameObjectModelList(); - /// Initialize the World void World::SetInitialWorldSettings() { @@ -1433,10 +1431,9 @@ void World::SetInitialWorldSettings() sScriptMgr->Initialize(); ///- Initialize VMapManager function pointers (to untangle game/collision circular deps) - if (VMAP::VMapManager2* vmmgr2 = dynamic_cast(VMAP::VMapFactory::createOrGetVMapManager())) - { - vmmgr2->GetLiquidFlagsPtr = &GetLiquidFlags; - } + VMAP::VMapManager2* vmmgr2 = VMAP::VMapFactory::createOrGetVMapManager(); + vmmgr2->GetLiquidFlagsPtr = &GetLiquidFlags; + vmmgr2->IsVMAPDisabledForPtr = &DisableMgr::IsVMAPDisabledFor; ///- Initialize config settings LoadConfigSettings(); @@ -1498,6 +1495,15 @@ void World::SetInitialWorldSettings() LoadDBCStores(m_dataPath); DetectDBCLang(); + std::vector mapIds; + for (auto const& map : sMapStore) + mapIds.emplace_back(map->MapID); + + vmmgr2->InitializeThreadUnsafe(mapIds); + + MMAP::MMapManager* mmmgr = MMAP::MMapFactory::createOrGetMMapManager(); + mmmgr->InitializeThreadUnsafe(mapIds); + LOG_INFO("server", "Loading Game Graveyard..."); sGraveyard->LoadGraveyardFromDB(); @@ -1520,7 +1526,7 @@ void World::SetInitialWorldSettings() sSpellMgr->LoadSpellCustomAttr(); LOG_INFO("server", "Loading GameObject models..."); - LoadGameObjectModelList(); + LoadGameObjectModelList(m_dataPath); LOG_INFO("server", "Loading Script Names..."); sObjectMgr->LoadScriptNames(); diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index 24e8f2d6e4..718c924126 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -88,9 +88,15 @@ public: WorldPacket data(12); if (strncmp(args, "on", 3) == 0) + { data.SetOpcode(SMSG_MOVE_SET_CAN_FLY); + sScriptMgr->AnticheatSetCanFlybyServer(target, true); + } else if (strncmp(args, "off", 4) == 0) + { data.SetOpcode(SMSG_MOVE_UNSET_CAN_FLY); + sScriptMgr->AnticheatSetCanFlybyServer(target, false); + } else { handler->SendSysMessage(LANG_USE_BOL); diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index f04081d5e4..05b31cdd2c 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -402,12 +402,25 @@ public: oz = player->GetOrientation(); } - object->SetWorldRotationAngles(oz, oy, ox); - object->DestroyForNearbyPlayers(); - object->UpdateObjectVisibility(); + Map* map = object->GetMap(); - object->SaveToDB(); - object->Refresh(); + object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), oz); + object->SetWorldRotationAngles(oz, oy, ox); + + object->SaveToDB(true); + + // Generate a completely new spawn with new guid + // 3.3.5a client caches recently deleted objects and brings them back to life + // when CreateObject block for this guid is received again + // however it entirely skips parsing that block and only uses already known location + object->Delete(); + + object = new GameObject(); + if (!object->LoadGameObjectFromDB(guidLow, map)) + { + delete object; + return false; + } handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId(), oz, oy, ox); @@ -438,12 +451,10 @@ public: char* toY = strtok(nullptr, " "); char* toZ = strtok(nullptr, " "); + Position pos; if (!toX) { - Player* player = handler->GetSession()->GetPlayer(); - object->GetMap()->GameObjectRelocation(object, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), object->GetOrientation()); - object->DestroyForNearbyPlayers(); - object->UpdateObjectVisibility(); + pos = handler->GetSession()->GetPlayer()->GetPosition(); } else { @@ -461,13 +472,31 @@ public: return false; } - object->GetMap()->GameObjectRelocation(object, x, y, z, object->GetOrientation()); - object->DestroyForNearbyPlayers(); - object->UpdateObjectVisibility(); + pos.Relocate(x, y, z); } + Map* map = object->GetMap(); + + pos.SetOrientation(object->GetOrientation()); + object->Relocate(pos); + + // update which cell has this gameobject registered for loading + sObjectMgr->RemoveGameobjectFromGrid(guidLow, object->GetGOData()); object->SaveToDB(); - object->Refresh(); + sObjectMgr->AddGameobjectToGrid(guidLow, object->GetGOData()); + + // Generate a completely new spawn with new guid + // 3.3.5a client caches recently deleted objects and brings them back to life + // when CreateObject block for this guid is received again + // however it entirely skips parsing that block and only uses already known location + object->Delete(); + + object = new GameObject(); + if (!object->LoadGameObjectFromDB(guidLow, map)) + { + delete object; + return false; + } handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetSpawnId()); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 02dbaecafa..95f45e4632 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1541,15 +1541,19 @@ public: // Subtract if (count < 0) { - if (!playerTarget->HasItemCount(itemId, 0)) + // Only have scam check on player accounts + if (playerTarget->GetSession()->GetSecurity() == SEC_PLAYER) { - // output that player don't have any items to destroy - handler->PSendSysMessage(LANG_REMOVEITEM_FAILURE, handler->GetNameLink(playerTarget).c_str(), itemId); - } - else if (!playerTarget->HasItemCount(itemId, -count)) - { - // output that player don't have as many items that you want to destroy - handler->PSendSysMessage(LANG_REMOVEITEM_ERROR, handler->GetNameLink(playerTarget).c_str(), itemId); + if (!playerTarget->HasItemCount(itemId, 0)) + { + // output that player don't have any items to destroy + handler->PSendSysMessage(LANG_REMOVEITEM_FAILURE, handler->GetNameLink(playerTarget).c_str(), itemId); + } + else if (!playerTarget->HasItemCount(itemId, -count)) + { + // output that player don't have as many items that you want to destroy + handler->PSendSysMessage(LANG_REMOVEITEM_ERROR, handler->GetNameLink(playerTarget).c_str(), itemId); + } } else { @@ -1561,14 +1565,6 @@ public: return true; } - /* [AC] Sunwell hack - if (handler->GetSession()->GetSecurity() < SEC_ADMINISTRATOR) - { - handler->PSendSysMessage("You may only remove items. Adding items is available for higher GMLevel."); - return false; - } - */ - // Adding items uint32 noSpaceForCount = 0; diff --git a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp index 5fb5046ee7..c8c702b62d 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp @@ -6,7 +6,7 @@ #include "ScriptedCreature.h" #include "ScriptMgr.h" -enum Spels +enum Spells { SPELL_SMITE_STOMP = 6432, SPELL_SMITE_SLAM = 6435, @@ -73,10 +73,6 @@ public: events.Update(diff); switch (events.ExecuteEvent()) { - case EVENT_SMITE_SLAM: - me->CastSpell(me->GetVictim(), SPELL_SMITE_SLAM, false); - events.ScheduleEvent(EVENT_SMITE_SLAM, 15000); - break; case EVENT_CHECK_HEALTH1: if (me->HealthBelowPct(67) && !health67) { @@ -107,6 +103,15 @@ public: } events.ScheduleEvent(EVENT_CHECK_HEALTH2, 500); break; + case EVENT_SMITE_SLAM: + if (me->HealthBelowPct(33)) + { + me->CastSpell(me->GetVictim(), SPELL_SMITE_SLAM, false); + events.ScheduleEvent(EVENT_SMITE_SLAM, 6000); + break; + } + events.ScheduleEvent(EVENT_SMITE_SLAM, 500); + break; case EVENT_SWAP_WEAPON1: me->LoadEquipment(EQUIP_TWO_SWORDS); me->SetCanDualWield(true); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index cfa8da8b09..406d9b182e 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -517,10 +517,16 @@ public: pPlayer->SetUnitMovementFlags(MOVEMENTFLAG_NONE); pPlayer->SetDisableGravity(true, true); + + sScriptMgr->AnticheatSetCanFlybyServer(pPlayer, true); + WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8); data << pPlayer->GetPackGUID(); pPlayer->SendMessageToSet(&data, true); + sScriptMgr->AnticheatSetUnderACKmount(pPlayer); + sScriptMgr->AnticheatSetSkipOnePacketForASH(pPlayer, true); + pPlayer->SetGuidValue(PLAYER_FARSIGHT, vp->GetGUID()); c->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } @@ -704,6 +710,9 @@ public: for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* pPlayer = i->GetSource()) { + sScriptMgr->AnticheatSetUnderACKmount(pPlayer); + sScriptMgr->AnticheatSetSkipOnePacketForASH(pPlayer, true); + if (!pPlayer->IsAlive() || pPlayer->IsGameMaster()) continue; @@ -884,6 +893,10 @@ public: plr->RemoveAura(SPELL_FREEZE_ANIM); plr->SetDisableGravity(false, true); plr->SetGuidValue(PLAYER_FARSIGHT, ObjectGuid::Empty); + + sScriptMgr->AnticheatSetCanFlybyServer(plr, false); + sScriptMgr->AnticheatSetUnderACKmount(plr); + sScriptMgr->AnticheatSetSkipOnePacketForASH(plr, true); } } @@ -921,6 +934,10 @@ public: { bUpdatedFlying = true; plr->SetDisableGravity(true, true); + + sScriptMgr->AnticheatSetCanFlybyServer(plr, true); + sScriptMgr->AnticheatSetSkipOnePacketForASH(plr, true); + sScriptMgr->AnticheatSetUnderACKmount(plr); } plr->SendMonsterMove(me->GetPositionX() + dist * cos(arcangle), me->GetPositionY() + dist * sin(arcangle), me->GetPositionZ(), VORTEX_DEFAULT_DIFF * 2, SPLINEFLAG_FLYING); diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index d93b893e08..be31c06a2f 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -1347,6 +1347,48 @@ public: } }; +// -50334 - Berserk +class spell_dru_berserk : public SpellScriptLoader +{ +public: + spell_dru_berserk() : SpellScriptLoader("spell_dru_berserk") { } + + class spell_dru_berserk_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dru_berserk_SpellScript); + + void HandleAfterCast() + { + Unit* caster = GetCaster(); + + if (caster->GetTypeId() == TYPEID_PLAYER) + { + // Remove tiger fury / mangle(bear) + const uint32 TigerFury[6] = { 5217, 6793, 9845, 9846, 50212, 50213 }; + const uint32 DireMaul[6] = { 33878, 33986, 33987, 48563, 48564 }; + + // remove aura + for (auto& i : TigerFury) + caster->RemoveAurasDueToSpell(i); + + // reset dire bear maul cd + for (auto& i : DireMaul) + caster->ToPlayer()->RemoveSpellCooldown(i, true); + } + } + + void Register() override + { + AfterCast += SpellCastFn(spell_dru_berserk_SpellScript::HandleAfterCast); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_dru_berserk_SpellScript(); + } +}; + void AddSC_druid_spell_scripts() { // Ours @@ -1357,6 +1399,7 @@ void AddSC_druid_spell_scripts() new spell_dru_brambles_treant(); new spell_dru_barkskin(); new spell_dru_treant_scaling(); + new spell_dru_berserk(); // Theirs new spell_dru_dash(); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/shared/SharedDefines.h similarity index 99% rename from src/server/game/Miscellaneous/SharedDefines.h rename to src/server/shared/SharedDefines.h index 4f8bfea5f0..fd3bb43ed9 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -3567,42 +3567,4 @@ enum PartyResult ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30 }; -#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 11 - -struct MmapTileHeader -{ - uint32 mmapMagic{MMAP_MAGIC}; - uint32 dtVersion; - uint32 mmapVersion{MMAP_VERSION}; - uint32 size{0}; - char usesLiquids{true}; - char padding[3]{}; - - MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) { } -}; - -// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files -static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size"); -static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) + - sizeof(MmapTileHeader::dtVersion) + - sizeof(MmapTileHeader::mmapVersion) + - sizeof(MmapTileHeader::size) + - sizeof(MmapTileHeader::usesLiquids) + - sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields"); - -enum NavTerrain -{ - NAV_EMPTY = 0x00, - NAV_GROUND = 0x01, - NAV_MAGMA = 0x02, - NAV_SLIME = 0x04, - NAV_WATER = 0x08, - NAV_UNUSED1 = 0x10, - NAV_UNUSED2 = 0x20, - NAV_UNUSED3 = 0x40, - NAV_UNUSED4 = 0x80 - // we only have 8 bits -}; - #endif diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h index 872a37f6d8..c1dd825473 100644 --- a/src/tools/mesh_extractor/Utils.h +++ b/src/tools/mesh_extractor/Utils.h @@ -6,6 +6,7 @@ #ifndef UTILS_H #define UTILS_H + #include #include #include @@ -337,9 +338,6 @@ public: virtual float Scale() const { return 1.0f; }; }; -#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 10 - struct MmapTileHeader { uint32 mmapMagic; diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 866b63c968..20a325b4c8 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -5,45 +5,14 @@ */ #include "MapBuilder.h" +#include "MapDefines.h" #include "MapTree.h" #include "ModelInstance.h" #include "PathCommon.h" - #include #include #include -#include "DisableMgr.h" - -namespace DisableMgr -{ - bool IsDisabledFor(DisableType /*type*/, uint32 /*entry*/, Unit const* /*unit*/, uint8 /*flags*/ /*= 0*/) { return false; } -} - -#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 11 - -struct MmapTileHeader -{ - uint32 mmapMagic{MMAP_MAGIC}; - uint32 dtVersion; - uint32 mmapVersion{MMAP_VERSION}; - uint32 size{0}; - char usesLiquids{true}; - char padding[3]{}; - - MmapTileHeader() : dtVersion(DT_NAVMESH_VERSION) {} -}; - -// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files -static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size"); -static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) + - sizeof(MmapTileHeader::dtVersion) + - sizeof(MmapTileHeader::mmapVersion) + - sizeof(MmapTileHeader::size) + - sizeof(MmapTileHeader::usesLiquids) + - sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields"); - namespace MMAP { MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid, diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h index 7aae074488..c196cf4ce6 100644 --- a/src/tools/mmaps_generator/PathCommon.h +++ b/src/tools/mmaps_generator/PathCommon.h @@ -20,20 +20,6 @@ #include #endif -enum NavTerrain -{ - NAV_EMPTY = 0x00, - NAV_GROUND = 0x01, - NAV_MAGMA = 0x02, - NAV_SLIME = 0x04, - NAV_WATER = 0x08, - NAV_UNUSED1 = 0x10, - NAV_UNUSED2 = 0x20, - NAV_UNUSED3 = 0x40, - NAV_UNUSED4 = 0x80 - // we only have 8 bits -}; - namespace MMAP { inline bool matchWildcardFilter(const char* filter, const char* str) diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 3c56e49c39..aaf33f675e 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -5,10 +5,9 @@ */ #include "TerrainBuilder.h" - #include "PathCommon.h" #include "MapBuilder.h" - +#include "MapDefines.h" #include "VMapManager2.h" #include "MapTree.h" #include "ModelInstance.h" diff --git a/src/tools/mmaps_generator/VMapExtensions.cpp b/src/tools/mmaps_generator/VMapExtensions.cpp deleted file mode 100644 index 29970ae15c..0000000000 --- a/src/tools/mmaps_generator/VMapExtensions.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2 - * Copyright (C) 2008-2016 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - */ - -#include -#include "MapTree.h" -#include "VMapManager2.h" -#include "WorldModel.h" -#include "ModelInstance.h" - -namespace VMAP -{ - // Need direct access to encapsulated VMAP data, so we add functions for MMAP generator - // maybe add MapBuilder as friend to all of the below classes would be better? - - // declared in src/common/vmap/MapTree.h - void StaticMapTree::getModelInstances(ModelInstance*& models, uint32& count) - { - models = iTreeValues; - count = iNTreeValues; - } - - // declared in src/common/vmap/VMapManager2.h - void VMapManager2::getInstanceMapTree(InstanceTreeMap& instanceMapTree) - { - instanceMapTree = iInstanceMapTrees; - } - - // declared in src/common/vmap/WorldModel.h - void WorldModel::getGroupModels(std::vector& groupModels) - { - groupModels = this->groupModels; - } - - // declared in src/common/vmap/WorldModel.h - void GroupModel::getMeshData(std::vector& vertices, std::vector& triangles, WmoLiquid*& liquid) - { - vertices = this->vertices; - triangles = this->triangles; - liquid = iLiquid; - } - - // declared in src/common/vmap/ModelInstance.h - WorldModel* ModelInstance::getWorldModel() - { - return iModel; - } - - // declared in src/common/vmap/WorldModel.h - void WmoLiquid::getPosInfo(uint32& tilesX, uint32& tilesY, G3D::Vector3& corner) const - { - tilesX = iTilesX; - tilesY = iTilesY; - corner = iCorner; - } -} diff --git a/var/ccache/.gitkeep b/var/ccache/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/docker/build/.gitkeep b/var/docker/build/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/docker/ccache/.gitkeep b/var/docker/ccache/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/extractors/dbc/.gitkeep b/var/extractors/dbc/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/extractors/maps/.gitkeep b/var/extractors/maps/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/extractors/mmaps/.gitkeep b/var/extractors/mmaps/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/var/extractors/vmaps/.gitkeep b/var/extractors/vmaps/.gitkeep new file mode 100644 index 0000000000..e69de29bb2