Skip to content

Instantly share code, notes, and snippets.

@basperheim
Created August 3, 2026 20:12
Show Gist options
  • Select an option

  • Save basperheim/12496c91188609837c9f84b054fc0ccc to your computer and use it in GitHub Desktop.

Select an option

Save basperheim/12496c91188609837c9f84b054fc0ccc to your computer and use it in GitHub Desktop.
minecraft-java-26-nether-lava-rescue-macos

Lava Rescue on TLauncher vs Official Mojang Launcher

The important distinctions are these:

  • Game version matters more than launcher. Java 26.1 moved player files from the old playerdata location to players/data, and level.dat now references the singleplayer UUID instead of containing the old Player tag. The guide should explicitly say it is for Java 26.1+ and should not be followed unchanged for 1.21.x or older worlds. (Minecraft.net)
  • The official macOS default directory is the same: ~/Library/Application Support/minecraft/saves (Minecraft.net)
  • Official-launcher installations may use different installation directories, so readers should locate the actual installation folder rather than blindly assume the default. Mojang’s launcher exposes the relevant folder through the Installations screen. (Minecraft.net)
  • Commands may work on the official launcher. Java Edition supports enabling commands through world options or Open to LAN, so /gamemode creative may be a simpler first attempt. That said, opening to LAN can resume simulation while the player is burning, and it failed entirely in your tested setup, so the offline NBT route remains valuable. (Minecraft.net)
  • The .dat_old synchronization should be described as a tested compatibility workaround, not a confirmed TLauncher defect or a universal Mojang requirement. We observed that copying the validated edit into both files made it work, but we did not prove exactly why the first edit was ignored.
  • The guide should clearly exclude Bedrock, Realms, and multiplayer servers whose files the reader does not control.

Download the revised launcher-neutral guide

Rescue a Minecraft Java 26.1+ Player Stuck in Nether Lava on macOS

Scope and tested environment

  • Minecraft Java Edition 26.1 or newer
  • macOS
  • Python 3 with nbtlib==2.0.4
  • Tested end-to-end with TLauncher running Minecraft Java 26.2

The underlying rescue targets Minecraft Java's world and player NBT format, not a TLauncher-only format. It should therefore also apply to the official Minecraft Launcher when it runs the same Java Edition world version, but the official-launcher path has not been tested end-to-end in this exact incident.

Minecraft Java 26.1 changed player storage to players/data/<UUID>.dat and changed level.dat to reference the singleplayer UUID. This guide should not be followed unchanged for Java 26.0, 1.21.x, or older worlds, which use the older save layout.

The official launcher normally uses the same macOS saves directory shown here:

$HOME/Library/Application Support/minecraft/saves

A launcher installation can use a custom game directory, so locate the actual installation/world directory before running commands.

Commands-first note: official Java Edition supports enabling commands through world options or the Open to LAN interface. Try that simpler route only when it can be done safely. In the tested TLauncher setup, /gamemode creative and /gamerule keepInventory true remained unavailable, so the offline NBT method below was used instead.

This guide is for a local singleplayer Java world. It does not apply directly to Bedrock Edition, Realms, or a multiplayer server whose files you do not control.

Back up everything before editing.


Official launcher versus TLauncher

Most of the procedure is identical because Minecraft itself writes the world data:

Area Official Minecraft Launcher TLauncher or another third-party launcher
Java 26.1+ player path players/data/<UUID>.dat Same game-format path
Default macOS game directory $HOME/Library/Application Support/minecraft Often the same, but may be configured differently
NBT script Same Same
Full-world backups Same Same
Python and nbtlib Same Same
Player UUID Normally tied to the authenticated profile May differ from the UUID expected from an online username lookup
In-game commands Often available after enabling Allow Commands May work, may differ by profile/version/setup
Java installed in Terminal Irrelevant to this Python script Irrelevant to this Python script

Do not calculate or guess the UUID from a username. Inspect the actual files in the world and use the UUID filename Minecraft is currently saving.

The important distinctions are:

  1. Game version: this exact path is for Java 26.1+.
  2. Actual game directory: do not assume every launcher profile uses the default location.
  3. Singleplayer ownership: local NBT editing works only when you control the world files.
  4. Command availability: commands may make the rescue easier, but the NBT route does not depend on them.

What happened

The player fell into lava in the Nether while carrying valuable armor, tools, and other items.

The game was exited before the player died, so the inventory and player state were still present in the save data. The goal was to:

  1. Preserve the original world and player files.
  2. Temporarily change the player to Creative mode and make them invulnerable.
  3. Load the world and fly out of the lava.
  4. Move the inventory into a chest as an extra precaution.
  5. Save and quit normally.
  6. Edit the player back to Survival mode.
  7. Reopen the world and retrieve the items from the chest.

The critical discovery was that changing only the main .dat file was not enough in this setup. Minecraft appeared to use or restore the .dat_old fallback file. The successful approach was to make the edited .dat and .dat_old files identical before reopening the world.


Safety rules

Follow these throughout the process:

  • Keep Minecraft and the launcher completely closed while editing save files.
  • Never edit the only copy of a world.
  • Make a full-world backup before doing anything.
  • Let the Python script make a separate player-file backup before each modification.
  • After preserving both originals, copy the edited .dat over .dat_old before reopening the world. This was required in the tested setup and also prevents the fallback from undoing the rescue.
  • Verify matching SHA-256 hashes.
  • Save and quit through Minecraft normally after reaching safety.
  • Do not force-quit Minecraft while the world is open.
  • Avoid editing Inventory, Pos, or Dimension unless absolutely necessary.
  • Do not delete any backup until the rescue has been fully verified.

World and player-save layout

Java 26.1 and newer

The tested world was stored under:

$HOME/Library/Application Support/minecraft/saves/Feb2026

