A Minecraft Forge mod that synchronizes player data across multiple servers using a MySQL backend.
Go to file
laforetbrut 8b687d20f7 Phase 17: advancements mtime cache + per-item log demotion
Two quality-of-life peaufinages.

(1) Advancements file mtime cache [VanillaSync.snapshotPlayerData]
    Each snapshot previously called Files.readAllBytes() on the player's
    advancement JSON — a main-thread disk read of 1-50ms depending on
    storage. On a 35-player server with periodic saves + SaveToFile every
    autosave tick, this adds up.

    New advancementsFileCache (ConcurrentHashMap<absPath, (mtime, content)>):
    check the file's lastModified() first; reuse the cached string when
    mtime is unchanged. PlayerAdvancements.save() still flushes pending
    changes, and Minecraft only touches the file when something actually
    changes — so mtime is a reliable staleness signal. Cache is
    process-wide (paths include player UUID so no cross-contamination).

    Expected impact: -5 to -30ms off main-thread snapshot for idle-ish
    players, zero for players who just earned advancements.

(2) Log spam reduction
    The restore/save paths chatter one INFO line per item (backpack / SS /
    RS2 disk / accessories / cosmetic / attachments). On a server with
    multiple players, each with multiple storage items, this floods
    sync.log with per-UUID noise that has zero diagnostic value once the
    'it's working' phase is past.

    Demoted to DEBUG:
      - [restore-backpack] uuid=X nbt_keys=N cleared_via=api
      - [restore-ss] uuid=X nbt_keys=N
      - Storing backpack data for player X
      - Saved backpack data for UUID X
      - Scanning inventory for Sophisticated Storage items for player X
      - Saved Sophisticated Storage item data for UUID X
      - Saved RS2 disk data for UUID X via save() NBT
      - Saved RS2 disk data for UUID X via codec reflection
      - Restored RS2 disk data for UUID X
      - Restored Accessories data for player X
      - Restored CosmeticArmor data for player X
      - Restored NeoForge attachments for player X

    Kept at INFO (per-save summaries):
      - Saved N RS2 disk(s) via direct codec (player-scoped)
      - Saved N RS2 disk(s) via legacy full-save fallback
      - Logout save completed for player X in Nms
      - Sync data for player X completed in Nms
      - [perf-logout] core=Xms backpacks=Yms ss=Zms rs2=Wms total=Nms
      - [emergency-flush] flushed N players

    Net effect: sync.log goes from ~10 lines per cross-server transfer
    to ~3. Still full diagnostic trace available with log_level=DEBUG.

Unchanged behavior, faster snapshots, cleaner logs.
2026-04-22 10:10:21 +02:00
.github Bump gradle/actions from 4 to 5 2025-10-14 16:55:21 +08:00
compat-mods Add compat-mods staging folder for mod compatibility analysis 2026-04-22 03:33:11 +02:00
gradle/wrapper migrate from ForgeGradle to ModDevGradle legacy 2025-05-02 22:40:39 +00:00
src/main Phase 17: advancements mtime cache + per-item log demotion 2026-04-22 10:10:21 +02:00
.gitattributes Initial commit 2022-12-08 16:59:20 +08:00
.gitignore Fix backpack/curios dup, perf overhaul, drop chat+cobblemon 2026-04-22 02:50:26 +02:00
build.gradle jarJar: declare version ranges for MySQL + HikariCP 2026-04-22 06:46:24 +02:00
CHANGELOG.md Phase 8: 20+ new config keys + 14 admin commands (/playersync) 2026-04-22 06:34:02 +02:00
docker-compose.yml use volume for docker-compose db to persist data 2025-05-01 18:42:58 +00:00
ERROR_LOG.md Phase 6: docs (CHANGELOG, ERROR_LOG, TEST_PROCEDURE) 2026-04-22 06:09:08 +02:00
gradle.properties perf: zero JDBC on server thread + HikariCP + parallel shutdown + audit fixes 2026-03-29 18:58:27 +02:00
gradlew migrate from ForgeGradle to ModDevGradle legacy 2025-05-02 22:40:39 +00:00
gradlew.bat migrate from ForgeGradle to ModDevGradle legacy 2025-05-02 22:40:39 +00:00
LICENSE Create LICENSE 2022-12-08 17:11:47 +08:00
README.md readme: add section on how to setup a dev env 2025-05-01 16:59:05 +00:00
settings.gradle half done, noticed about advancement can't store normally 2025-06-07 00:55:30 +08:00
TEST_PROCEDURE_v2.1.5.html Phase 6: docs (CHANGELOG, ERROR_LOG, TEST_PROCEDURE) 2026-04-22 06:09:08 +02:00

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.

  1. Make sure Docker is installed.
  2. Inside your work directory run:
    docker compose up -d
    
    This will download the MariaDB image (if not already present) and start a database container in the background.
  3. 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.

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).

  1. Make sure that the MySQL database you configured is running.
  2. Run the Server
    ./gradlew runServer
    
    or on Windows:
    .\gradlew.bat runServer
    
    This task compiles the mod and starts a dedicated Minecraft server instance with the mod loaded in the run directory.
  3. Run the Client
    ./gradlew runClient
    
    or on Windows:
    .\gradlew.bat runClient