diff --git a/CMakeLists.txt b/CMakeLists.txt index ebc7db0c6..419f0faff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ list(APPEND MINECRAFT_SERVER_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandList.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandTp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Console/commands/CliCommandGamemode.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/Common/StringUtils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Server/vendor/linenoise/linenoise.c" ) @@ -215,3 +216,4 @@ add_custom_command(TARGET MinecraftServer POST_BUILD ) set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT MinecraftServer) + diff --git a/Minecraft.Server/Common/StringUtils.cpp b/Minecraft.Server/Common/StringUtils.cpp new file mode 100644 index 000000000..b22819f3d --- /dev/null +++ b/Minecraft.Server/Common/StringUtils.cpp @@ -0,0 +1,111 @@ +#include "stdafx.h" + +#include "StringUtils.h" + +#include + +namespace ServerRuntime +{ + namespace StringUtils + { + std::string WideToUtf8(const std::wstring &value) + { + if (value.empty()) + { + return std::string(); + } + + int charCount = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), (int)value.length(), NULL, 0, NULL, NULL); + if (charCount <= 0) + { + return std::string(); + } + + std::string utf8; + utf8.resize(charCount); + WideCharToMultiByte(CP_UTF8, 0, value.c_str(), (int)value.length(), &utf8[0], charCount, NULL, NULL); + return utf8; + } + + std::wstring Utf8ToWide(const char *value) + { + if (value == NULL || value[0] == 0) + { + return std::wstring(); + } + + int wideCount = MultiByteToWideChar(CP_UTF8, 0, value, -1, NULL, 0); + if (wideCount <= 0) + { + wideCount = MultiByteToWideChar(CP_ACP, 0, value, -1, NULL, 0); + if (wideCount <= 0) + { + return std::wstring(); + } + + std::wstring wide; + wide.resize(wideCount - 1); + MultiByteToWideChar(CP_ACP, 0, value, -1, &wide[0], wideCount); + return wide; + } + + std::wstring wide; + wide.resize(wideCount - 1); + MultiByteToWideChar(CP_UTF8, 0, value, -1, &wide[0], wideCount); + return wide; + } + + std::wstring Utf8ToWide(const std::string &value) + { + return Utf8ToWide(value.c_str()); + } + + std::string TrimAscii(const std::string &value) + { + size_t start = 0; + while (start < value.length() && std::isspace((unsigned char)value[start])) + { + ++start; + } + + size_t end = value.length(); + while (end > start && std::isspace((unsigned char)value[end - 1])) + { + --end; + } + + return value.substr(start, end - start); + } + + std::string ToLowerAscii(const std::string &value) + { + std::string lowered = value; + for (size_t i = 0; i < lowered.length(); ++i) + { + lowered[i] = (char)std::tolower((unsigned char)lowered[i]); + } + return lowered; + } + + bool StartsWithIgnoreCase(const std::string &value, const std::string &prefix) + { + if (prefix.size() > value.size()) + { + return false; + } + + for (size_t i = 0; i < prefix.size(); ++i) + { + unsigned char a = (unsigned char)value[i]; + unsigned char b = (unsigned char)prefix[i]; + if (std::tolower(a) != std::tolower(b)) + { + return false; + } + } + + return true; + } + } +} + diff --git a/Minecraft.Server/Common/StringUtils.h b/Minecraft.Server/Common/StringUtils.h new file mode 100644 index 000000000..fa1d5734a --- /dev/null +++ b/Minecraft.Server/Common/StringUtils.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace ServerRuntime +{ + namespace StringUtils + { + std::string WideToUtf8(const std::wstring &value); + std::wstring Utf8ToWide(const char *value); + std::wstring Utf8ToWide(const std::string &value); + + std::string TrimAscii(const std::string &value); + std::string ToLowerAscii(const std::string &value); + bool StartsWithIgnoreCase(const std::string &value, const std::string &prefix); + } +} + diff --git a/Minecraft.Server/Console/ServerCliEngine.cpp b/Minecraft.Server/Console/ServerCliEngine.cpp index c1bb21c87..1a8c3a5b3 100644 --- a/Minecraft.Server/Console/ServerCliEngine.cpp +++ b/Minecraft.Server/Console/ServerCliEngine.cpp @@ -10,6 +10,7 @@ #include "commands\CliCommandList.h" #include "commands\CliCommandStop.h" #include "commands\CliCommandTp.h" +#include "..\Common\StringUtils.h" #include "..\ServerLogger.h" #include "..\..\Minecraft.Client\MinecraftServer.h" #include "..\..\Minecraft.Client\PlayerList.h" @@ -17,7 +18,6 @@ #include "..\..\Minecraft.World\LevelSettings.h" #include "..\..\Minecraft.World\StringHelpers.h" -#include #include #include @@ -68,36 +68,16 @@ namespace ServerRuntime } } - std::string ServerCliEngine::Normalize(const std::string &value) - { - std::string lowered = value; - for (size_t i = 0; i < lowered.size(); ++i) - { - lowered[i] = (char)tolower((unsigned char)lowered[i]); - } - return lowered; - } - - std::wstring ServerCliEngine::ToWide(const std::string &value) - { - return convStringToWstring(value); - } - - std::string ServerCliEngine::ToUtf8(const std::wstring &value) - { - return WideToUtf8(value); - } - bool ServerCliEngine::ExecuteCommandLine(const std::string &line) { // Normalize user input before parsing (trim + optional leading slash). - std::wstring wide = trimString(ToWide(line)); + std::wstring wide = trimString(StringUtils::Utf8ToWide(line)); if (wide.empty()) { return true; } - std::string normalizedLine = ToUtf8(wide); + std::string normalizedLine = StringUtils::WideToUtf8(wide); if (!normalizedLine.empty() && normalizedLine[0] == '/') { normalizedLine = normalizedLine.substr(1); @@ -221,7 +201,7 @@ namespace ServerRuntime std::shared_ptr player = players->players[i]; if (player != NULL) { - result.push_back(ToUtf8(player->getName())); + result.push_back(StringUtils::WideToUtf8(player->getName())); } } @@ -242,7 +222,7 @@ namespace ServerRuntime return nullptr; } - std::wstring target = ToWide(name); + std::wstring target = StringUtils::Utf8ToWide(name); for (size_t i = 0; i < players->players.size(); ++i) { std::shared_ptr player = players->players[i]; @@ -258,10 +238,10 @@ namespace ServerRuntime void ServerCliEngine::SuggestPlayers(const std::string &prefix, const std::string &linePrefix, std::vector *out) const { std::vector players = GetOnlinePlayerNamesUtf8(); - std::string loweredPrefix = Normalize(prefix); + std::string loweredPrefix = StringUtils::ToLowerAscii(prefix); for (size_t i = 0; i < players.size(); ++i) { - std::string loweredName = Normalize(players[i]); + std::string loweredName = StringUtils::ToLowerAscii(players[i]); if (loweredName.compare(0, loweredPrefix.size(), loweredPrefix) == 0) { out->push_back(linePrefix + players[i]); @@ -272,11 +252,11 @@ namespace ServerRuntime void ServerCliEngine::SuggestGamemodes(const std::string &prefix, const std::string &linePrefix, std::vector *out) const { static const char *kModes[] = { "survival", "creative", "s", "c", "0", "1" }; - std::string loweredPrefix = Normalize(prefix); + std::string loweredPrefix = StringUtils::ToLowerAscii(prefix); for (size_t i = 0; i < sizeof(kModes) / sizeof(kModes[0]); ++i) { std::string candidate = kModes[i]; - std::string loweredCandidate = Normalize(candidate); + std::string loweredCandidate = StringUtils::ToLowerAscii(candidate); if (loweredCandidate.compare(0, loweredPrefix.size(), loweredPrefix) == 0) { out->push_back(linePrefix + candidate); @@ -286,7 +266,7 @@ namespace ServerRuntime GameType *ServerCliEngine::ParseGamemode(const std::string &token) const { - std::string lowered = Normalize(token); + std::string lowered = StringUtils::ToLowerAscii(token); if (lowered == "survival" || lowered == "s" || lowered == "0") { return GameType::SURVIVAL; @@ -312,3 +292,4 @@ namespace ServerRuntime return *m_registry; } } + diff --git a/Minecraft.Server/Console/ServerCliEngine.h b/Minecraft.Server/Console/ServerCliEngine.h index f460f94f8..32e166674 100644 --- a/Minecraft.Server/Console/ServerCliEngine.h +++ b/Minecraft.Server/Console/ServerCliEngine.h @@ -102,9 +102,6 @@ namespace ServerRuntime private: void RegisterDefaultCommands(); - static std::string Normalize(const std::string &value); - static std::wstring ToWide(const std::string &value); - static std::string ToUtf8(const std::wstring &value); private: mutable std::mutex m_queueMutex; diff --git a/Minecraft.Server/Console/ServerCliRegistry.cpp b/Minecraft.Server/Console/ServerCliRegistry.cpp index 1483c7006..432907b23 100644 --- a/Minecraft.Server/Console/ServerCliRegistry.cpp +++ b/Minecraft.Server/Console/ServerCliRegistry.cpp @@ -3,39 +3,10 @@ #include "ServerCliRegistry.h" #include "commands\IServerCliCommand.h" - -#include +#include "..\Common\StringUtils.h" namespace ServerRuntime { - static bool StartsWithIgnoreCase(const std::string &value, const std::string &prefix) - { - if (prefix.size() > value.size()) - { - return false; - } - for (size_t i = 0; i < prefix.size(); ++i) - { - char a = (char)tolower((unsigned char)value[i]); - char b = (char)tolower((unsigned char)prefix[i]); - if (a != b) - { - return false; - } - } - return true; - } - - std::string ServerCliRegistry::Normalize(const std::string &value) - { - std::string normalized = value; - for (size_t i = 0; i < normalized.size(); ++i) - { - normalized[i] = (char)tolower((unsigned char)normalized[i]); - } - return normalized; - } - bool ServerCliRegistry::Register(std::unique_ptr command) { if (!command) @@ -44,7 +15,7 @@ namespace ServerRuntime } IServerCliCommand *raw = command.get(); - std::string baseName = Normalize(raw->Name()); + std::string baseName = StringUtils::ToLowerAscii(raw->Name()); // Reject empty/duplicate primary command names. if (baseName.empty() || m_lookup.find(baseName) != m_lookup.end()) { @@ -55,7 +26,7 @@ namespace ServerRuntime normalizedAliases.reserve(aliases.size()); for (size_t i = 0; i < aliases.size(); ++i) { - std::string alias = Normalize(aliases[i]); + std::string alias = StringUtils::ToLowerAscii(aliases[i]); // Alias must also be unique across all names and aliases. if (alias.empty() || m_lookup.find(alias) != m_lookup.end()) { @@ -77,7 +48,7 @@ namespace ServerRuntime const IServerCliCommand *ServerCliRegistry::Find(const std::string &name) const { - std::string key = Normalize(name); + std::string key = StringUtils::ToLowerAscii(name); auto it = m_lookup.find(key); if (it == m_lookup.end()) { @@ -88,7 +59,7 @@ namespace ServerRuntime IServerCliCommand *ServerCliRegistry::FindMutable(const std::string &name) { - std::string key = Normalize(name); + std::string key = StringUtils::ToLowerAscii(name); auto it = m_lookup.find(key); if (it == m_lookup.end()) { @@ -103,7 +74,7 @@ namespace ServerRuntime { const IServerCliCommand *command = m_commands[i].get(); std::string name = command->Name(); - if (StartsWithIgnoreCase(name, prefix)) + if (StringUtils::StartsWithIgnoreCase(name, prefix)) { out->push_back(linePrefix + name); } @@ -112,7 +83,7 @@ namespace ServerRuntime std::vector aliases = command->Aliases(); for (size_t aliasIndex = 0; aliasIndex < aliases.size(); ++aliasIndex) { - if (StartsWithIgnoreCase(aliases[aliasIndex], prefix)) + if (StringUtils::StartsWithIgnoreCase(aliases[aliasIndex], prefix)) { out->push_back(linePrefix + aliases[aliasIndex]); } @@ -125,3 +96,4 @@ namespace ServerRuntime return m_commands; } } + diff --git a/Minecraft.Server/Console/ServerCliRegistry.h b/Minecraft.Server/Console/ServerCliRegistry.h index 0dc0fb9ad..5104b5345 100644 --- a/Minecraft.Server/Console/ServerCliRegistry.h +++ b/Minecraft.Server/Console/ServerCliRegistry.h @@ -51,9 +51,6 @@ namespace ServerRuntime */ const std::vector> &Commands() const; - private: - static std::string Normalize(const std::string &value); - private: std::vector> m_commands; std::unordered_map m_lookup; diff --git a/Minecraft.Server/Console/commands/CliCommandGamemode.cpp b/Minecraft.Server/Console/commands/CliCommandGamemode.cpp index d2d5ee360..f54392370 100644 --- a/Minecraft.Server/Console/commands/CliCommandGamemode.cpp +++ b/Minecraft.Server/Console/commands/CliCommandGamemode.cpp @@ -4,7 +4,7 @@ #include "..\ServerCliEngine.h" #include "..\ServerCliParser.h" -#include "..\..\ServerLogger.h" +#include "..\..\Common\StringUtils.h" #include "..\..\..\Minecraft.Client\MinecraftServer.h" #include "..\..\..\Minecraft.Client\PlayerList.h" #include "..\..\..\Minecraft.Client\ServerPlayer.h" @@ -77,7 +77,9 @@ namespace ServerRuntime target->setGameMode(mode); target->fallDistance = 0.0f; - engine->LogInfo("Set " + WideToUtf8(target->getName()) + " gamemode to " + WideToUtf8(mode->getName()) + "."); + engine->LogInfo( + "Set " + StringUtils::WideToUtf8(target->getName()) + " gamemode to " + + StringUtils::WideToUtf8(mode->getName()) + "."); return true; } @@ -93,3 +95,4 @@ namespace ServerRuntime } } } + diff --git a/Minecraft.Server/Console/commands/CliCommandList.cpp b/Minecraft.Server/Console/commands/CliCommandList.cpp index 8a91c03c0..a3c1d05b3 100644 --- a/Minecraft.Server/Console/commands/CliCommandList.cpp +++ b/Minecraft.Server/Console/commands/CliCommandList.cpp @@ -3,7 +3,7 @@ #include "CliCommandList.h" #include "..\ServerCliEngine.h" -#include "..\..\ServerLogger.h" +#include "..\..\Common\StringUtils.h" #include "..\..\..\Minecraft.Client\MinecraftServer.h" #include "..\..\..\Minecraft.Client\PlayerList.h" @@ -35,7 +35,7 @@ namespace ServerRuntime } PlayerList *players = server->getPlayers(); - std::string names = WideToUtf8(players->getPlayerNames()); + std::string names = StringUtils::WideToUtf8(players->getPlayerNames()); if (names.empty()) { names = "(none)"; @@ -45,3 +45,4 @@ namespace ServerRuntime return true; } } + diff --git a/Minecraft.Server/Minecraft.Server.vcxproj b/Minecraft.Server/Minecraft.Server.vcxproj index cdbd5f540..246da3068 100644 --- a/Minecraft.Server/Minecraft.Server.vcxproj +++ b/Minecraft.Server/Minecraft.Server.vcxproj @@ -1,4 +1,4 @@ - + @@ -657,6 +657,7 @@ + @@ -683,6 +684,7 @@ + @@ -705,3 +707,4 @@ + diff --git a/Minecraft.Server/Minecraft.Server.vcxproj.filters b/Minecraft.Server/Minecraft.Server.vcxproj.filters index 4cb5008a8..a4567a11f 100644 --- a/Minecraft.Server/Minecraft.Server.vcxproj.filters +++ b/Minecraft.Server/Minecraft.Server.vcxproj.filters @@ -10,6 +10,9 @@ {7C28D123-0DA3-4B17-84C0-E326F5A75740} + + {BC6FD58B-1A40-45FE-B8D9-1A087C25126D} + {3E4D5A41-CAB8-4A10-82B5-8B2AE2E25CB2} @@ -36,6 +39,9 @@ Server\Console + + Server\Common + Server\Vendor @@ -566,6 +572,9 @@ Server\Console + + Server\Common + Server @@ -604,4 +613,5 @@ - \ No newline at end of file + + diff --git a/Minecraft.Server/ServerLogger.cpp b/Minecraft.Server/ServerLogger.cpp index 9599df0a9..0c7c567f6 100644 --- a/Minecraft.Server/ServerLogger.cpp +++ b/Minecraft.Server/ServerLogger.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "ServerLogger.h" +#include "Common\\StringUtils.h" #include "vendor\\linenoise\\linenoise.h" #include @@ -186,53 +187,6 @@ EServerLogLevel GetServerLogLevel() return (EServerLogLevel)g_minLogLevel; } -std::string WideToUtf8(const std::wstring &value) -{ - if (value.empty()) - { - return std::string(); - } - - int charCount = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), (int)value.length(), NULL, 0, NULL, NULL); - if (charCount <= 0) - { - return std::string(); - } - - std::string utf8; - utf8.resize(charCount); - WideCharToMultiByte(CP_UTF8, 0, value.c_str(), (int)value.length(), &utf8[0], charCount, NULL, NULL); - return utf8; -} - -std::wstring Utf8ToWide(const char *value) -{ - if (value == NULL || value[0] == 0) - { - return std::wstring(); - } - - int wideCount = MultiByteToWideChar(CP_UTF8, 0, value, -1, NULL, 0); - if (wideCount <= 0) - { - wideCount = MultiByteToWideChar(CP_ACP, 0, value, -1, NULL, 0); - if (wideCount <= 0) - { - return std::wstring(); - } - - std::wstring wide; - wide.resize(wideCount - 1); - MultiByteToWideChar(CP_ACP, 0, value, -1, &wide[0], wideCount); - return wide; - } - - std::wstring wide; - wide.resize(wideCount - 1); - MultiByteToWideChar(CP_UTF8, 0, value, -1, &wide[0], wideCount); - return wide; -} - void LogDebug(const char *category, const char *message) { WriteLogLine(eServerLogLevel_Debug, category, message); @@ -297,7 +251,8 @@ void LogWorldIO(const char *message) void LogWorldName(const char *prefix, const std::wstring &name) { - std::string utf8 = WideToUtf8(name); + std::string utf8 = StringUtils::WideToUtf8(name); LogInfof("world-io", "%s: %s", (prefix != NULL) ? prefix : "name", utf8.c_str()); } } + diff --git a/Minecraft.Server/ServerLogger.h b/Minecraft.Server/ServerLogger.h index 8008225ae..426a3d365 100644 --- a/Minecraft.Server/ServerLogger.h +++ b/Minecraft.Server/ServerLogger.h @@ -24,9 +24,6 @@ namespace ServerRuntime void SetServerLogLevel(EServerLogLevel level); EServerLogLevel GetServerLogLevel(); - std::string WideToUtf8(const std::wstring &value); - std::wstring Utf8ToWide(const char *value); - void LogDebug(const char *category, const char *message); void LogInfo(const char *category, const char *message); void LogWarn(const char *category, const char *message); diff --git a/Minecraft.Server/ServerProperties.cpp b/Minecraft.Server/ServerProperties.cpp index defe6d099..fd57b92ed 100644 --- a/Minecraft.Server/ServerProperties.cpp +++ b/Minecraft.Server/ServerProperties.cpp @@ -3,6 +3,7 @@ #include "ServerProperties.h" #include "ServerLogger.h" +#include "Common\\StringUtils.h" #include #include @@ -13,6 +14,11 @@ namespace ServerRuntime { +using StringUtils::ToLowerAscii; +using StringUtils::TrimAscii; +using StringUtils::Utf8ToWide; +using StringUtils::WideToUtf8; + struct ServerPropertyDefault { const char *key; @@ -72,34 +78,6 @@ static const ServerPropertyDefault kServerPropertyDefaults[] = { "trust-players", "true" } }; -static std::string TrimAscii(const std::string &value) -{ - size_t start = 0; - while (start < value.length() && std::isspace((unsigned char)value[start])) - { - ++start; - } - - size_t end = value.length(); - while (end > start && std::isspace((unsigned char)value[end - 1])) - { - --end; - } - - return value.substr(start, end - start); -} - -static std::string ToLowerAscii(const std::string &value) -{ - std::string lowered = value; - for (size_t i = 0; i < lowered.length(); ++i) - { - unsigned char ch = (unsigned char)lowered[i]; - lowered[i] = (char)std::tolower(ch); - } - return lowered; -} - static std::string BoolToString(bool value) { return value ? "true" : "false"; @@ -778,3 +756,4 @@ bool SaveServerPropertiesConfig(const ServerPropertiesConfig &config) return WriteServerPropertiesFile(kServerPropertiesPath, merged); } } + diff --git a/Minecraft.Server/Windows64/ServerMain.cpp b/Minecraft.Server/Windows64/ServerMain.cpp index 2b1486460..6346d5d05 100644 --- a/Minecraft.Server/Windows64/ServerMain.cpp +++ b/Minecraft.Server/Windows64/ServerMain.cpp @@ -5,6 +5,7 @@ #include "Input.h" #include "Minecraft.h" #include "MinecraftServer.h" +#include "..\Common\StringUtils.h" #include "..\ServerLogger.h" #include "..\ServerProperties.h" #include "..\WorldManager.h" @@ -119,7 +120,7 @@ using ServerRuntime::SaveServerPropertiesConfig; using ServerRuntime::SetServerLogLevel; using ServerRuntime::ServerPropertiesConfig; using ServerRuntime::TryParseServerLogLevel; -using ServerRuntime::WideToUtf8; +using ServerRuntime::StringUtils::WideToUtf8; using ServerRuntime::BootstrapWorldForServer; using ServerRuntime::eWorldBootstrap_CreatedNew; using ServerRuntime::eWorldBootstrap_Failed; @@ -609,3 +610,4 @@ int main(int argc, char **argv) return 0; } + diff --git a/Minecraft.Server/WorldManager.cpp b/Minecraft.Server/WorldManager.cpp index a8b439482..4e197a269 100644 --- a/Minecraft.Server/WorldManager.cpp +++ b/Minecraft.Server/WorldManager.cpp @@ -5,12 +5,16 @@ #include "Minecraft.h" #include "MinecraftServer.h" #include "ServerLogger.h" +#include "Common\\StringUtils.h" #include #include namespace ServerRuntime { +using StringUtils::Utf8ToWide; +using StringUtils::WideToUtf8; + enum EWorldSaveLoadResult { eWorldSaveLoad_Loaded, @@ -525,3 +529,4 @@ bool WaitForWorldActionIdle( return (app.GetXuiServerAction(actionPad) == eXuiServerAction_Idle); } } +