The active player file was:

$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat

The fallback file was:

$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat_old

Replace Feb2026 and the UUID with the values from your own world.

Older Java versions

Do not blindly substitute the older path into the rest of this guide.

Before Java 26.1, player storage used the older playerdata directory, and singleplayer data could also be represented through the Player data in level.dat. The 26.1 storage migration changed both the directory layout and how level.dat identifies the singleplayer character.

For a Java 26.0, 1.21.x, or older world, use a version-specific NBT guide or first upgrade a copy of the world. Never open the only copy in a different game version merely to make this tutorial fit.


Part 1: Back up the entire world

Close Minecraft and whichever launcher you use first.

cd "$HOME/Library/Application Support/minecraft"

Create a ZIP backup on the Desktop:

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-before-lava.zip"

Putting the backup outside the saves folder prevents Minecraft from listing it as another playable world.

Confirm the backup exists:

ls -lh "$HOME/Desktop/Feb2026-before-lava.zip"

Part 2: Locate the player file

These commands assume Java 26.1+.

List player .dat files:

find "saves/Feb2026/players/data" \
  -maxdepth 1 \
  -type f \
  -name '*.dat' \
  -print

Inspect modification times:

ls -laht "saves/Feb2026/players/data"

In a singleplayer world with one active player, there may be only one UUID .dat file.

Example:

saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat

Do not derive the UUID from a username lookup. Use the filename actually present in the world. This is especially important with third-party or offline profiles, but inspecting the save is the safer approach with any launcher.


Part 3: Prepare Python and install nbtlib

Create an isolated virtual environment:

python3 -m venv "$HOME/.venvs/minecraft-rescue"

Activate it:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Install the required package:

python -m pip install 'nbtlib==2.0.4'

Java is not used by this script. The installed Java version does not affect the NBT edit.


Part 4: Create the rescue script

Save the following as:

$HOME/Desktop/rescue_minecraft_player.py
#!/usr/bin/env python3

from __future__ import annotations

import argparse
import shutil
from datetime import datetime
from pathlib import Path

import nbtlib
from nbtlib.tag import Byte, Compound, Double, Float, Int, List, Short


def set_numeric_tag(
    compound: Compound,
    name: str,
    value: int | float,
    default_type: type,
) -> None:
    """Preserve the existing NBT numeric type when possible."""
    current_value = compound.get(name)

    if current_value is not None:
        try:
            compound[name] = type(current_value)(value)
            return
        except (TypeError, ValueError):
            pass

    compound[name] = default_type(value)


def ensure_compound(parent: Compound, name: str) -> Compound:
    current_value = parent.get(name)

    if isinstance(current_value, Compound):
        return current_value

    new_compound = Compound()
    parent[name] = new_compound
    return new_compound


def describe_player(player_data: Compound) -> None:
    position = player_data.get("Pos")
    dimension = player_data.get("Dimension")
    health = player_data.get("Health")
    fire = player_data.get("Fire")
    game_type = player_data.get("playerGameType")
    inventory = player_data.get("Inventory", [])

    print(f"Dimension: {dimension}")
    print(f"Position:  {position}")
    print(f"Health:    {health}")
    print(f"Fire:      {fire}")
    print(f"Game type: {game_type}")
    print(f"Inventory entries: {len(inventory)}")


def apply_rescue(player_data: Compound) -> None:
    # Restore basic survival state before loading the world.
    set_numeric_tag(player_data, "Health", 20.0, Float)
    set_numeric_tag(player_data, "Fire", 0, Short)
    set_numeric_tag(player_data, "Air", 300, Short)
    set_numeric_tag(player_data, "HurtTime", 0, Short)
    set_numeric_tag(player_data, "DeathTime", 0, Short)

    # Different versions may use one of these field names.
    if "FallDistance" in player_data:
        set_numeric_tag(player_data, "FallDistance", 0.0, Float)

    if "fall_distance" in player_data:
        set_numeric_tag(player_data, "fall_distance", 0.0, Float)

    # Creative mode plus explicit invulnerability and flight abilities.
    player_data["playerGameType"] = Int(1)
    player_data["Invulnerable"] = Byte(1)

    abilities = ensure_compound(player_data, "abilities")
    abilities["invulnerable"] = Byte(1)
    abilities["mayfly"] = Byte(1)
    abilities["flying"] = Byte(1)
    abilities["instabuild"] = Byte(1)
    abilities["mayBuild"] = Byte(1)

    # Remove existing momentum so the player does not continue sinking or falling.
    player_data["Motion"] = List[Double](
        [
            Double(0.0),
            Double(0.0),
            Double(0.0),
        ]
    )


def apply_survival(player_data: Compound) -> None:
    player_data["playerGameType"] = Int(0)
    player_data["Invulnerable"] = Byte(0)

    abilities = ensure_compound(player_data, "abilities")
    abilities["invulnerable"] = Byte(0)
    abilities["mayfly"] = Byte(0)
    abilities["flying"] = Byte(0)
    abilities["instabuild"] = Byte(0)
    abilities["mayBuild"] = Byte(1)

    set_numeric_tag(player_data, "Fire", 0, Short)


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Temporarily rescue a Minecraft player using offline NBT edits."
    )
    parser.add_argument(
        "player_file",
        type=Path,
        help="Path to players/data/<uuid>.dat",
    )
    parser.add_argument(
        "mode",
        choices=("inspect", "rescue", "survival"),
        help="Inspect, enter temporary Creative rescue mode, or return to Survival.",
    )
    args = parser.parse_args()

    player_file: Path = args.player_file.expanduser().resolve()

    if not player_file.is_file():
        raise SystemExit(f"Player file does not exist: {player_file}")

    player_nbt = nbtlib.load(player_file)

    print("Before:")
    describe_player(player_nbt)
    print()

    if args.mode == "inspect":
        return

    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_file = player_file.with_name(
        f"{player_file.name}.backup-{timestamp}"
    )
    shutil.copy2(player_file, backup_file)
    print(f"Backup: {backup_file}")

    if args.mode == "rescue":
        apply_rescue(player_nbt)
    else:
        apply_survival(player_nbt)

    player_nbt.save()

    # Reopen the written file to verify that it is still valid NBT.
    verified_nbt = nbtlib.load(player_file)

    print()
    print("After:")
    describe_player(verified_nbt)
    print()
    print("NBT save verified successfully.")


