File Details
claimmyland-neoforge-1.21.1-2.9.0.jar
- R
- May 5, 2026
- 864.29 KB
- 47
- 1.21.1
- NeoForge
File Name
claimmyland-neoforge-1.21.1-2.9.0.jar
Supported Versions
- 1.21.1
Curse Maven Snippet
Changelog for Claim My Land for Neoforge 1.21.1
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
⚠️ IMPORTANT — Breaking Change & Backup Warning
v2.x is not save-compatible with v1.x. Parcel data saved by any v1 release will not load in v2. If you are upgrading an existing world, your claimed parcels will be lost.
Back up your world before installing v2. Copy your entire world folder to a safe location before upgrading. Once you have loaded the world in v2, downgrading back to v1 is not supported.
💡 Recommended: Since this mod is heavily command-based, we recommend using 🔗 Chat Plus for a better command history and larger chat window.
Claim My Land — Changelog
[2.9.0] - 2026-05-04
🎉 Highlights
- Whitelist clear — every whitelist (player, block, block-tag, item, item-tag,
entity-spawn, entity-spawn-tag) now supports a
clearsubcommand with a confirmation prompt and an inline✘✘ Clear Allbutton at the bottom of every list display. - Backup load / list — restore parcel state from any rolling backup with
/cml-ops backup load <file>. Newlistsubcommand shows available backups. Inline✔ Confirmbutton drives the destructive replace. - Backup persistence rewrite — backups are now written to the world-specific
data directory (fixes single-player saves), serialized through a polymorphic
GSON
ParcelGsonbuilder so new parcel/estate fields are picked up automatically.
➕ Added
Whitelist clear subcommand (all 7 whitelist types)
/cml estate whitelist <type> clear <estateName>— owner version/cml-ops estate whitelist <type> clear <ownerName> <estateName>— ops version- Two-step destructive command: first invocation shows a confirmation prompt with
entry count and an inline
[✔ Confirm]button; the... clear ... confirmform performs the actual clear. - Idempotent: clearing an already-empty whitelist returns a "no change" message.
- Saves via
CommandHelper.save(level)after a successful clear. - New lang keys (per type):
estate.whitelist.clear.confirm/.body,estate.whitelist.clear.no_change/.body,estate.<type>.clear.success/.bodyforfriends,block,block_tag,item,item_tag,entity,entity_tag. - New
whitelistClearIcon/whitelistClearIconOps/whitelistClearConfirmIconhelpers inFormatterConstants; appended to every whitelist list display.
Backup management commands (ops-only)
/cml-ops backup— immediate on-demand save (existed in v2.5; reorganized)./cml-ops backup list— list available backup files (newest first)./cml-ops backup load <file>— show a confirmation prompt with an inline[✔ Confirm]button; tab completion suggests existing backup filenames./cml-ops backup load <file> confirm— clearEstateRegistryandParcelRegistry, repopulate from the backup (NATION parcels first so estates are registered before Citizen/Zone reference them), persist the restored state, and resync to all online players.- New lang keys:
backup.list,backup.list.empty,backup.load.confirm/.body,backup.load.not_found,backup.load.failure,backup.load.success/.body. - New class:
BackupSubCommand(split out ofOpsCommandad-hoc handling).
🐛 Fixed
Backup save directory was wrong for single-player worlds
- Root cause:
RollingJsonSaverwas constructed withnew File("world/data/claimmyland"), a relative path that resolved against the server working directory. In dedicated server this happened to land in the right place; in single-player it created a strayworld/folder next to the game launcher instead of writing to the active save. - Fix: capture the world's data path in
ServerStartingEventviaevent.getServer().getWorldPath(LevelResource.ROOT).resolve("data/claimmyland"), store it asClaimMyLand.serverDataPath, and rebuild theRollingJsonSaverfrom that path on startup and on config reload.
Backup restore corrupted parcel coordinates and crashed clients
- Root cause: the original field-by-field JSON loader assumed UUID was
serialized as
{mostSigBits, leastSigBits}; GSON actually writes UUIDs as hyphenated strings. Every UUID-bearing field silently failed to load, leavingownerIdnull.SyncParcelPacket.encode()then calledbuf.writeUUID(null)→ NPE → NettyEncoderException→ client kicked withFailed to encode packet 'clientbound/minecraft:custom_payload'. - Fix: replaced the hand-rolled loader with a polymorphic GSON builder
(
ParcelGson) that registers TypeAdapters forUUID,ICoords,Box,Parcel,Estate, andNationEstate.Parceldispatches to the concrete class viaParcelTypeRegistry.create(type).getClass();EstatechoosesEstateContextvsNationEstateContextby the presence of anaccessTypefield. SameGsoninstance is now used for both write and read, so any new field added to a parcel or estate is automatically round-tripped. - Removed:
ParcelBackupLoader(dead after the GSON refactor).
Backup restore put parcels at impossible Y coordinates
- Root cause: the
BoxAdapterwrote box JSON with keys"minCoords"and"maxCoords", butgottschcore'sBox.save()/Box.load()use"min"and"max". On load,Box.load(tag)couldn't find its keys and returnedBox.EMPTY, which is statically initialized asnew Box(Coords(0,-255,0), Coords(0,-255,0)). The result: every restored parcel had its minCoords Y shifted by -255 (e.g.49displayed as-206). - Fix:
BoxAdapternow writes"min"/"max"to matchBox.save(). The reader accepts both"min"/"max"(correct) and the legacy"minCoords"/"maxCoords"keys for any backups written before this fix.
Dispenser firing tool (e.g. shears) inside a claimed parcel crashed the server
- Root cause:
ModEvents.onToolInteractcastevent.getPlayer()directly toServerPlayerand passed it toParcelRegistry.hasAccess(...), which dereferencesplayer.getUUID()insideresolveParcelCached. Vanilla'sShearsDispenseItemBehaviorpostsBlockToolModificationEventwith anullplayer (no entity is wielding the dispensed item), producing an NPE that killed the server tick. - Fix: added an explicit null-player branch in
onToolInteract. With no player there is no UUID to check whitelists against, so the position is default-denied: ifParcelRegistry.intersectsParcel(coords, dim)is true, cancel the event; otherwise allow it.
Citizen/Zone nationEstate reference diverged from EstateRegistry after restore
- Root cause: during JSON restore, every parcel's
nationEstatefield was deserialized into its ownNationEstateContextinstance, so live mutations to the Nation's access type (via/cml estate nation accessType) would update only theNationParcel's registered estate, not the cachednationEstateon Citizen/Zone parcels. - Fix:
BackupSubCommand.executeLoadConfirmednow re-links everyNationalizedParcel.nationEstateto the registeredNationEstateinEstateRegistry, mirroring the behavior ofNationalizedParcel.loadNationEstate(tag)on the NBT load path.

