Commit Graph

20 Commits

Author SHA1 Message Date
laforetbrut
484f1a8c05 Final audit: fix ghost-online, SQL injection, resource leak, NPE
CRITICAL-1/2: Remove duplicate online=1 writes from doPlayerJoin.
The synchronous onPlayerLoggedInKickCheck already sets online=1.
The background thread writes raced with logout's online=0, permanently
locking players as "online" after crash-disconnect during join.

HIGH-1: Startup SQL uses PreparedStatement for server_id (was string concat).
HIGH-2: update() method now uses try-with-resources for PreparedStatement.
HIGH-3: NPE guard in RS2 data file logging when getRS2DataFile returns null.

Vyrriox
2026-03-26 18:33:00 +01:00
laforetbrut
0a88694166 Production hardening: fix all critical audit issues
CRITICAL fixes:
- C-1/C-2/C-4: Auto-save and logout now run on MAIN THREAD. All entity
  reads (inventory, curios, effects) were happening off-thread, causing
  duplication exploits (player interacts during save → items duplicated).
  Auto-save uses tryLock() to skip players already being saved.
- C-5: NPE fix for non-RS2 items (null check on registry key lookup)
- C-6: RS2 .dat file written atomically (temp file + rename) to prevent
  corruption of entire RS2 storage on crash mid-write

HIGH fixes:
- H-3: Deadlock prevention: lock released BEFORE latch.await() in
  doPlayerJoin. Prevents shutdown deadlock where background thread
  holds lock while waiting for main thread, and shutdown holds main
  thread while waiting for lock.
- H-5: Curios cache now works WITHOUT keepInventory. Players who die
  then disconnect before respawning no longer lose curios data.
- H-8: server_id SQL uses PreparedStatements instead of string concat

MEDIUM fixes:
- M-1: NumberFormatException in LocalJsonUtil caught per-entry instead
  of crashing entire map parse (prevents losing all cosmetic armor)

Vyrriox
2026-03-26 18:14:31 +01:00
laforetbrut
6c5807d3c8 Fix Sophisticated Storage shulkers, RS2 disks, and kick system
1. Sophisticated Storage shulkers/barrels/chests:
   - ROOT CAUSE: UUID stored as DataComponent (not in CustomData).
     extractStorageUuid() only checked CustomData, missing the UUID.
   - FIX: Use StackStorageWrapper.fromStack(provider, item).getContentsUuid()
     which reads the DataComponent via the proper API.
   - Also scan ender chest for packed storage items.

2. Refined Storage 2 disks:
   - ROOT CAUSE: save() on StorageRepositoryImpl returned data in an
     unknown codec format that our extraction couldn't parse.
   - FIX: Read/write the .dat file directly from disk after forcing
     a save flush. This uses the exact NBT format RS2 writes.
   - Search multiple NBT structures (direct keys, nested compounds,
     list-of-pairs) to handle any codec format.
   - On restore: write entries into .dat file, clear DimensionDataStorage
     cache via reflection to force RS2 to reload.

3. Kick system:
   - ROOT CAUSE: PlayerNegotiationEvent.getConnection().disconnect()
     does NOT work in NeoForge 1.21.1 (too early in connection).
   - FIX: Full duplicate check moved to PlayerLoggedInEvent with
     HIGHEST priority. Uses player.connection.disconnect() which
     is reliable on the server thread.
   - Marks online=1 synchronously to close race condition.

Vyrriox
2026-03-26 18:05:12 +01:00
laforetbrut
e907bcbfb0 Security audit: fix 7 critical/high issues from code review
1. CRITICAL - Anti-dupe: Player inventory mutations now run on the main
   server thread via server.execute(). DB reads stay async, but all
   setItem/setHealth/addEffect calls happen on the tick thread.
   CountDownLatch ensures the lock is held until apply completes.

2. CRITICAL - Resource leaks: 3 QueryResults in PlayerSync.java startup
   now use try-with-resources + PreparedStatements instead of raw
   String.format SQL.

3. HIGH - Curios save: UPDATE changed to REPLACE INTO to prevent silent
   no-ops when the curios row doesn't exist yet (new player who died
   before first init save).

4. HIGH - RS2 restore: Removed skip-if-exists check. DB is always the
   source of truth - stale local data was persisting permanently.

5. HIGH - Race conditions: Shutdown save now acquires per-player lock.
   All logout saves (curios, mod-compat, inventory) moved inside
   doPlayerLogout under a single lock acquisition.

6. HIGH - SQL injection: DATABASE_NAME validated against [A-Za-z0-9_]+
   regex on startup to prevent injection via config.

Vyrriox
2026-03-26 17:34:36 +01:00
laforetbrut
a85131708f Fix NeoForge attachment sync, kick system, and backpack upgrades
1. NeoForge attachments (SOL Onion, Ars Nouveau, etc.):
   - deserializeAttachments signature is (Provider, CompoundTag) not
     (CompoundTag) - reflection was failing silently, nothing restored
   - Use serializeAttachments(Provider) directly for saving instead of
     saveWithoutId() for cleaner approach
   - This fixes SOL Onion food diversity, Ars Nouveau mana/glyphs,
     Iron's Spellbooks, Pehkui scale, and all other NeoForge attachments

2. Multi-server kick:
   - Add secondary kick check in PlayerLoggedInEvent as fallback
   - Mark online=1 SYNCHRONOUSLY on login to close race condition
     where async doPlayerJoin hasn't set online=1 yet