if __name__ == "__main__":
    main()

Make it executable:

chmod +x "$HOME/Desktop/rescue_minecraft_player.py"

Confirm that macOS recognizes it as a Python script:

file "$HOME/Desktop/rescue_minecraft_player.py"

Expected output resembles:

Python script text executable, ASCII text

Part 5: Define reusable paths

Set the player directory, UUID, and active player file:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"

These shell variables last only for the current Terminal session.


Part 6: Inspect the current player state

Activate the Python environment if necessary:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Inspect the player:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Example output before rescue:

Before:
Dimension: minecraft:the_nether
Position:  List[Double]([Double(-10.8255), Double(28.0544), Double(22.6445)])
Health:    Float(17.9072)
Fire:      Short(300)
Game type: Int(0)
Inventory entries: 22

Interpretation:

  • minecraft:the_nether confirms the player is in the Nether.
  • Fire: 300 confirms the player is burning.
  • Game type: 0 means Survival.
  • A nonzero inventory count confirms that inventory data still exists.

The script does not print item names. It only reports the number of inventory entries.


Part 7: Make absolutely sure Minecraft is closed

This applies to the official launcher and third-party launchers alike. A running game process can overwrite an offline edit.

Check for running processes:

pgrep -ifl 'minecraft|java|tlauncher'

If Minecraft or the launcher is still running, close it normally.

If necessary:

pkill -if 'minecraft|tlauncher'

Be careful with broad java process matching if other Java applications are running.

A nonzero shell status from pkill may simply mean no matching process was found.


Part 8: Apply temporary Creative rescue mode

Run:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  rescue

Expected changes:

Health:    Float(20.0)
Fire:      Short(0)
Game type: Int(1)

The inventory count should remain unchanged.

The script also creates a timestamped player-file backup, for example:

bd3ea752-cf3a-472e-8e50-388d038802d5.dat.backup-20260803-144401

Critical step: replace .dat_old

Copy the edited file over the fallback file:

cp -p \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Verify both files are byte-for-byte identical:

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

The two hashes must match.

Example:

6e4553cd...  .../bd3ea752-cf3a-472e-8e50-388d038802d5.dat
6e4553cd...  .../bd3ea752-cf3a-472e-8e50-388d038802d5.dat_old

This was the step that made the rescue work reliably in the tested setup.


Part 9: Launch the world and escape the lava

Launch the same launcher profile, player identity, game directory, and Minecraft version used by the world.

Open the world.

The player should load in Creative mode with:

  • Full health
  • Fire cleared
  • Flight enabled
  • Inventory still present
  • Existing momentum stopped

Immediately:

  1. Double-tap Space to begin flying.
  2. Fly vertically out of the lava.
  3. Move to a safe solid platform.
  4. Stay away from lava edges, fire, hostile mobs, and open drops.
  5. Preferably move near an existing chest or place one.

If the player still loads in Survival, exit immediately and verify that .dat and .dat_old have matching hashes.


Part 10: Put valuable inventory into a chest

Once safely out of the lava, put all important items into a chest:

  • Armor
  • Weapons
  • Tools
  • Enchanted items
  • Rare materials
  • Anything difficult to replace

This is not strictly required, but it separates the item rescue from the player-state edit.

After the items are in a chest, the player file may report:

Inventory entries: 0

That is expected. The items are now stored in the world/chunk data associated with the chest rather than in the player NBT.

Do not place items into the Creative inventory destroy slot.


Part 11: Save and quit normally

While standing safely:

Esc → Save and Quit to Title

Then close Minecraft and TLauncher completely.

Do not force-quit while the world is open.

This normal save records:

  • The new safe player position
  • The Creative player state
  • The chest contents
  • The world changes

Part 12: Back up the successful Creative rescue state

Create a second full-world backup:

cd "$HOME/Library/Application Support/minecraft"

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-safe-in-creative.zip"

This backup is especially valuable because it contains:

  • The player safely out of the lava
  • The items stored in a chest
  • The world saved normally
  • The player still in Creative mode

If anything fails while returning to Survival, restore this backup instead of returning all the way to the original lava state.


Part 13: Inspect the newly saved safe position

Re-establish the shell variables if this is a new Terminal session:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"

Activate the environment:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Inspect:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Example safe-state output:

Before:
Dimension: minecraft:the_nether
Position:  List[Double]([Double(-5.6906), Double(57.0), Double(41.2366)])
Health:    Float(20.0)
Fire:      Short(-20)
Game type: Int(1)
Inventory entries: 0

Confirm:

  • The coordinates are different from the original lava coordinates.
  • Game type is 1.
  • Health is full.
  • The inventory count matches what you expect after moving items into a chest.

A negative Fire value is not inherently a problem. The Survival conversion resets it to 0.


Part 14: Change the player back to Survival

With Minecraft still closed:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  survival

Expected output:

Before:
Game type: Int(1)

After:
Game type: Int(0)
Fire:      Short(0)

The script does not modify:

  • Inventory
  • Pos
  • Dimension
  • Experience
  • Experience level
  • Chest contents

It only changes the relevant game-mode, invulnerability, flight, building, and fire fields.

