Real-time survival-to-creative phantom mirror plugin
Find a file
exo d976100a5d
All checks were successful
Build & Release / build (push) Successful in 33s
Build & Release / release (push) Successful in 2s
perf: cache all reflection lookups + distance culling + respawn 15s
- NmsHelper: ALL Method/Constructor/Field cached at init(), zero
  getMethod() calls during gameplay (~5-10x faster per NMS call)
- Distance culling: skip teleport/equip packets for viewers >128 blocks
- Respawn interval: 5s → 15s (teleport handles movement between)
- Particles disabled by default (cosmetic overhead)
- send() method cached after first resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-11 22:27:49 +02:00
.forgejo/workflows EkaiiMirror v1.0.0 — real-time survival→creative phantom mirror 2026-05-11 03:10:24 +02:00
gradle/wrapper fix: include gradle-wrapper.jar (was excluded by *.jar gitignore) 2026-05-11 03:13:56 +02:00
src perf: cache all reflection lookups + distance culling + respawn 15s 2026-05-11 22:27:49 +02:00
velocity-plugin feat: NMS fake player + equipment sync + tab format "pseudo [Monde]" 2026-05-11 18:33:52 +02:00
.gitignore fix: include gradle-wrapper.jar (was excluded by *.jar gitignore) 2026-05-11 03:13:56 +02:00
build.gradle.kts feat: NMS reflection for fake player model (no compile-time NMS deps) 2026-05-11 18:41:20 +02:00
gradle.properties EkaiiMirror v1.0.0 — real-time survival→creative phantom mirror 2026-05-11 03:10:24 +02:00
gradlew EkaiiMirror v1.0.0 — real-time survival→creative phantom mirror 2026-05-11 03:10:24 +02:00
gradlew.bat EkaiiMirror v1.0.0 — real-time survival→creative phantom mirror 2026-05-11 03:10:24 +02:00
README.md docs: comprehensive README + session learnings 2026-05-11 22:16:02 +02:00
settings.gradle.kts fix: remove all PacketEvents fake entity code from backend receiver 2026-05-11 15:53:42 +02:00

EkaiiMirror

Real-time survival → creative server mirroring plugin for Minecraft 26.1.2 (Luminol/Folia).

Players on the creative server see survival players as phantom entities with full skin, armor, items, sneaking, elytra flying, and vehicle riding — all in real time.

Features

Phantom Players (NMS)

  • Full player model with skin (via NMS ServerPlayer + reflection)
  • Real-time position + head rotation sync (100ms updates)
  • Sneaking (Pose.CROUCHING + shared flags)
  • Arm swing animation
  • Full equipment sync: main hand, off hand, helmet, chestplate, leggings, boots
  • Elytra flying (Pose.FALL_FLYING + flag 0x80)
  • Vehicle riding: boats, horses, minecarts, camels, etc.
  • Glow outline (scoreboard team color, default AQUA)
  • Soul flame particles
  • Periodic respawn (5s) handles: late joins, dimension changes, reconnections

Ghost Blocks

  • Block place/break events mirrored as client-side fake blocks
  • Uses player.sendBlockChange() — no server-side modification
  • Batched for performance (configurable flush interval)

Cross-Server (Velocity Plugin)

  • Chat bridge: messages forwarded between all servers
  • /world survie|crea|plot command to switch servers
  • Tab list: cross-server player entries via Velocity

Architecture

Sender (Survie)  →  Redis pub/sub  →  Receiver (CreaClone)
                    channel: ekaii:mirror

Velocity Plugin: chat bridge + /world command + tab sync

Message Protocol

Compact JSON over Redis pub/sub. Message types:

  • bp Block Place, bb Block Break
  • pj Player Join, pq Player Quit
  • pm Player Move, ps Player Sneak, pa Player Swing
  • pe Player Equipment (6 slots)
  • el Player Elytra, vm Vehicle Mount, vd Vehicle Dismount
  • hb Heartbeat, ba Batch

NMS Approach

PacketEvents was found to silently drop all entity spawn packets on Luminol/Folia. The plugin uses pure Java reflection to access NMS classes at runtime — zero compile-time NMS dependencies.

Key NMS packets used:

  • ClientboundPlayerInfoUpdatePacket (player profile + skin)
  • ClientboundAddEntityPacket (spawn entity, raw values constructor)
  • ClientboundSetEntityDataPacket (metadata: glow, sneak, elytra flags)
  • ClientboundTeleportEntityPacket (position sync via PositionMoveRotation)
  • ClientboundRotateHeadPacket (head rotation)
  • ClientboundSetEquipmentPacket (all 6 equipment slots)
  • ClientboundSetPassengersPacket (vehicle riding, via Unsafe field injection)
  • ClientboundRemoveEntitiesPacket (despawn)
  • ClientboundAnimatePacket (arm swing)

Installation

Requirements

  • Minecraft 26.1.2 server (Luminol, Folia, or Paper)
  • Redis server
  • Velocity proxy (for cross-server features)

Backend Plugin

  1. Drop EkaiiMirror-1.0.0.jar in plugins/ on both servers
  2. Configure plugins/EkaiiMirror/config.yml:

Sender (survival server):

mode: SENDER
redis:
  host: "<redis-host>"
  port: 6379
  password: ""
  channel: "ekaii:mirror"
sender:
  worlds: []  # empty = all worlds (overworld, nether, end)
  move-interval-ms: 100
  batch-interval-ms: 50
receiver:
  glow-color: AQUA
  block-display: true
  particles: true

Receiver (creative server):

mode: RECEIVER
redis:
  host: "<redis-host>"
  port: 6379
  password: ""
  channel: "ekaii:mirror"
sender:
  worlds: []
  move-interval-ms: 100
  batch-interval-ms: 50
receiver:
  glow-color: AQUA
  block-display: true
  particles: true

Velocity Plugin

  1. Drop EkaiiMirrorVelocity-1.0.0.jar in Velocity's plugins/
  2. Configure plugins/ekaii-mirror-velocity/config.yml:
servers:
  ekaii:
    display: "Survie"
    color: "gray"
  creaclone:
    display: "Créa"
    color: "green"
  plot:
    display: "Plot"
    color: "gold"
shared-chat: true
shared-tab: true

Redis

docker run -d --name ekaii-redis --restart unless-stopped --network host redis:7-alpine

Commands

Command Description
/mirror toggle Toggle phantom visibility (receiver only)
/mirror status Show plugin status
/world survie Switch to survival server
/world crea Switch to creative server
/world plot Switch to plot server

Building

./gradlew :shadowJar                          # Backend plugin
./gradlew :velocity-plugin:shadowJar          # Velocity plugin

Output:

  • build/libs/EkaiiMirror-1.0.0.jar
  • velocity-plugin/build/libs/EkaiiMirrorVelocity-1.0.0.jar

Known Limitations

  • PacketEvents sendPacket does not work on Luminol/Folia for entity spawning — NMS reflection is used instead
  • Vehicle position syncs via teleport (may appear slightly jerky at high latency)
  • Equipment updates every ~2 seconds (not instant on item pickup)
  • Phantom players are purely visual — no collision, no interaction