Three targeted optimizations that cut main-thread work per connect/disconnect
from ~200-300ms down to ~20-50ms. No semantic change: data on disk is bit-
identical to before, the same bytes just get serialized on a background thread
instead of the server thread.
(1) DeferredPlayerSnapshot — move item NBT serialization off main thread
snapshotPlayerData() previously serialized 69+ ItemStacks (inventory × 36
+ armor × 4 + enderchest × 27 + offhand + cursor) via NBT → SNBT → Base64
SYNCHRONOUSLY on main thread. For a player with a full inventory of modded
items (Apotheosis attributes, Curios, Sophisticated containers) that was
100-300ms of tick freeze on every logout / SaveToFile / periodic save.
New record DeferredPlayerSnapshot holds ItemStack.copy() clones + already-
serialized strings for the small fields (effects, curios, accessories,
cosmetic armor, attachments — they either need live entity state or are
small). Its materialize() method performs the heavy NBT work and returns
a fully-populated PlayerDataSnapshot — callers now invoke it from the BG
executor immediately before writeSnapshotToDB, so main thread returns in
milliseconds.
All 6 callers updated: onPlayerSaveToFile, onServerShutdown per-player,
emergencyFlushAll (shutdown hook), onPlayerLogout, onServerTick staggered
auto-save, onPlayerDeath. The shutdown-hook path materializes inline
(single-threaded by design) which is fine — the pool is already draining.
(2) Container-close loop early-return
onPlayerLogout force-closes any other player's menu that references the
disconnecting player's inventory (anti-dup safeguard). Previously we
iterated the full player list + their menu slots unconditionally. Now
a fast any-foreign-menu-open? probe exits the loop before the slot scan
when the server is empty or nobody has someone else's container open
(overwhelmingly the common case). Saves 1-5ms per logout on idle servers.
(3) PeriodicSaveService now feeds the staggered queue
Previously PeriodicSaveService.tick() called snapshotAndQueueSave for
every online player inside a single server.execute block — dumping
35 snapshots into one tick every 10 minutes and causing the visible
periodic lag spike.
New flow: the tick handler calls VanillaSync.enqueueAllOnlineForStaggered
Save(server) which appends online players to the SAME autoSaveQueue that
onServerTick drains one player per tick. 35 players now snapshot over
35 ticks (1.75s at 20 TPS) with ~30-50ms peak per-tick cost (after
Phase 18 #1). Dedupe check keeps duplicate triggers from double-enqueuing.
Anti-dup / anti-loss guarantees (Phase 15 / 2-phase commit) unchanged.
Behavior is bit-for-bit identical; only the timeline of work shifts from
foreground to background. Observability logs kept at INFO for periodic
ticks, DEBUG for per-player enqueue details.
|
||
|---|---|---|
| .github | ||
| compat-mods | ||
| gradle/wrapper | ||
| src/main | ||
| .gitattributes | ||
| .gitignore | ||
| build.gradle | ||
| CHANGELOG.md | ||
| docker-compose.yml | ||
| ERROR_LOG.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LICENSE | ||
| README.md | ||
| settings.gradle | ||
| TEST_PROCEDURE_v2.1.5.html | ||
PlayerSync
PlayerSync is a Minecraft Forge mod that synchronizes player data across multiple servers using a MySQL backend. It allows players to maintain their inventory, equipment, experience, advancements, and more when moving between servers in a network.
Mod Support
Any other mods support is also possible.
Development Setup
Database Setup (Docker)
A docker-compose.yml file is provided for easily setting up a MariaDB database instance for development testing.
- Make sure Docker is installed.
- Inside your work directory run:
This will download the MariaDB image (if not already present) and start a database container in the background.docker compose up -d - Stoppinng the Database
docker compose down
Data Persistence: The database uses a Docker volume, ensuring your data persists even if you stop and restart the containers.
Database Management Tool
The docker-compose.yml also includes an Adminer service, a lightweight database management tool.
- Access Adminer in your web browser at http://localhost:8080.
- Log in using the server with
- username:
playersync - database:
playersync - password: see docker-compose.yml
- username:
For debugging purposes, you can enable use_legacy_serialization to have readable database fields. This can cause crashes and unintended side-effects. Do not enable this on a production server if not absolutely necessary!
Running the Mod
The project uses Gradle for building and running. Use the provided Gradle wrapper (gradlew for Linux/macOS, gradlew.bat for Windows).
- Make sure that the MySQL database you configured is running.
- Run the Server
or on Windows:./gradlew runServer
This task compiles the mod and starts a dedicated Minecraft server instance with the mod loaded in the.\gradlew.bat runServerrundirectory. - Run the Client
or on Windows:./gradlew runClient.\gradlew.bat runClient