Skip to content

A simple tool to remove unused chunks from Minecraft worlds, freeing disk space. || Maybe a Java implementation of Thanos.

License

Notifications You must be signed in to change notification settings

Bottle-M/PotatoPeeler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PotatoPeeler

Peeling Potato

Lang: English | 简体中文

A simple tool to remove unused chunks from Minecraft worlds(Java Edition), freeing disk space.

  • Maybe a Java implementation of Thanos.

  • Currently only supports the Anvil file format (since Minecraft JE 1.2.1).

  • In some cases, disk space occupied by the worlds can be reduced by over 50%.

  • Supports configuring protected chunks for each world using chunk coordinates and chunk coordinate ranges (wildcard * supported), preventing certain chunks from being removed.

1. How It Works

Chunks are stored within the Anvil file, and Minecraft Java Edition stores a field InhabitedTime for each chunk, which records the cumulative time ticks that players have spent within that chunk.

This tool finds out chunks where players have barely stayed by examining the InhabitedTime value, and then removes them. It can be used on both local game worlds and server worlds.

The InhabitedTime of a chunk increases as long as a player is within the "mob spawn distance"Doc of that chunk. Therefore, the InhabitedTime of chunks around the player's current chunk often increases as well.

2. Important Notes Before Use

  1. If you are using a Paper server or a server based on Paper (such as Purpur), DO NOT set the fixed-chunk-inhabited-timeDoc key in the Paper World Configuration file to a value $\ge 0$, as this will fix the InhabitedTime of the chunks, thereby affecting the functionality of the tool.

  2. If your world is created or edited by mods / external softwares rather than manual construction by players, the InhabitedTime values of the chunks may be unpredictable, and it's not recommended to use this tool in such cases.

    Of course, you can configure protected chunks to prevent certain chunks from being removed.

  3. This tool performs in-place operations on the region Anvil files, the changes will firstly be written to a temporary file and then replace the original file. It is still advisable to occasionally make backups.

3. Installation

  1. You should have already installed the corresponding version of JRE (Java Runtime Environment). For details, refer to this document.
  2. Download the PotatoPeeler*.jar from Releases according to your Java version, and place it in a suitable location (such as the root directory of your Minecraft Server).

4. Usage

You can run this tool from the command line:

java [jvmOptions...] -jar PotatoPeeler*.jar 
    [--world-dirs <worldPath1>,<worldPath2>,...]
    [--server-jar <serverJarPath>]
    [--min-inhabited <ticks>]
    [--help]
    [--cool-down <minutes>]
    [--threads-num <number>]
    [--verbose]
    [--skip-peeler]
    [additionalOptions...]
Flag Description
--help Displays help information
--verbose Outputs detailed information to the log
--skip-peeler Skips chunk processing, no chunks will be removed. If the --server-jar parameter is specified, it will directly launch the Minecraft server
Parameter Default Value Description
--world-dirs Comma-separated paths to Minecraft Worlds.

* For example, /opt/server/world,world_nether specifies two world directories, one with an absolute path and the other with a relative path. The program will process these worlds one by one.
--min-inhabited 0 The InhabitedTime threshold for chunks (in ticks, 20 ticks = 1 second).

* A chunk with an InhabitedTime less than or equal to this value, and not protectedSee below, will be removed.
* For example, if you want to remove chunks where players have stayed for $\le 5$ seconds, set this to 100.
* It is not recommended to set this value to be $\gt 200$, the program will print a warning at startup if exceeded.
* The default value of 0 is already useful in most cases.
--cool-down 0 The amount of time that must wait for since the last chunk processing before this tool can be used again (in minutes).

* Note that the timer starts after the last chunk processing for all specified worlds has been completed. For example, if the --skip-peeler flag is used to skip chunk processing, it will not count toward this cooldown.
--threads-num 10 The number of threads to use for concurrent (and possibly parallel) processing of Anvil files in a world.
--server-jar The path to the Minecraft server jar file.

* If a valid jar file is specified, this tool will run the jar file in the current JVM after chunk processing, starting the server.
jvmOptions JVM options.

* If --server-jar is specified, these JVM options will be inherited by the server.
additionalOptions Remaining parameters.

* If --server-jar is specified, these parameters will be passed to the server.
  • Note 1: For the vanilla level format, you can specify the world dimensions like this: --world-dirs world,world/DIM1,world/DIM-1.

    In fact, this tool will search for the region directory using a breadth-first approach.

  • Note 2: If you prefer not to write parameters in the command line, you can create a file named potatopeeler.args in the working directory of PotatoPeeler*.jar and write all the command line parameters into this file (excluding JVM parameters).

    This tool will only read the potatopeeler.args file when no parameters are specified in the command line (excluding JVM parameters).

5. Protected Chunks

Protected chunks will not be removed and can be categorized into three types:

  1. Force-loaded chunks in the world (/forceload).
  2. Custom protected chunks.
  3. Chunks with excessive data.

5.1. Custom Protected Chunks

You can create a text file named chunks.protected in the dimension root directory (the same level as region) to specify chunks that you want to protect in this world.

