/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ /** * @file cs_mmaps.cpp * @brief .mmap related commands * * This file contains the CommandScripts for all * mmap sub-commands */ #include "ScriptMgr.h" #include "CellImpl.h" #include "Chat.h" #include "ChatCommand.h" #include "DisableMgr.h" #include "GridNotifiersImpl.h" #include "MMapFactory.h" #include "PathGenerator.h" #include "PhasingHandler.h" #include "Player.h" #include "PointMovementGenerator.h" #include "RBAC.h" #include "WorldSession.h" #if TRINITY_COMPILER == TRINITY_COMPILER_GNU #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif class mmaps_commandscript : public CommandScript { public: mmaps_commandscript() : CommandScript("mmaps_commandscript") { } std::vector GetCommands() const override { static std::vector mmapCommandTable = { { "loadedtiles", rbac::RBAC_PERM_COMMAND_MMAP_LOADEDTILES, false, &HandleMmapLoadedTilesCommand, "" }, { "loc", rbac::RBAC_PERM_COMMAND_MMAP_LOC, false, &HandleMmapLocCommand, "" }, { "path", rbac::RBAC_PERM_COMMAND_MMAP_PATH, false, &HandleMmapPathCommand, "" }, { "stats", rbac::RBAC_PERM_COMMAND_MMAP_STATS, false, &HandleMmapStatsCommand, "" }, { "testarea", rbac::RBAC_PERM_COMMAND_MMAP_TESTAREA, false, &HandleMmapTestArea, "" }, }; static std::vector commandTable = { { "mmap", rbac::RBAC_PERM_COMMAND_MMAP, true, nullptr, "", mmapCommandTable }, }; return commandTable; } static bool HandleMmapPathCommand(ChatHandler* handler, char const* args) { if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } handler->PSendSysMessage("mmap path:"); // units Player* player = handler->GetSession()->GetPlayer(); Unit* target = handler->getSelectedUnit(); if (!player || !target) { handler->PSendSysMessage("Invalid target/source selection."); return true; } char* para = strtok((char*)args, " "); bool useStraightPath = false; if (para && strcmp(para, "true") == 0) useStraightPath = true; bool useRaycast = false; if (para && (strcmp(para, "line") == 0 || strcmp(para, "ray") == 0 || strcmp(para, "raycast") == 0)) useRaycast = true; // unit locations float x, y, z; player->GetPosition(x, y, z); // path PathGenerator path(target); path.SetUseStraightPath(useStraightPath); path.SetUseRaycast(useRaycast); bool result = path.CalculatePath(x, y, z, false); Movement::PointsArray const& pointPath = path.GetPath(); handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str()); handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useRaycast ? "Raycast" : "SmoothPath"); handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType()); G3D::Vector3 const& start = path.GetStartPosition(); G3D::Vector3 const& end = path.GetEndPosition(); G3D::Vector3 const& actualEnd = path.GetActualEndPosition(); handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z); handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z); handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z); if (!player->IsGameMaster()) handler->PSendSysMessage("Enable GM mode to see the path points."); for (uint32 i = 0; i < pointPath.size(); ++i) player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9s); return true; } static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/) { handler->PSendSysMessage("mmap tileloc:"); // grid tile location Player* player = handler->GetSession()->GetPlayer(); int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS; int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS; float x, y, z; player->GetPosition(x, y, z); handler->PSendSysMessage("%04u%02i%02i.mmtile", player->GetMapId(), gx, gy); handler->PSendSysMessage("tileloc [%i, %i]", gy, gx); // calculate navmesh tile location uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMapId(), player->GetMap()->GetTerrain(), x, y); dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(terrainMapId); dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(terrainMapId, player->GetMapId(), player->GetInstanceId()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } float const* min = navmesh->getParams()->orig; float location[VERTEX_SIZE] = { y, z, x }; float extents[VERTEX_SIZE] = { 3.0f, 5.0f, 3.0f }; int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS); int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS); handler->PSendSysMessage("Calc [%02i, %02i]", tilex, tiley); // navmesh poly -> navmesh tile location dtQueryFilter filter = dtQueryFilter(); dtPolyRef polyRef = INVALID_POLYREF; if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, nullptr))) { handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); return true; } if (polyRef == INVALID_POLYREF) handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)"); else { dtMeshTile const* tile; dtPoly const* poly; if (dtStatusSucceed(navmesh->getTileAndPolyByRef(polyRef, &tile, &poly))) { if (tile) { handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); return true; } } handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); } return true; } static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/) { Player* player = handler->GetSession()->GetPlayer(); uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMapId(), player->GetMap()->GetTerrain(), player->GetPositionX(), player->GetPositionY()); dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(terrainMapId); dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(terrainMapId, player->GetMapId(), player->GetInstanceId()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } handler->PSendSysMessage("mmap loadedtiles:"); for (int32 i = 0; i < navmesh->getMaxTiles(); ++i) { dtMeshTile const* tile = navmesh->getTile(i); if (!tile || !tile->header) continue; handler->PSendSysMessage("[%02i, %02i]", tile->header->x, tile->header->y); } return true; } static bool HandleMmapStatsCommand(ChatHandler* handler, char const* /*args*/) { Player* player = handler->GetSession()->GetPlayer(); uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMapId(), player->GetMap()->GetTerrain(), player->GetPositionX(), player->GetPositionY()); handler->PSendSysMessage("mmap stats:"); handler->PSendSysMessage(" global mmap pathfinding is %sabled", DisableMgr::IsPathfindingEnabled(player->GetMapId()) ? "en" : "dis"); MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager(); handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); dtNavMesh const* navmesh = manager->GetNavMesh(terrainMapId); if (!navmesh) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } uint32 tileCount = 0; uint32 nodeCount = 0; uint32 polyCount = 0; uint32 vertCount = 0; uint32 triCount = 0; uint32 triVertCount = 0; uint32 dataSize = 0; for (int32 i = 0; i < navmesh->getMaxTiles(); ++i) { dtMeshTile const* tile = navmesh->getTile(i); if (!tile || !tile->header) continue; tileCount++; nodeCount += tile->header->bvNodeCount; polyCount += tile->header->polyCount; vertCount += tile->header->vertCount; triCount += tile->header->detailTriCount; triVertCount += tile->header->detailVertCount; dataSize += tile->dataSize; } handler->PSendSysMessage("Navmesh stats:"); handler->PSendSysMessage(" %u tiles loaded", tileCount); handler->PSendSysMessage(" %u BVTree nodes", nodeCount); handler->PSendSysMessage(" %u polygons (%u vertices)", polyCount, vertCount); handler->PSendSysMessage(" %u triangles (%u vertices)", triCount, triVertCount); handler->PSendSysMessage(" %.2f MB of data (not including pointers)", ((float)dataSize / sizeof(unsigned char)) / 1048576); return true; } static bool HandleMmapTestArea(ChatHandler* handler, char const* /*args*/) { float radius = 40.0f; WorldObject* object = handler->GetSession()->GetPlayer(); // Get Creatures std::list creatureList; Trinity::AnyUnitInObjectRangeCheck go_check(object, radius); Trinity::CreatureListSearcher go_search(object, creatureList, go_check); Cell::VisitGridObjects(object, go_search, radius); if (!creatureList.empty()) { handler->PSendSysMessage("Found %zu Creatures.", creatureList.size()); uint32 paths = 0; uint32 uStartTime = getMSTime(); float gx, gy, gz; object->GetPosition(gx, gy, gz); for (std::list::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) { PathGenerator path(*itr); path.CalculatePath(gx, gy, gz); ++paths; } uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime()); handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime); } else handler->PSendSysMessage("No creatures in %f yard range.", radius); return true; } }; void AddSC_mmaps_commandscript() { new mmaps_commandscript(); }