Again, the script creates a timestamped backup before writing.


Part 15: Replace .dat_old again

Copy the final Survival player file over the fallback:

cp -p \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Verify matching hashes:

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Both hashes must match.

Inspect one final time:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Expected state:

Game type: Int(0)
Fire:      Short(0)

The safe coordinates should remain unchanged.


Part 16: Reopen the world and retrieve the chest contents

Launch Minecraft and open the world.

You should now load:

  • In Survival
  • At the safe location
  • Not burning
  • With the same XP level as before
  • With the rescued equipment still inside the chest

Open the chest and move the items back into your inventory and armor slots.

Once everything is confirmed, save and quit normally again.

Optionally create a final clean backup:

cd "$HOME/Library/Application Support/minecraft"

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-after-full-rescue.zip"

Roll back to the original player backup

If an edit goes wrong, keep Minecraft closed and restore a timestamped player backup.

Example variables:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
ORIGINAL="$PLAYER_DIR/$UUID.dat.backup-20260803-143513"

Preserve the failed current file:

cp -p \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat.failed-$(date +%Y%m%d-%H%M%S)"

Restore the backup to both active and fallback slots:

cp -p "$ORIGINAL" "$PLAYER_DIR/$UUID.dat"
cp -p "$ORIGINAL" "$PLAYER_DIR/$UUID.dat_old"

Verify all three hashes:

shasum -a 256 \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat_old" \
  "$ORIGINAL"

All hashes should match.

Inspect the restored player:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DIR/$UUID.dat" \
  inspect

Restore the entire world from a ZIP backup

Use this only if the world itself becomes damaged or the player-file backups are insufficient.

Keep Minecraft closed.

Move the damaged world aside:

cd "$HOME/Library/Application Support/minecraft/saves"

mv "Feb2026" "Feb2026-damaged-$(date +%Y%m%d-%H%M%S)"

Extract the backup:

ditto -x -k \
  "$HOME/Desktop/Feb2026-before-lava.zip" \
  "$HOME/Library/Application Support/minecraft/saves"

Because the archive was created with --keepParent, it should restore the Feb2026 directory itself.

Confirm:

ls -la \
  "$HOME/Library/Application Support/minecraft/saves/Feb2026"

Why the first attempt may fail

In the tested TLauncher/Minecraft 26.2 setup, editing only:

<UUID>.dat

did not reliably change the loaded player state.

The exact internal reason was not proven. The observed behavior was consistent with the unedited fallback file being loaded, restored, or used during save recovery:

<UUID>.dat_old

Do not assume this is inherently a TLauncher bug. The fallback file is part of the Minecraft save, and behavior may vary by game version, crash state, save timing, or launcher setup.

Because the guide makes external ZIP and timestamped player backups first, synchronizing .dat_old to the validated edited .dat is an intentional compatibility measure rather than the only remaining backup.

The successful procedure was:

  1. Edit <UUID>.dat.
  2. Validate it with nbtlib.load().
  3. Copy it over <UUID>.dat_old.
  4. Verify matching SHA-256 hashes.
  5. Launch Minecraft only after both files match.

The same synchronization was done when returning from Creative to Survival.


Why not directly edit the inventory

Directly changing the inventory is riskier than changing game mode and abilities.

The rescue method deliberately avoids modifying:

Inventory

Instead:

  1. Preserve the inventory in the player file.
  2. Load in temporary Creative mode.
  3. Fly out of danger.
  4. Put the items into a chest.
  5. Save normally.
  6. Return the player to Survival offline.

This minimizes the number of NBT structures being changed.


Why use a chest before returning to Survival

A chest adds a separate recovery layer.

Before using a chest, the items depend on the player file being loaded and rewritten correctly.

After using a chest, the items are stored in world chunk data. Even if the player inventory becomes empty or the game-mode edit has a problem, the items remain in the saved chest.

That is why Inventory entries: 0 was expected after moving everything into the chest.


Troubleshooting

The player still loads in Survival

Keep Minecraft closed and verify:

shasum -a 256 \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat_old"

The hashes must match.

Then inspect:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Confirm:

Game type: Int(1)

If .dat says Creative but the game still loads Survival, verify that:

  • The world name is correct.
  • The UUID filename is correct.
  • The same TLauncher profile is being used.
  • Minecraft was fully closed during the edit.
  • No synchronization or backup tool restored the old save.

The player is still burning

The rescue script sets:

Fire: 0

It also sets full health and invulnerability.

If the game rewrites the file before launch, close everything and reapply the edit to both .dat and .dat_old.

The inventory count is zero before using a chest

Stop and restore a backup.

A zero inventory count before intentionally moving items into a chest may mean:

  • The wrong player UUID was selected.
  • The player file was already rewritten after death.
  • The wrong world was edited.
  • A launcher profile created a different player identity.

Do not continue until the correct player file is found.

The inventory count is zero after using a chest

That is expected if every item was moved into the chest.

Commands are unavailable in-game

Official Java Edition normally provides an Allow Commands option in world settings or while opening a world to LAN. When it works, a commands-based rescue is simpler:

/gamemode creative

After reaching safe ground:

/gamemode survival

Opening a world to LAN can cause the world simulation to continue, so this is not automatically safer when the player is already taking lava damage. Prepare the command before loading and do not waste time troubleshooting permissions while the player burns.

In the tested TLauncher/Minecraft 26.2 environment, /gamemode creative and /gamerule keepInventory true remained unavailable after attempting the LAN route. The offline NBT procedure does not require command permission.

A command failure does not itself alter or delete the inventory.

The shell says pkill returned status 1

That usually means no matching process was running. It is not necessarily an error.

nbtlib cannot load the file

Restore the latest timestamped player backup and verify that Minecraft is fully closed.

