mojira.dev
MC-265541

player.dat_old won't be read even if player.dat doesn't exist

Notice: player.dat represents to player data file(<PlayerUUID>.dat) here, you'll find them in world\playerdata

Steps to Reproduce:
1. Run your test server.
2. Enter the server, /give yourself a bedrock or whatever, then quit the server.
3. Delete your player.dat in world\playerdata, it may appear as 3752d12c-3924-4d32-8407-6c19a4bd409f.dat
4. Enter the server again, and you'll find your stuff is gone even if your player.dat_old still stores your inventory. If you quit the server, your player.dat_old will be overwritten and you will never find your stuff back.

Expected Results:
In Step 4, your stuff shouldn't be gone since player.dat_old has stored it.
(Rename it into player.dat when it is not overwritten and return to the server, you'll see your stuff)

The behavior of player.dat_old should be the same as level.dat_old.
If you delete the level.dat of a world, reenter it and you'll see the data is still there since the game will read the data of the level.dat_old if level_dat doesn't exist.

Notes:
You can't reproduce this in single-player mode since your data is stored in another place.
This bug may cause player data lost if player.dat is corrupted somehow but player.dat_old isn't corrupted.

Code analysis:
This is from net.minecraft.world.WorldSaveHandler method, yarn mapping.
You'll see the game won't do anything if player.dat doesn't exist.

public NbtCompound loadPlayerData(PlayerEntity player) {
        NbtCompound nbtCompound = null;

        try {
            File file = new File(this.playerDataDir, player.getUuidAsString() + ".dat");
            if (file.exists() && file.isFile()) {
                nbtCompound = NbtIo.readCompressed(file);
            }
        } catch (Exception var4) {
            LOGGER.warn("Failed to load player data for {}", player.getName().getString());
        }
...
    }

However, the game does do something in loading level.dat. If it goes wrong, the game will restore the level.dat from level.dat_old.
This is from net.minecraft.world.level.storage.LevelStorage method, yarn mapping.

public CompletableFuture<List<LevelSummary>> loadSummaries(LevelList levels) {
       ...
        while(var3.hasNext()) {
           ...
                try {
                    LevelSummary levelSummary = (LevelSummary)this.readLevelProperties(levelSave, this.createLevelDataParser(levelSave, bl));
                    return levelSummary != null ? levelSummary : null;
                 ...
                } catch (StackOverflowError var5) {
                    LOGGER.error(LogUtils.FATAL_MARKER, "Ran out of stack trying to read summary of {}. Assuming corruption; attempting to restore from from level.dat_old.", levelSave.getRootPath());
                    Util.backupAndReplace(levelSave.getLevelDatPath(), levelSave.getLevelDatOldPath(), levelSave.getCorruptedLevelDatPath(LocalDateTime.now()), true);
                    throw var5;
                }
            }...
        }

Comments 0

No comments.

HackerRouter

Tommy Wallberg

Plausible

Platform

Important

Save Data

1.20.2

23w51a

Retrieved