add: migration from XUID to UUID

This commit is contained in:
Matthew Toro 2026-04-04 15:20:58 -04:00
parent 692a1ffc8e
commit acef537a94
4 changed files with 68 additions and 2 deletions

View file

@ -8,6 +8,7 @@
#include "..\Common\StringUtils.h"
#include "..\ServerLogger.h"
#include "Common/vendor/nlohmann/json.hpp"
#include "..\..\Minecraft.World\UUID.h"
#include <algorithm>
#include <stdio.h>
@ -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;
}

View file

@ -7,6 +7,7 @@
#include "..\Common\StringUtils.h"
#include "..\ServerLogger.h"
#include "Common/vendor/nlohmann/json.hpp"
#include "..\..\Minecraft.World\UUID.h"
#include <algorithm>
@ -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;
}

View file

@ -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> 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<FileEntry *> *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<PlayerUID>(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);
}

View file

@ -139,6 +139,7 @@ public:
static wstring getPlayerDir() { return sc_szPlayerDir; }
private:
void migratePlayerXuidsToUuids();
void dontSaveMapMappingForPlayer(PlayerUID xuid);
void deleteMapFilesForPlayer(PlayerUID xuid);
};