Do not repeatedly overwrite a file that no longer parses.


Cleanup

After the rescue is fully verified, the following may be removed later:

$HOME/.venvs/minecraft-rescue
$HOME/Desktop/rescue_minecraft_player.py

Do not remove world or player backups immediately. Keep at least:

Feb2026-before-lava.zip
Feb2026-safe-in-creative.zip
Feb2026-after-full-rescue.zip

The timestamped .dat.backup-* files can also be retained until the world has been played and saved successfully several times.


Condensed command checklist

Replace the world name and UUID first:

WORLD="Feb2026"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
MINECRAFT_DIR="$HOME/Library/Application Support/minecraft"
PLAYER_DIR="$MINECRAFT_DIR/saves/$WORLD/players/data"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"
SCRIPT="$HOME/Desktop/rescue_minecraft_player.py"

Back up:

cd "$MINECRAFT_DIR"

ditto -c -k --keepParent \
  "saves/$WORLD" \
  "$HOME/Desktop/$WORLD-before-lava.zip"

Inspect:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$SCRIPT" "$PLAYER_DAT" inspect

Apply Creative rescue:

python "$SCRIPT" "$PLAYER_DAT" rescue

cp -p "$PLAYER_DAT" "$PLAYER_DIR/$UUID.dat_old"

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Launch the world, fly to safety, put items in a chest, and save and quit normally.

Back up the safe Creative state:

cd "$MINECRAFT_DIR"

ditto -c -k --keepParent \
  "saves/$WORLD" \
  "$HOME/Desktop/$WORLD-safe-in-creative.zip"

Return to Survival:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$SCRIPT" "$PLAYER_DAT" survival

cp -p "$PLAYER_DAT" "$PLAYER_DIR/$UUID.dat_old"

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

python "$SCRIPT" "$PLAYER_DAT" inspect

Reopen the world and retrieve the items from the chest.


Final result from the tested rescue

The completed rescue preserved:

  • The original armor and tools
  • The original XP level
  • The player’s world progress
  • The player’s inventory, after temporarily moving it into a chest
  • The player’s safe new Nether position
  • Survival mode after the rescue

No direct inventory rewriting was required.


Official references

Rescue a Minecraft Java Player Stuck in Nether Lava by Editing Player NBT

Tested environment

  • macOS
  • TLauncher
  • Minecraft Java 26.2 using the newer players/data/<UUID>.dat player-save layout
  • Python 3 with nbtlib==2.0.4

This was tested successfully in a singleplayer world after the player fell into Nether lava and exited before dying.

Important limitation: opening the world to LAN and trying commands such as /gamemode creative or /gamerule keepInventory true did not work in this setup because cheats remained unavailable. The method below is an offline NBT-editing alternative.

This is not guaranteed to work on every Minecraft, launcher, modpack, or world version. Back up everything before editing.


What happened

The player fell into lava in the Nether while carrying valuable armor, tools, and other items.

The game was exited before the player died, so the inventory and player state were still present in the save data. The goal was to:

  1. Preserve the original world and player files.
  2. Temporarily change the player to Creative mode and make them invulnerable.
  3. Load the world and fly out of the lava.
  4. Move the inventory into a chest as an extra precaution.
  5. Save and quit normally.
  6. Edit the player back to Survival mode.
  7. Reopen the world and retrieve the items from the chest.

The critical discovery was that changing only the main .dat file was not enough in this setup. Minecraft appeared to use or restore the .dat_old fallback file. The successful approach was to make the edited .dat and .dat_old files identical before reopening the world.


Safety rules

Follow these throughout the process:

  • Keep Minecraft and TLauncher completely closed while editing save files.
  • Never edit the only copy of a world.
  • Make a full-world backup before doing anything.
  • Let the Python script make a separate player-file backup before each modification.
  • Copy the edited .dat over .dat_old before reopening the world.
  • Verify matching SHA-256 hashes.
  • Save and quit through Minecraft normally after reaching safety.
  • Do not force-quit Minecraft while the world is open.
  • Avoid editing Inventory, Pos, or Dimension unless absolutely necessary.
  • Do not delete any backup until the rescue has been fully verified.

World and player-save layout

The tested world was stored under:

$HOME/Library/Application Support/minecraft/saves/Feb2026

The active player file was:

$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat

The fallback file was:

$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat_old

Replace Feb2026 and the UUID with the values from your own world.


Part 1: Back up the entire world

Close Minecraft and TLauncher first.

cd "$HOME/Library/Application Support/minecraft"

Create a ZIP backup on the Desktop:

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-before-lava.zip"

Putting the backup outside the saves folder prevents Minecraft from listing it as another playable world.

Confirm the backup exists:

ls -lh "$HOME/Desktop/Feb2026-before-lava.zip"

Part 2: Locate the player file

List player .dat files:

find "saves/Feb2026/players/data" \
  -maxdepth 1 \
  -type f \
  -name '*.dat' \
  -print

Inspect modification times:

ls -laht "saves/Feb2026/players/data"

In a singleplayer world with one active player, there may be only one UUID .dat file.

Example:

saves/Feb2026/players/data/bd3ea752-cf3a-472e-8e50-388d038802d5.dat

Do not assume the UUID matches a Microsoft account UUID. TLauncher or offline profiles may use a different UUID. Use the filename actually present in the world.


Part 3: Prepare Python and install nbtlib

Create an isolated virtual environment:

python3 -m venv "$HOME/.venvs/minecraft-rescue"

Activate it:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Install the required package:

python -m pip install 'nbtlib==2.0.4'

Java is not used by this script. The installed Java version does not affect the NBT edit.


Part 4: Create the rescue script

Save the following as:

$HOME/Desktop/rescue_minecraft_player.py
#!/usr/bin/env python3

from __future__ import annotations

