diff --git a/Minecraft.Server/Access/BanManager.cpp b/Minecraft.Server/Access/BanManager.cpp index 76f14b00..937a8113 100644 --- a/Minecraft.Server/Access/BanManager.cpp +++ b/Minecraft.Server/Access/BanManager.cpp @@ -8,6 +8,7 @@ #include "..\Common\StringUtils.h" #include "..\ServerLogger.h" #include "Common/vendor/nlohmann/json.hpp" +#include "..\..\Minecraft.World\UUID.h" #include #include @@ -121,9 +122,19 @@ namespace ServerRuntime { return false; } + bool dirty = false; + for (auto &entry : players) + { + if (!entry.uuid.empty() || entry.xuid.empty()) continue; + try { + uint64_t xuid = std::stoull(entry.xuid, nullptr, 0); + if (xuid) { entry.uuid = GameUUID::fromXuid(xuid).toString(); dirty = true; } + } catch (...) {} + } m_bannedPlayers.swap(players); m_bannedIps.swap(ips); + if (dirty) Save(); return true; } diff --git a/Minecraft.Server/Access/WhitelistManager.cpp b/Minecraft.Server/Access/WhitelistManager.cpp index ec0104b7..9b671445 100644 --- a/Minecraft.Server/Access/WhitelistManager.cpp +++ b/Minecraft.Server/Access/WhitelistManager.cpp @@ -7,6 +7,7 @@ #include "..\Common\StringUtils.h" #include "..\ServerLogger.h" #include "Common/vendor/nlohmann/json.hpp" +#include "..\..\Minecraft.World\UUID.h" #include @@ -44,8 +45,18 @@ namespace ServerRuntime { return false; } + bool dirty = false; + for (auto &entry : players) + { + if (!entry.uuid.empty() || entry.xuid.empty()) continue; + try { + uint64_t xuid = std::stoull(entry.xuid, nullptr, 0); + if (xuid) { entry.uuid = GameUUID::fromXuid(xuid).toString(); dirty = true; } + } catch (...) {} + } m_whitelistedPlayers.swap(players); + if (dirty) Save(); return true; } diff --git a/Minecraft.World/DirectoryLevelStorage.cpp b/Minecraft.World/DirectoryLevelStorage.cpp index c557e37a..892ccae5 100644 --- a/Minecraft.World/DirectoryLevelStorage.cpp +++ b/Minecraft.World/DirectoryLevelStorage.cpp @@ -11,6 +11,8 @@ #include "LevelData.h" #include "DirectoryLevelStorage.h" #include "ConsoleSaveFileIO.h" +#include "UUID.h" +#include "StringHelpers.h" const wstring DirectoryLevelStorage::sc_szPlayerDir(L"players/"); @@ -168,6 +170,8 @@ DirectoryLevelStorage::DirectoryLevelStorage(ConsoleSaveFile *saveFile, const Fi #ifdef _LARGE_WORLDS m_usedMappings = byteArray(MAXIMUM_MAP_SAVE_DATA/8); #endif + + migratePlayerXuidsToUuids(); } DirectoryLevelStorage::~DirectoryLevelStorage() @@ -398,7 +402,7 @@ void DirectoryLevelStorage::save(shared_ptr player) #elif defined(_DURANGO) ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + player->getXuid().toString() + L".dat" ); #else - const ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + std::to_wstring( player->getXuid() ) + L".dat" ); + const ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + player->getGameUUID().toWString() + L".dat" ); #endif // If saves are disabled (e.g. because we are writing the save buffer to disk) then cache this player data if(StorageManager.GetSaveDisabled()) @@ -447,7 +451,7 @@ CompoundTag *DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid) #elif defined(_DURANGO) ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + xuid.toString() + L".dat" ); #else - const ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + std::to_wstring( xuid ) + L".dat" ); + const ConsoleSavePath realFile = ConsoleSavePath( playerDir.getName() + GameUUID::fromXuid(xuid).toWString() + L".dat" ); #endif const auto it = m_cachedSaveData.find(realFile.getName()); if(it != m_cachedSaveData.end() ) @@ -818,3 +822,42 @@ void DirectoryLevelStorage::saveAllCachedData() } m_mapFilesToDelete.clear(); } +void DirectoryLevelStorage::migratePlayerXuidsToUuids() +{ + if (!m_saveFile) return; + + const ConsoleSavePath marker(L"migration_v1.dat"); + if (m_saveFile->doesFileExist(marker)) return; + + if (vector *playerFiles = m_saveFile->getFilesWithPrefix(playerDir.getName())) + { + for (FileEntry *file : *playerFiles) + { + wstring stem = replaceAll(replaceAll(file->data.filename, playerDir.getName(), L""), L".dat", L""); + + if (stem.empty() || !std::all_of(stem.begin(), stem.end(), [](wchar_t c) { return c >= L'0' && c <= L'9'; })) continue; + + const PlayerUID xuid = _fromString(stem); + if (xuid == INVALID_XUID) continue; + + ConsoleSaveFileInputStream fis(m_saveFile, file); + CompoundTag *tag = NbtIo::readCompressed(&fis); + if (!tag) continue; + + const wstring uuidStr = GameUUID::fromXuid(xuid).toWString(); + tag->putString(L"UUID", uuidStr); + + ConsoleSaveFileOutputStream fos(m_saveFile, ConsoleSavePath(playerDir.getName() + uuidStr + L".dat")); + NbtIo::writeCompressed(tag, &fos); + delete tag; + + m_saveFile->deleteFile(file); + app.DebugPrintf("migrated player %ls -> %ls\n", stem.c_str(), uuidStr.c_str()); + } + delete playerFiles; + } + + DWORD written = 0; + const uint8_t ver = 1; + m_saveFile->writeFile(m_saveFile->createFile(marker), &ver, 1, &written); +} diff --git a/Minecraft.World/DirectoryLevelStorage.h b/Minecraft.World/DirectoryLevelStorage.h index 6d305ba3..b0edff1e 100644 --- a/Minecraft.World/DirectoryLevelStorage.h +++ b/Minecraft.World/DirectoryLevelStorage.h @@ -139,6 +139,7 @@ public: static wstring getPlayerDir() { return sc_szPlayerDir; } private: + void migratePlayerXuidsToUuids(); void dontSaveMapMappingForPlayer(PlayerUID xuid); void deleteMapFilesForPlayer(PlayerUID xuid); };