3. Backpack upgrades:
   - Call refreshInventoryForInputOutput() before reading from
     BackpackStorage to flush pending wrapper changes

Vyrriox
2026-03-26 17:22:21 +01:00
laforetbrut
fc7d81f914 Fix Sophisticated Storage shulkers/chests/barrels losing contents on transfer
Root cause: Sophisticated Storage uses its own ItemContentsStorage
(SavedData) for packed items, NOT BackpackStorage from Sophisticated
Backpacks. The code was calling BackpackStorage which returned empty
data for storage items.

Fixes:
- Use ItemContentsStorage.get().getOrCreateStorageContents() for save
- Use ItemContentsStorage.get().setStorageContents() for restore
- Add extractStorageUuid() for "storageUuid" key (SS uses this, not
  "contentsUuid" which is for backpacks only)
- Try both UUID keys when scanning inventory items
- Add sophisticatedstorage as compileOnly dependency

Vyrriox
2026-03-26 17:12:29 +01:00
laforetbrut
2e0269ee62 Add Refined Storage 2 disk sync + Extra Disks support
- Sync RS2 disk storage contents between servers (storageReference UUID)
- Support both refinedstorage and extradisks namespaces
- Save: extract individual entries from StorageRepository SavedData
- Restore: decode via RS2 codec and inject into target server repository
- Skip restore if storage already exists on target server (no overwrite)
- Scan inventory + ender chest for disks

Vyrriox
2026-03-26 15:07:28 +01:00
laforetbrut
f37e58be53 Add generic NeoForge attachment sync for full mod compatibility
Adds a generic system that syncs ALL NeoForge player attachments,
covering per-player data from every mod in the modpack:

- Ars Nouveau: mana, glyph/spell knowledge
- Iron's Spellbooks: mana, learned spells, cooldowns
- Pehkui: player scale
- Spice of Life: Onion: food diversity history
- And ANY other mod using NeoForge's attachment system

Implementation:
- Save: extracts neoforge:attachments tag from player.saveWithoutId()
- Restore: uses reflection to call NeoForge's deserializeAttachments()
  which ensures exact same deserialization path as normal player load
- Stored as BNBT in mod_player_data table (mod_id=neoforge_attachments)

Also verified CosmeticArmours (mod id: cosmeticarmoursmod) and
CosmeticWeapons (mod id: cosmeticweaponsmod) are content-only mods
that add craftable items - no custom player storage, fully handled
by existing inventory sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:43:42 +01:00
laforetbrut
c63d5849a3 Add mod compatibility: Accessories (Aether), Cosmetic Armor, Apotheosis
- Add Accessories API sync for Aether mod accessory slots (pendant, cape,
  gloves, rings, shield, misc). Uses same pattern as Curios: validate data
  before clearing slots, PreparedStatements for DB operations
- Add Cosmetic Armor Reworked sync for 4 cosmetic armor slots via
  InventoryManager/CosArmorAPI
- Add Apotheosis + Placebo as compileOnly deps. Apotheosis item data
  (affixes, gems, sockets, rarity) travels with items via DataComponents
  and is already synced by the inventory sync
- New generic mod_player_data DB table with composite key (uuid, mod_id)
  for extensible mod-specific data storage
- Integrated save/restore in join, logout, and auto-save pipelines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:21:09 +01:00
laforetbrut
03b57c3e6b Fix critical sync bugs, security, and add Sophisticated Storage support
- Fix advancements disappearing: use PreparedStatements for all SQL with
  user data (advancement JSON contains chars that broke string-concat SQL),
  add null safety for advancement file
- Fix multi-server kick: run doPlayerConnect synchronously instead of async
  (players could join before the duplicate check completed)
- Fix Curios disappearing: clear slots AFTER validating data exists (not
  before), use CuriosCache for dead players on logout instead of empty API
- Fix Sophisticated Storage items: add storeSophisticatedStorageItems() and
  restoreSophisticatedStorageItems() to sync packed barrels/shulkers/chests
- Anti-duplication: clear all inventories before restoring from DB on join
- Fix tick counter: remove LevelTickEvent (fired per dimension = 3x too
  fast), merge heartbeat into ServerTickEvent
- Fix connection leaks: use try-with-resources for all QueryResult
- Fix logout order: save data BEFORE marking player offline
- Skip auto-save for dead/unsynced players to prevent saving empty data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:04:00 +01:00
mlus
148ac4db9b Revert "fallback BNBT, Compat with codec"
This reverts commit ce7004dba0.
2026-02-24 10:24:13 +08:00
mlus
ce7004dba0 fallback BNBT, Compat with codec 2026-02-24 10:20:27 +08:00
mlus
4b39d52c12 Add binary NBT serialization and deserialization support to improve data handling 2026-02-23 23:53:41 +08:00
mlus
b6da709393 curios snbt clean 2026-02-23 22:33:13 +08:00
mlus
d0044fa824 snbt structure clean 2026-02-17 19:08:34 +08:00
mlus
d8c3bac31f new nbt serializer 2026-02-17 15:41:45 +08:00
mlus
72d0255d48 fix advancements sync 2025-11-30 01:57:26 +08:00
mlus
90742aafa0 fix backpack didn't sync 2025-11-30 00:50:55 +08:00
mlus
733f37cbb3 supplement 2025-11-28 22:15:29 +08:00
mlus
29da0f28ad recently commit port 2025-11-28 21:00:25 +08:00