import argparse
import shutil
from datetime import datetime
from pathlib import Path

import nbtlib
from nbtlib.tag import Byte, Compound, Double, Float, Int, List, Short


def set_numeric_tag(
    compound: Compound,
    name: str,
    value: int | float,
    default_type: type,
) -> None:
    """Preserve the existing NBT numeric type when possible."""
    current_value = compound.get(name)

    if current_value is not None:
        try:
            compound[name] = type(current_value)(value)
            return
        except (TypeError, ValueError):
            pass

    compound[name] = default_type(value)


def ensure_compound(parent: Compound, name: str) -> Compound:
    current_value = parent.get(name)

    if isinstance(current_value, Compound):
        return current_value

    new_compound = Compound()
    parent[name] = new_compound
    return new_compound


def describe_player(player_data: Compound) -> None:
    position = player_data.get("Pos")
    dimension = player_data.get("Dimension")
    health = player_data.get("Health")
    fire = player_data.get("Fire")
    game_type = player_data.get("playerGameType")
    inventory = player_data.get("Inventory", [])

    print(f"Dimension: {dimension}")
    print(f"Position:  {position}")
    print(f"Health:    {health}")
    print(f"Fire:      {fire}")
    print(f"Game type: {game_type}")
    print(f"Inventory entries: {len(inventory)}")


def apply_rescue(player_data: Compound) -> None:
    # Restore basic survival state before loading the world.
    set_numeric_tag(player_data, "Health", 20.0, Float)
    set_numeric_tag(player_data, "Fire", 0, Short)
    set_numeric_tag(player_data, "Air", 300, Short)
    set_numeric_tag(player_data, "HurtTime", 0, Short)
    set_numeric_tag(player_data, "DeathTime", 0, Short)

    # Different versions may use one of these field names.
    if "FallDistance" in player_data:
        set_numeric_tag(player_data, "FallDistance", 0.0, Float)

    if "fall_distance" in player_data:
        set_numeric_tag(player_data, "fall_distance", 0.0, Float)

    # Creative mode plus explicit invulnerability and flight abilities.
    player_data["playerGameType"] = Int(1)
    player_data["Invulnerable"] = Byte(1)

    abilities = ensure_compound(player_data, "abilities")
    abilities["invulnerable"] = Byte(1)
    abilities["mayfly"] = Byte(1)
    abilities["flying"] = Byte(1)
    abilities["instabuild"] = Byte(1)
    abilities["mayBuild"] = Byte(1)

    # Remove existing momentum so the player does not continue sinking or falling.
    player_data["Motion"] = List[Double](
        [
            Double(0.0),
            Double(0.0),
            Double(0.0),
        ]
    )


def apply_survival(player_data: Compound) -> None:
    player_data["playerGameType"] = Int(0)
    player_data["Invulnerable"] = Byte(0)

    abilities = ensure_compound(player_data, "abilities")
    abilities["invulnerable"] = Byte(0)
    abilities["mayfly"] = Byte(0)
    abilities["flying"] = Byte(0)
    abilities["instabuild"] = Byte(0)
    abilities["mayBuild"] = Byte(1)

    set_numeric_tag(player_data, "Fire", 0, Short)


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Temporarily rescue a Minecraft player using offline NBT edits."
    )
    parser.add_argument(
        "player_file",
        type=Path,
        help="Path to players/data/<uuid>.dat",
    )
    parser.add_argument(
        "mode",
        choices=("inspect", "rescue", "survival"),
        help="Inspect, enter temporary Creative rescue mode, or return to Survival.",
    )
    args = parser.parse_args()

    player_file: Path = args.player_file.expanduser().resolve()

    if not player_file.is_file():
        raise SystemExit(f"Player file does not exist: {player_file}")

    player_nbt = nbtlib.load(player_file)

    print("Before:")
    describe_player(player_nbt)
    print()

    if args.mode == "inspect":
        return

    timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup_file = player_file.with_name(
        f"{player_file.name}.backup-{timestamp}"
    )
    shutil.copy2(player_file, backup_file)
    print(f"Backup: {backup_file}")

    if args.mode == "rescue":
        apply_rescue(player_nbt)
    else:
        apply_survival(player_nbt)

    player_nbt.save()

    # Reopen the written file to verify that it is still valid NBT.
    verified_nbt = nbtlib.load(player_file)

    print()
    print("After:")
    describe_player(verified_nbt)
    print()
    print("NBT save verified successfully.")


if __name__ == "__main__":
    main()

Make it executable:

chmod +x "$HOME/Desktop/rescue_minecraft_player.py"

Confirm that macOS recognizes it as a Python script:

file "$HOME/Desktop/rescue_minecraft_player.py"

Expected output resembles:

Python script text executable, ASCII text

Part 5: Define reusable paths

Set the player directory, UUID, and active player file:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"

These shell variables last only for the current Terminal session.


Part 6: Inspect the current player state

Activate the Python environment if necessary:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Inspect the player:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Example output before rescue:

Before:
Dimension: minecraft:the_nether
Position:  List[Double]([Double(-10.8255), Double(28.0544), Double(22.6445)])
Health:    Float(17.9072)
Fire:      Short(300)
Game type: Int(0)
Inventory entries: 22

Interpretation:

  • minecraft:the_nether confirms the player is in the Nether.
  • Fire: 300 confirms the player is burning.
  • Game type: 0 means Survival.
  • A nonzero inventory count confirms that inventory data still exists.

The script does not print item names. It only reports the number of inventory entries.


Part 7: Make absolutely sure Minecraft is closed

Check for running processes:

pgrep -ifl 'minecraft|java|tlauncher'

If Minecraft or TLauncher is still running, close it normally.

If necessary:

pkill -if 'minecraft|tlauncher'

