1. InnerCoreServer.java — getStringParam("path_for_world") was hardcoded to "worlds" (root), so the WorldDataSaver read/wrote worlds/moddata.json instead of worlds/<level>/moddata.json — all mod data appeared "lost". Now it resolves the real level name from server.properties. Also set NativeAPI.setWorldsPathOverride() so LevelInfo.getAbsoluteDir() points at the server's worlds/ (needed for custom dimensions later).
2. IDRegistry.java — genBlockID/genItemID ignored the pack's .staticids (looked up only the raw name, not the canonical minecraft:block_<name> key). Block/item numeric IDs were shifted vs the phone, silently corrupting saver hashes (tile entities restored with the wrong prototypes) and container item IDs. Fix: honor .staticids — IDs now match the phone exactly (verified 128/128 blocks). Self-gating: packs without the file behave as before.
3. BlockPalette.java (getStateUnsafe) — Horizon's leveldb stores custom block states as minecraft:block_* + "color": "<name>" (string = damage index in vanilla color order), Zote registered block_* + ints. Old fallback always resolved damage 0 → all variants wrong (49× "Replacing a unit with low compatibility"). Fix: strip minecraft: prefix, normalize color-string→int, resolve damage from the stored state. Result: 0 warnings, correct variants.
4. ItemUtils.java — get(...) didn't flush dirty custom data (putInt changes) before building the item, then bind() discarded it — wireless item bindings (controllerX/Y/Z) never persisted. Fix: call extra.getValue() first.
5. ItemInstanceExtra.java — phone items carry custom data wrapped as {"data":"<json string>"}; Zote parsed it flat, so getInt('energy') returned -1. Fix: unwrap on read (flat data passes through untouched).
6. RakNetPlayerSessionHooks.java — packet callbacks run on a network thread not marked SERVER, so mods checking LowLevelUtils.getCurrentThreadType() == "SERVER" (e.g. RS wireless grid open) silently did nothing. Fix: mark the packet thread as SERVER.
7. core-engine.dev.js — entityTypeName is not defined (ReferenceError) in TileEntityBasePrototype._readImpl broke deserialization of tile entities with legacy containers. Fix: use this.networkEntityTypeName.
Now get/put/has and ScriptableObject.get/put/hasProperty on the ScriptableModuleInstanceImpl object will be equivalent to each other
1. has() will return true for bound methods, fields and extra fields, added in prototype
2. get() will return methods or fields from prototype, but if they are overridden in this object, will prioritize those
3. put() will
- write into java field bindings directly via new ScriptableObject.getRawSetter
- override java method bindings for this object only (if VALIDATE_INVALID_WRITES = false)
- add/override extra fields (if VALIDATE_INVALID_WRITES = false)