Click to see an example of the file's location
world
├── DIM-1
│   ├── data
│   │   └── raids_end.dat
│   └── region
│       └── ...
├── DIM1
│   ├── data
│   │   └── raids_end.dat
│   ├── region
│   └── chunks.protected # Protected chunks in the End dimension
├── data
│   └── raids.dat
├── datapacks
├── entities
│   ├── r.-1.-1.mca
│   └── ...
│   
├── level.dat
├── level.dat_old
├── chunks.protected # Protected chunks in the Overworld dimension
├── playerdata
├── region
│   ├── r.-1.-1.mca 
│   ├── r.-1.0.mca
│   ├── r.0.-1.mca
│   └── r.0.0.mca
└── session.lock

Note: Non-vanilla servers may save dimensions like DIM-1, DIM1 in separate directories, commonly as world_nether/DIM-1, world_the_end/DIM1.

5.2. chunks.protected File Format

  1. Each line specifies a rule, which can be a single chunk coordinate like x,z, or a rectangular area like x1~x2,z1~z2.
  2. Wildcard * is supported. (For example, *~5,6 protects chunks in the area $x \in [-2^{31},5], z = 6$.)
  3. Starting with #, single-line and inline comments are both supported.

The coordinates mentioned above are chunk coordinates, which can be seen in the game by pressing F3:
Chunk Pos

Click to see an example of the file content
# Protect all chunks, the tool will remove no chunks in this world dimension.
*,*

*~*,* # The same as above.
*,*~*

# Protect a long strip area where x ranges from -5 to 5 and z = 6.
-5~5,6

# Protect a rectangular area where x ranges from -54 to 14 and z ranges from 7 to 77.
-54 ~ 14 ,  7    ~  77 # Loose spacing is OK

# It doesn't matter if the num on the left is bigger or smaller than the num on the right.
1~4, 18~9   # Protect a rectangular area where x ranges from 1 to 4 and z ranges from 9 to 18.

# Protect a single chunk.
12 , 450

6. Logs

All logs output to the console will also be saved in the peeler_logs subdirectory of the tool's working directory.

7. Examples

7.1. Using as a Standalone Tool

# Remove chunks with a total player stay time <= 5 seconds from the specified three worlds
java -jar PotatoPeeler*.jar --min-inhabited 100 --world-dirs world,world_nether,/opt/server/world_the_end

# Or it can be simpler, just specify the world paths. By default, only chunks with a total player stay time = 0 seconds will be removed
java -jar PotatoPeeler*.jar --world-dirs world,world_nether,/opt/server/world_the_end

7.2. Using as a Server Wrapper

# Remove chunks with a total player stay time <= 5 seconds from the specified two worlds
# After removal, purpur.jar will be started in the current JVM
# JVM options -Xms1G -Xmx4G will be inherited
# Additional parameters/flags --nogui --forceUpgrade will be passed to purpur.jar
java -Xms1G -Xmx4G -jar PotatoPeeler*.jar --min-inhabited 100 --world-dirs world,world_nether --server-jar purpur.jar --nogui --forceUpgrade

7.3. Cleaning Chunks before Server Restart

You can set up a scheduled restart task for your server. For example, if you restart your server every day at 4 AM and you want to clean up unused chunks every 4 days, you can write a server startup script like this:

#!/bin/bash
# Use the --cool-down parameter to configure a cooldown period of 5760 minutes after each cleanup, which means cleaning unused chunks every 4 days
java -Xms1G -Xmx4G -jar PotatoPeeler*.jar --cool-down 5760 --world-dirs world,world_nether --server-jar purpur.jar --nogui

7.4. Cleaning Chunks in Local Game

java -jar PotatoPeeler*.jar --world-dirs 'C:\Users\Administrator\AppData\Roaming\.minecraft\saves\MyWorld'

7.5. Checking if Protected Chunks are Loaded Correctly

ProtectedChunksRead

For each world dimension, if there is a chunks.protected configuration file, the program will print to the console:

Protected chunks from <path of chunks.protected> have been read.

If the chunks.protected file has a format error and cannot be read, the program will print the erroneous line number and part of the content.

If there are force-loaded chunks in this world, it will print:

Force-loaded chunks read.

7.6. Importing Command Line Arguments from a File

Click to see this example

When no command line parameters are specified, the program will attempt to read parameters from the potatopeeler.args file.

You can write all command line parameters (excluding JVM parameters) into the potatopeeler.args file in the working directory of PotatoPeeler*.jar.

An example of the potatopeeler.args file is as follows:

--min-inhabited 100 --world-dirs world,world_nether,world_the_end --server-jar purpur.jar

Typically, we will place the potatopeeler.args and PotatoPeeler*.jar files in the same directory:

Server Root
├── PotatoPeeler-1.0.0.jar # PotatoPeeler
├── bukkit.yml
├── config
├── plugins
├── potatopeeler.args # Command line parameters
├── server.properties
├── spigot.yml
├── purpur.jar
├── whitelist.json
├── world
├── world_nether
└── world_the_end

Then simply execute java -jar PotatoPeeler*.jar, and the command line parameters will be automatically read from the potatopeeler.args file.

Open Source Libraries Used

Thanks to the hard work of open source developers!

References

  1. 区域文件格式 - Minecraft Wiki
  2. 强制加载区块存储格式 - Minecraft Wiki
  3. Java版存档格式 - Minecraft Wiki
  4. 区块存储格式 - Minecraft Wiki
  5. NBT 二进制格式 - Minecraft Wiki

License

This project is licensed under the MIT License.

Thanks for using it! o(* ̄▽ ̄*)o