Be careful with broad java process matching if other Java applications are running.

A nonzero shell status from pkill may simply mean no matching process was found.


Part 8: Apply temporary Creative rescue mode

Run:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  rescue

Expected changes:

Health:    Float(20.0)
Fire:      Short(0)
Game type: Int(1)

The inventory count should remain unchanged.

The script also creates a timestamped player-file backup, for example:

bd3ea752-cf3a-472e-8e50-388d038802d5.dat.backup-20260803-144401

Critical step: replace .dat_old

Copy the edited file over the fallback file:

cp -p \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Verify both files are byte-for-byte identical:

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

The two hashes must match.

Example:

6e4553cd...  .../bd3ea752-cf3a-472e-8e50-388d038802d5.dat
6e4553cd...  .../bd3ea752-cf3a-472e-8e50-388d038802d5.dat_old

This was the step that made the rescue work reliably in the tested setup.


Part 9: Launch the world and escape the lava

Launch the same TLauncher profile and Minecraft version used by the world.

Open the world.

The player should load in Creative mode with:

  • Full health
  • Fire cleared
  • Flight enabled
  • Inventory still present
  • Existing momentum stopped

Immediately:

  1. Double-tap Space to begin flying.
  2. Fly vertically out of the lava.
  3. Move to a safe solid platform.
  4. Stay away from lava edges, fire, hostile mobs, and open drops.
  5. Preferably move near an existing chest or place one.

If the player still loads in Survival, exit immediately and verify that .dat and .dat_old have matching hashes.


Part 10: Put valuable inventory into a chest

Once safely out of the lava, put all important items into a chest:

  • Armor
  • Weapons
  • Tools
  • Enchanted items
  • Rare materials
  • Anything difficult to replace

This is not strictly required, but it separates the item rescue from the player-state edit.

After the items are in a chest, the player file may report:

Inventory entries: 0

That is expected. The items are now stored in the world/chunk data associated with the chest rather than in the player NBT.

Do not place items into the Creative inventory destroy slot.


Part 11: Save and quit normally

While standing safely:

Esc → Save and Quit to Title

Then close Minecraft and TLauncher completely.

Do not force-quit while the world is open.

This normal save records:

  • The new safe player position
  • The Creative player state
  • The chest contents
  • The world changes

Part 12: Back up the successful Creative rescue state

Create a second full-world backup:

cd "$HOME/Library/Application Support/minecraft"

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-safe-in-creative.zip"

This backup is especially valuable because it contains:

  • The player safely out of the lava
  • The items stored in a chest
  • The world saved normally
  • The player still in Creative mode

If anything fails while returning to Survival, restore this backup instead of returning all the way to the original lava state.


Part 13: Inspect the newly saved safe position

Re-establish the shell variables if this is a new Terminal session:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"

Activate the environment:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

Inspect:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Example safe-state output:

Before:
Dimension: minecraft:the_nether
Position:  List[Double]([Double(-5.6906), Double(57.0), Double(41.2366)])
Health:    Float(20.0)
Fire:      Short(-20)
Game type: Int(1)
Inventory entries: 0

Confirm:

  • The coordinates are different from the original lava coordinates.
  • Game type is 1.
  • Health is full.
  • The inventory count matches what you expect after moving items into a chest.

A negative Fire value is not inherently a problem. The Survival conversion resets it to 0.


Part 14: Change the player back to Survival

With Minecraft still closed:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  survival

Expected output:

Before:
Game type: Int(1)

After:
Game type: Int(0)
Fire:      Short(0)

The script does not modify:

  • Inventory
  • Pos
  • Dimension
  • Experience
  • Experience level
  • Chest contents

It only changes the relevant game-mode, invulnerability, flight, building, and fire fields.

Again, the script creates a timestamped backup before writing.


Part 15: Replace .dat_old again

Copy the final Survival player file over the fallback:

cp -p \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Verify matching hashes:

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Both hashes must match.

Inspect one final time:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Expected state:

Game type: Int(0)
Fire:      Short(0)

The safe coordinates should remain unchanged.


Part 16: Reopen the world and retrieve the chest contents

Launch Minecraft and open the world.

You should now load:

  • In Survival
  • At the safe location
  • Not burning
  • With the same XP level as before
  • With the rescued equipment still inside the chest

Open the chest and move the items back into your inventory and armor slots.

Once everything is confirmed, save and quit normally again.

Optionally create a final clean backup:

cd "$HOME/Library/Application Support/minecraft"

ditto -c -k --keepParent \
  "saves/Feb2026" \
  "$HOME/Desktop/Feb2026-after-full-rescue.zip"

Roll back to the original player backup

If an edit goes wrong, keep Minecraft closed and restore a timestamped player backup.

Example variables:

PLAYER_DIR="$HOME/Library/Application Support/minecraft/saves/Feb2026/players/data"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
ORIGINAL="$PLAYER_DIR/$UUID.dat.backup-20260803-143513"

Preserve the failed current file:

cp -p \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat.failed-$(date +%Y%m%d-%H%M%S)"

Restore the backup to both active and fallback slots:

cp -p "$ORIGINAL" "$PLAYER_DIR/$UUID.dat"
cp -p "$ORIGINAL" "$PLAYER_DIR/$UUID.dat_old"

Verify all three hashes:

shasum -a 256 \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat_old" \
  "$ORIGINAL"

All hashes should match.

Inspect the restored player:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DIR/$UUID.dat" \
  inspect

Restore the entire world from a ZIP backup

Use this only if the world itself becomes damaged or the player-file backups are insufficient.

Keep Minecraft closed.

Move the damaged world aside:

cd "$HOME/Library/Application Support/minecraft/saves"

mv "Feb2026" "Feb2026-damaged-$(date +%Y%m%d-%H%M%S)"

