From 8710a6c6b6d4edee24b23a74741cb3bd6346623b Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sat, 2 Nov 2024 13:00:06 -0500 Subject: [PATCH] Add github issue and pull request templates (#132) * Add issue and pull request templates * fix build --- cmake/genrev.cmake | 111 +++++++++++---- cmake/macros/FindGit.cmake | 38 ----- cmake/options.cmake | 2 +- cmake/showoptions.cmake | 15 ++ issue_template.md | 45 ++++++ pull_request_template.md | 29 ++++ revision_data.h.in.cmake | 12 +- src/common/GitRevision.cpp | 10 ++ src/common/GitRevision.h | 2 + src/server/game/DataStores/DB2Stores.cpp | 4 +- src/server/game/DataStores/DB2Stores.h | 2 +- src/server/game/Maps/TransportMgr.h | 2 +- src/server/game/World/World.cpp | 3 +- src/server/game/World/World.h | 3 + src/server/scripts/Commands/cs_server.cpp | 162 ++++++++++++++++++++-- 15 files changed, 350 insertions(+), 90 deletions(-) delete mode 100644 cmake/macros/FindGit.cmake create mode 100644 issue_template.md create mode 100644 pull_request_template.md diff --git a/cmake/genrev.cmake b/cmake/genrev.cmake index dd11c56c..1fbccc32 100644 --- a/cmake/genrev.cmake +++ b/cmake/genrev.cmake @@ -20,39 +20,86 @@ if(WITHOUT_GIT) set(rev_date "1970-01-01 00:00:00 +0000") set(rev_hash "unknown") set(rev_branch "Archived") + # No valid git commit date, use today + string(TIMESTAMP rev_date_fallback "%Y-%m-%d %H:%M:%S" UTC) else() if(GIT_EXECUTABLE) # Create a revision-string that we can use execute_process( - COMMAND "${GIT_EXECUTABLE}" describe --long --match init --dirty=+ --abbrev=12 + COMMAND "${GIT_EXECUTABLE}" rev-parse --short=12 HEAD WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - OUTPUT_VARIABLE rev_info + OUTPUT_VARIABLE rev_hash OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) - # And grab the commits timestamp - execute_process( - COMMAND "${GIT_EXECUTABLE}" show -s --format=%ci - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - OUTPUT_VARIABLE rev_date - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) + if(rev_hash) + # Retrieve repository dirty status + execute_process( + COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD -- + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE is_dirty + ERROR_QUIET + ) - # Also retrieve branch name - execute_process( - COMMAND "${GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - OUTPUT_VARIABLE rev_branch - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_QUIET - ) + # Append dirty marker to commit hash + if(is_dirty) + set(rev_hash "${rev_hash}+") + endif() + + # And grab the commits timestamp + execute_process( + COMMAND "${GIT_EXECUTABLE}" show -s --format=%ci + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE rev_date + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + # Also retrieve branch name + execute_process( + COMMAND "${GIT_EXECUTABLE}" symbolic-ref -q --short HEAD + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE rev_branch + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + + # when ran on CI, repository is put in detached HEAD state, attempt to scan for known local branches + if(NOT rev_branch) + execute_process( + COMMAND "${GIT_EXECUTABLE}" for-each-ref --points-at=HEAD refs/heads "--format=%(refname:short)" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE rev_branch + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + # if local branch scan didn't find anything, try remote branches + if(NOT rev_branch) + execute_process( + COMMAND "${GIT_EXECUTABLE}" for-each-ref --points-at=HEAD refs/remotes "--format=%(refname:short)" + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE rev_branch + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + # give up finding a name for branch, use commit hash + if(NOT rev_branch) + set(rev_branch ${rev_hash}) + endif() + + # normalize branch to single line (for-each-ref can output multiple lines if there are multiple branches on the same commit) + string(REGEX MATCH "^[^ \t\r\n]+" rev_branch ${rev_branch}) + endif() endif() # Last minute check - ensure that we have a proper revision # If everything above fails (means the user has erased the git revision control directory or removed the origin/HEAD tag) - if(NOT rev_info) + if(NOT rev_hash) # No valid ways available to find/set the revision/hash, so let's force some defaults message(STATUS " Could not find a proper repository signature (hash) - you may need to pull tags with git fetch -t @@ -60,19 +107,23 @@ else() set(rev_date "1970-01-01 00:00:00 +0000") set(rev_hash "unknown") set(rev_branch "Archived") + # No valid git commit date, use today + string(TIMESTAMP rev_date_fallback "%Y-%m-%d %H:%M:%S" UTC) else() - # Extract information required to build a proper versionstring - string(REGEX REPLACE init-|[0-9]+-g "" rev_hash ${rev_info}) + # We have valid date from git commit, use that + set(rev_date_fallback ${rev_date}) endif() endif() +# For package/copyright information we always need a proper date - keep "Archived/1970" for displaying git info but a valid year elsewhere +string(REGEX MATCH "([0-9]+)-([0-9]+)-([0-9]+)" rev_date_fallback_match ${rev_date_fallback}) +set(rev_year ${CMAKE_MATCH_1}) +set(rev_month ${CMAKE_MATCH_2}) +set(rev_day ${CMAKE_MATCH_3}) + # Create the actual revision_data.h file from the above params -if(NOT "${rev_hash_cached}" MATCHES "${rev_hash}" OR NOT "${rev_branch_cached}" MATCHES "${rev_branch}" OR NOT EXISTS "${BUILDDIR}/revision_data.h") - configure_file( - "${CMAKE_SOURCE_DIR}/revision_data.h.in.cmake" - "${BUILDDIR}/revision_data.h" - @ONLY - ) - set(rev_hash_cached "${rev_hash}" CACHE INTERNAL "Cached commit-hash") - set(rev_branch_cached "${rev_branch}" CACHE INTERNAL "Cached branch name") -endif() +configure_file( + "${CMAKE_SOURCE_DIR}/revision_data.h.in.cmake" + "${BUILDDIR}/revision_data.h" + @ONLY +) diff --git a/cmake/macros/FindGit.cmake b/cmake/macros/FindGit.cmake deleted file mode 100644 index b95fb920..00000000 --- a/cmake/macros/FindGit.cmake +++ /dev/null @@ -1,38 +0,0 @@ - -include(${CMAKE_SOURCE_DIR}/cmake/macros/EnsureVersion.cmake) - -set(_REQUIRED_GIT_VERSION "1.7") - -find_program(GIT_EXECUTABLE - NAMES - git git.cmd - HINTS - ENV PATH - DOC "Full path to git commandline client" -) -MARK_AS_ADVANCED(GIT_EXECUTABLE) - -if(NOT GIT_EXECUTABLE) - message(FATAL_ERROR " - Git was NOT FOUND on your system - did you forget to install a recent version, or setting the path to it? - Observe that for revision hash/date to work you need at least version ${_REQUIRED_GIT_VERSION}") -else() - message(STATUS "Found git binary : ${GIT_EXECUTABLE}") - execute_process( - COMMAND "${GIT_EXECUTABLE}" --version - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - OUTPUT_VARIABLE _GIT_VERSION - ERROR_QUIET - ) - - # make sure we're using minimum the required version of git, so the "dirty-testing" will work properly - ensure_version( "${_REQUIRED_GIT_VERSION}" "${_GIT_VERSION}" _GIT_VERSION_OK) - - # throw an error if we don't have a recent enough version of git... - if(NOT _GIT_VERSION_OK) - message(STATUS "Git version too old : ${_GIT_VERSION}") - message(FATAL_ERROR " - Git was found but is OUTDATED - did you forget to install a recent version, or setting the path to it? - Observe that for revision hash/date to work you need at least version ${_REQUIRED_GIT_VERSION}") - endif() -endif() diff --git a/cmake/options.cmake b/cmake/options.cmake index a50c50d7..070ef966 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -18,4 +18,4 @@ option(WITH_COREDEBUG "Include additional debug-code in core" set(WITH_SOURCE_TREE "hierarchical" CACHE STRING "Build the source tree for IDE's.") set_property(CACHE WITH_SOURCE_TREE PROPERTY STRINGS no flat hierarchical hierarchical-folders) -option(WITHOUT_GIT "Disable the GIT testing routines" 1) +option(WITHOUT_GIT "Disable the GIT testing routines" 0) diff --git a/cmake/showoptions.cmake b/cmake/showoptions.cmake index b183014a..547dfbc2 100644 --- a/cmake/showoptions.cmake +++ b/cmake/showoptions.cmake @@ -59,4 +59,19 @@ else() message("* Show source tree : No") endif() +if(WITHOUT_GIT) + message("* Use GIT revision hash : No") + message("") + message(" *** WITHOUT_GIT - WARNING!") + message(" *** By choosing the WITHOUT_GIT option you have waived all rights for support,") + message(" *** and accept that or all requests for support or assistance sent to the core") + message(" *** developers will be rejected. This due to that we will be unable to detect") + message(" *** what revision of the codebase you are using in a proper way.") + message(" *** We remind you that you need to use the repository codebase and a supported") + message(" *** version of git for the revision-hash to work, and be allowed to ask for") + message(" *** support if needed.") +else() + message("* Use GIT revision hash : Yes (default)") +endif() + message("") diff --git a/issue_template.md b/issue_template.md new file mode 100644 index 00000000..5d596b55 --- /dev/null +++ b/issue_template.md @@ -0,0 +1,45 @@ + + +**Description:** + +CHANGEME Description of the problem or issue here. +If this is a crash, post the crashlog (upload to https://gist.github.com/). + +**Expected behaviour:** + +CHANGEME Tell us what should happen instead. + +**Steps to reproduce the problem:** + +1. CHANGEME Step 1 include entries of affected creatures / items / quests with a link to the relevant wowhead page. +2. Step 2 +3. Step 3 + +**LC rev. hash/commit:** + +CHANGEME Copy the result of server debug command (if you need to run it from client get prat addon) + +**Operating system:** + +CHANGEME OS + + + diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 00000000..3c2d4781 --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,29 @@ + + +**Changes proposed:** + +- +- +- + +**Issues addressed:** + +Closes # (insert issue tracker number) + + +**Tests performed:** + +(Does it build, tested in-game, etc.) + + +**Known issues and TODO list:** (add/remove lines as needed) + +- [ ] +- [ ] + + + diff --git a/revision_data.h.in.cmake b/revision_data.h.in.cmake index 768d1544..248311ae 100644 --- a/revision_data.h.in.cmake +++ b/revision_data.h.in.cmake @@ -11,10 +11,10 @@ #define _MYSQL_EXECUTABLE R"(@MYSQL_EXECUTABLE@)" #define _FULL_DATABASE "LegionCore_world_735.26972_2024_10_23.sql" #define _HOTFIXES_DATABASE "LegionCore_hotfixes_735.26972_2024_10_23.sql" - #define VER_COMPANYNAME_STR "LegionCore" - #define VER_LEGALCOPYRIGHT_STR "(c)2024 LegionCore" - #define VER_FILEVERSION 0,0,0 - #define VER_FILEVERSION_STR "LegionCore 2024-09-22" - #define VER_PRODUCTVERSION VER_FILEVERSION - #define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR + #define VER_COMPANYNAME_STR "LegionCore" + #define VER_LEGALCOPYRIGHT_STR "(c)@rev_year@ LegionCore" + #define VER_FILEVERSION 0,0,0 + #define VER_FILEVERSION_STR "@rev_hash@ @rev_date@ (@rev_branch@ branch)" + #define VER_PRODUCTVERSION VER_FILEVERSION + #define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR #endif // __REVISION_DATA_H__ diff --git a/src/common/GitRevision.cpp b/src/common/GitRevision.cpp index 26b1ccf5..d9865bf8 100644 --- a/src/common/GitRevision.cpp +++ b/src/common/GitRevision.cpp @@ -21,6 +21,16 @@ char const* GitRevision::GetCMakeCommand() return _CMAKE_COMMAND; } +char const* GitRevision::GetCMakeVersion() +{ + return _CMAKE_VERSION; +} + +char const* GitRevision::GetHostOSVersion() +{ + return _CMAKE_HOST_SYSTEM; +} + char const* GitRevision::GetBuildDirectory() { return _BUILD_DIRECTORY; diff --git a/src/common/GitRevision.h b/src/common/GitRevision.h index f918d5d7..8323af39 100644 --- a/src/common/GitRevision.h +++ b/src/common/GitRevision.h @@ -27,6 +27,8 @@ namespace GitRevision char const* GetDate(); char const* GetBranch(); char const* GetCMakeCommand(); + char const* GetCMakeVersion(); + char const* GetHostOSVersion(); char const* GetBuildDirectory(); char const* GetSourceDirectory(); char const* GetMySQLExecutable(); diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index a71ef5fb..1ce507a1 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -954,7 +954,7 @@ DB2Manager& DB2Manager::Instance() return instance; } -void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) +uint32 DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) { uint32 oldMSTime = getMSTime(); @@ -1591,6 +1591,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) InitDB2CustomStores(); TC_LOG_INFO("server.loading", ">> Initialized " SZFMTD " DB2 data stores in %u ms", _stores.size(), GetMSTimeDiffToNow(oldMSTime)); + + return availableDb2Locales; } void DB2Manager::InitDB2CustomStores() diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 6f159eb7..7c6d87f1 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -405,7 +405,7 @@ class DB2Manager static DB2Manager& Instance(); - void LoadStores(std::string const& dataPath, uint32 defaultLocale); + uint32 LoadStores(std::string const& dataPath, uint32 defaultLocale); void InitDB2CustomStores(); static DB2StorageBase const* GetStorage(uint32 type); void LoadingExtraHotfixData(); diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 4f59b85c..cd1928ee 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -102,7 +102,7 @@ typedef std::map TransportAnimationContainer; class TransportMgr { - friend void DB2Manager::LoadStores(std::string const&, uint32); + friend uint32 DB2Manager::LoadStores(std::string const&, uint32); public: static TransportMgr* instance(); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 00d776d4..0a871935 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -161,6 +161,7 @@ rate_values{}, m_int_configs{}, m_bool_configs{}, m_float_configs{}, m_NextRando m_pvpMysticCount = 0; m_defaultDbcLocale = LOCALE_enUS; + m_availableDbcLocaleMask = 0; m_isClosed = false; @@ -1616,7 +1617,7 @@ void World::SetInitialWorldSettings() CharacterDatabase.Execute(stmt); TC_LOG_INFO("server.loading", "Loading db2 info..."); - sDB2Manager.LoadStores(m_dataPath, m_defaultDbcLocale); + m_availableDbcLocaleMask = sDB2Manager.LoadStores(m_dataPath, m_defaultDbcLocale); TC_LOG_INFO("server.loading", "Loading hotfix info..."); sDB2Manager.LoadHotfixData(); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index dd135bad..ffceb411 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -844,6 +844,8 @@ class World void UpdateRealmCharCount(uint32 accid); + LocaleConstant GetAvailableDbcLocale(LocaleConstant locale) const { if (m_availableDbcLocaleMask & (1 << locale)) return locale; else return m_defaultDbcLocale; } + // used World DB version void LoadDBVersion(); char const* GetDBVersion() const { return m_DBVersion.c_str(); } @@ -963,6 +965,7 @@ class World uint32 m_playerLimit; AccountTypes m_allowedSecurityLevel; LocaleConstant m_defaultDbcLocale; // from config for one from loaded DBC locales + uint32 m_availableDbcLocaleMask; // by loaded DBC bool m_allowMovement; std::vector _motd; std::string m_dataPath; diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 5f8228f4..7927eccf 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -25,12 +25,19 @@ EndScriptData */ #include "Anticheat.h" #include "Chat.h" #include "Config.h" +#include "DatabaseLoader.h" #include "GameTime.h" #include "GitRevision.h" #include "MapManager.h" +#include "MySQLThreading.h" #include "ObjectAccessor.h" #include "ScriptMgr.h" #include "UpdateTime.h" +#include "VMapFactory.h" +#include +#include +#include +#include class server_commandscript : public CommandScript { @@ -73,17 +80,18 @@ class server_commandscript : public CommandScript static std::vector serverCommandTable = { - { "corpses", SEC_GAMEMASTER, true, &HandleServerCorpsesCommand, ""}, - { "anticheatReload", SEC_ADMINISTRATOR, true, &HandleReloadAnticheatCommand, ""}, - { "exit", SEC_CONSOLE, true, &HandleServerExitCommand, ""}, - { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable }, - { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverIdleShutdownCommandTable }, - { "info", SEC_PLAYER, true, &HandleServerInfoCommand, ""}, - { "motd", SEC_PLAYER, true, &HandleServerMotdCommand, ""}, - { "plimit", SEC_ADMINISTRATOR, true, &HandleServerPLimitCommand, ""}, - { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable }, - { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable }, - { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable } + { "corpses", SEC_GAMEMASTER, true, &HandleServerCorpsesCommand, ""}, + { "debug", SEC_ADMINISTRATOR, true, &HandleServerDebugCommand, ""}, + { "anticheatReload", SEC_ADMINISTRATOR, true, &HandleReloadAnticheatCommand, ""}, + { "exit", SEC_CONSOLE, true, &HandleServerExitCommand, ""}, + { "idlerestart", SEC_ADMINISTRATOR, true, NULL, "", serverIdleRestartCommandTable }, + { "idleshutdown", SEC_ADMINISTRATOR, true, NULL, "", serverIdleShutdownCommandTable }, + { "info", SEC_PLAYER, true, &HandleServerInfoCommand, ""}, + { "motd", SEC_PLAYER, true, &HandleServerMotdCommand, ""}, + { "plimit", SEC_ADMINISTRATOR, true, &HandleServerPLimitCommand, ""}, + { "restart", SEC_ADMINISTRATOR, true, NULL, "", serverRestartCommandTable }, + { "shutdown", SEC_ADMINISTRATOR, true, NULL, "", serverShutdownCommandTable }, + { "set", SEC_ADMINISTRATOR, true, NULL, "", serverSetCommandTable } }; static std::vector commandTable = @@ -106,6 +114,138 @@ class server_commandscript : public CommandScript return true; } + static bool HandleServerDebugCommand(ChatHandler* handler, char const* /*args*/) + { + uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); + std::string dbPortOutput; + + { + uint16 dbPort = 0; + if (QueryResult res = LoginDatabase.PQuery("SELECT port FROM realmlist WHERE id = %u", realm.Id.Realm)) + dbPort = (*res)[0].GetUInt16(); + + if (dbPort) + dbPortOutput = Trinity::StringFormat("Realmlist (Realm Id: %u) configured in port %" PRIu16, realm.Id.Realm, dbPort); + else + dbPortOutput = Trinity::StringFormat("Realm Id: %u not found in `realmlist` table. Please check your setup", realm.Id.Realm); + } + + handler->PSendSysMessage("%s", GitRevision::GetFullVersion()); + handler->PSendSysMessage("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + handler->PSendSysMessage("Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); + handler->PSendSysMessage("Using MySQL version: %u", MySQL::GetLibraryVersion()); + handler->PSendSysMessage("Using CMake version: %s", GitRevision::GetCMakeVersion()); + + handler->PSendSysMessage("Compiled on: %s", GitRevision::GetHostOSVersion()); + + uint32 updateFlags = sConfigMgr->GetIntDefault("Updates.EnableDatabases", DatabaseLoader::DATABASE_NONE); + if (!updateFlags) + handler->SendSysMessage("Automatic database updates are disabled for all databases!"); + else + { + static char const* const databaseNames[] = + { + "Auth", + "Characters", + "World", + "Hotfixes" + }; + static size_t constexpr databaseCount = std::extent::value; + + std::string availableUpdateDatabases; + for (uint32 i = 0; i < databaseCount; ++i) + { + if (!(updateFlags & (1 << i))) + continue; + + availableUpdateDatabases += databaseNames[i]; + if (i != databaseCount - 1) + availableUpdateDatabases += ", "; + } + + handler->PSendSysMessage("Automatic database updates are enabled for the following databases: %s", availableUpdateDatabases.c_str()); + } + + handler->PSendSysMessage("Worldserver listening connections on port %" PRIu16, worldPort); + handler->PSendSysMessage("%s", dbPortOutput.c_str()); + + bool vmapIndoorCheck = sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK); + bool vmapLOSCheck = VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled(); + bool vmapHeightCheck = VMAP::VMapFactory::createOrGetVMapManager()->isHeightCalcEnabled(); + + bool mmapEnabled = sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS); + + std::string dataDir = sWorld->GetDataPath(); + std::vector subDirs; + subDirs.emplace_back("maps"); + if (vmapIndoorCheck || vmapLOSCheck || vmapHeightCheck) + { + handler->PSendSysMessage("VMAPs status: Enabled. LineOfSight: %i, getHeight: %i, indoorCheck: %i", vmapLOSCheck, vmapHeightCheck, vmapIndoorCheck); + subDirs.emplace_back("vmaps"); + } + else + handler->SendSysMessage("VMAPs status: Disabled"); + + if (mmapEnabled) + { + handler->SendSysMessage("MMAPs status: Enabled"); + subDirs.emplace_back("mmaps"); + } + else + handler->SendSysMessage("MMAPs status: Disabled"); + + for (std::string const& subDir : subDirs) + { + boost::filesystem::path mapPath(dataDir); + mapPath.append(subDir); + + if (!boost::filesystem::exists(mapPath)) + { + handler->PSendSysMessage("%s directory doesn't exist!. Using path: %s", subDir.c_str(), mapPath.generic_string().c_str()); + continue; + } + + auto end = boost::filesystem::directory_iterator(); + std::size_t folderSize = std::accumulate(boost::filesystem::directory_iterator(mapPath), end, std::size_t(0), [](std::size_t val, boost::filesystem::path const& mapFile) + { + if (boost::filesystem::is_regular_file(mapFile)) + val += boost::filesystem::file_size(mapFile); + return val; + }); + + handler->PSendSysMessage("%s directory located in %s. Total size: " SZFMTD " bytes", subDir.c_str(), mapPath.generic_string().c_str(), folderSize); + } + + LocaleConstant defaultLocale = sWorld->GetDefaultDbcLocale(); + uint32 availableLocalesMask = (1 << defaultLocale); + + for (uint8 i = 0; i < TOTAL_LOCALES; ++i) + { + LocaleConstant locale = static_cast(i); + if (locale == defaultLocale) + continue; + + if (sWorld->GetAvailableDbcLocale(locale) != defaultLocale) + availableLocalesMask |= (1 << locale); + } + + std::string availableLocales; + for (uint8 i = 0; i < TOTAL_LOCALES; ++i) + { + if (!(availableLocalesMask & (1 << i))) + continue; + + availableLocales += localeNames[i]; + if (i != TOTAL_LOCALES - 1) + availableLocales += " "; + } + + handler->PSendSysMessage("Using %s DBC Locale as default. All available DBC locales: %s", localeNames[defaultLocale], availableLocales.c_str()); + + handler->PSendSysMessage("Using World DB: %s", sWorld->GetDBVersion()); + return true; + } + static bool HandleServerInfoCommand(ChatHandler* handler, char const* /*args*/) { uint32 playersNum = sWorld->GetPlayerCount();