Extract the backup:

ditto -x -k \
  "$HOME/Desktop/Feb2026-before-lava.zip" \
  "$HOME/Library/Application Support/minecraft/saves"

Because the archive was created with --keepParent, it should restore the Feb2026 directory itself.

Confirm:

ls -la \
  "$HOME/Library/Application Support/minecraft/saves/Feb2026"

Why the first attempt may fail

In the tested setup, editing only:

<UUID>.dat

did not reliably change the loaded player state.

The likely cause was Minecraft loading, restoring, or otherwise preferring the fallback:

<UUID>.dat_old

The successful procedure was:

  1. Edit <UUID>.dat.
  2. Validate it with nbtlib.load().
  3. Copy it over <UUID>.dat_old.
  4. Verify matching SHA-256 hashes.
  5. Launch Minecraft only after both files match.

The same synchronization was done when returning from Creative to Survival.


Why not directly edit the inventory

Directly changing the inventory is riskier than changing game mode and abilities.

The rescue method deliberately avoids modifying:

Inventory

Instead:

  1. Preserve the inventory in the player file.
  2. Load in temporary Creative mode.
  3. Fly out of danger.
  4. Put the items into a chest.
  5. Save normally.
  6. Return the player to Survival offline.

This minimizes the number of NBT structures being changed.


Why use a chest before returning to Survival

A chest adds a separate recovery layer.

Before using a chest, the items depend on the player file being loaded and rewritten correctly.

After using a chest, the items are stored in world chunk data. Even if the player inventory becomes empty or the game-mode edit has a problem, the items remain in the saved chest.

That is why Inventory entries: 0 was expected after moving everything into the chest.


Troubleshooting

The player still loads in Survival

Keep Minecraft closed and verify:

shasum -a 256 \
  "$PLAYER_DIR/$UUID.dat" \
  "$PLAYER_DIR/$UUID.dat_old"

The hashes must match.

Then inspect:

python "$HOME/Desktop/rescue_minecraft_player.py" \
  "$PLAYER_DAT" \
  inspect

Confirm:

Game type: Int(1)

If .dat says Creative but the game still loads Survival, verify that:

  • The world name is correct.
  • The UUID filename is correct.
  • The same TLauncher profile is being used.
  • Minecraft was fully closed during the edit.
  • No synchronization or backup tool restored the old save.

The player is still burning

The rescue script sets:

Fire: 0

It also sets full health and invulnerability.

If the game rewrites the file before launch, close everything and reapply the edit to both .dat and .dat_old.

The inventory count is zero before using a chest

Stop and restore a backup.

A zero inventory count before intentionally moving items into a chest may mean:

  • The wrong player UUID was selected.
  • The player file was already rewritten after death.
  • The wrong world was edited.
  • A launcher profile created a different player identity.

Do not continue until the correct player file is found.

The inventory count is zero after using a chest

That is expected if every item was moved into the chest.

Commands are unavailable in-game

In the tested environment, /gamemode creative and /gamerule keepInventory true were unavailable even after attempting the LAN-cheats route.

The offline NBT procedure does not require in-game command permission.

The shell says pkill returned status 1

That usually means no matching process was running. It is not necessarily an error.

nbtlib cannot load the file

Restore the latest timestamped player backup and verify that Minecraft is fully closed.

Do not repeatedly overwrite a file that no longer parses.


Cleanup

After the rescue is fully verified, the following may be removed later:

$HOME/.venvs/minecraft-rescue
$HOME/Desktop/rescue_minecraft_player.py

Do not remove world or player backups immediately. Keep at least:

Feb2026-before-lava.zip
Feb2026-safe-in-creative.zip
Feb2026-after-full-rescue.zip

The timestamped .dat.backup-* files can also be retained until the world has been played and saved successfully several times.


Condensed command checklist

Replace the world name and UUID first:

WORLD="Feb2026"
UUID="bd3ea752-cf3a-472e-8e50-388d038802d5"
MINECRAFT_DIR="$HOME/Library/Application Support/minecraft"
PLAYER_DIR="$MINECRAFT_DIR/saves/$WORLD/players/data"
PLAYER_DAT="$PLAYER_DIR/$UUID.dat"
SCRIPT="$HOME/Desktop/rescue_minecraft_player.py"

Back up:

cd "$MINECRAFT_DIR"

ditto -c -k --keepParent \
  "saves/$WORLD" \
  "$HOME/Desktop/$WORLD-before-lava.zip"

Inspect:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$SCRIPT" "$PLAYER_DAT" inspect

Apply Creative rescue:

python "$SCRIPT" "$PLAYER_DAT" rescue

cp -p "$PLAYER_DAT" "$PLAYER_DIR/$UUID.dat_old"

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

Launch the world, fly to safety, put items in a chest, and save and quit normally.

Back up the safe Creative state:

cd "$MINECRAFT_DIR"

ditto -c -k --keepParent \
  "saves/$WORLD" \
  "$HOME/Desktop/$WORLD-safe-in-creative.zip"

Return to Survival:

source "$HOME/.venvs/minecraft-rescue/bin/activate"

python "$SCRIPT" "$PLAYER_DAT" survival

cp -p "$PLAYER_DAT" "$PLAYER_DIR/$UUID.dat_old"

shasum -a 256 \
  "$PLAYER_DAT" \
  "$PLAYER_DIR/$UUID.dat_old"

python "$SCRIPT" "$PLAYER_DAT" inspect

Reopen the world and retrieve the items from the chest.


Final result from the tested rescue

The completed rescue preserved:

  • The original armor and tools
  • The original XP level
  • The player’s world progress
  • The player’s inventory, after temporarily moving it into a chest
  • The player’s safe new Nether position
  • Survival mode after the rescue

No direct inventory rewriting was required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment