
VeryMcProto
Serverside plugins that add servux&JEI&syncmatica protocol support for papermc servers.
⬇ Download on ModrinthVeryMcProto
A protocol-layer port that re-implements Fabric-only protocol mods as a pure Paper plugin. The client still uses the original Fabric mods; the server swaps from "Fabric server + server-side mod" to "standard Paper server + this plugin", with identical protocol behavior.
Paper 1.21.11 · Java 21 · paperweight userdev · Version 1.0.0
Servux ✅ · JEI Recipe Bridge ✅ · Syncmatica ✅ (all three targets fully implemented and tested)
Table of Contents
- 1. What It Is
- 2. Protocol Mods
- 3. Requirements
- 4. Installation
- 5. Architecture
- 6. Commands
- 7. Permissions
- 8. Configuration
- 9. Data Layout
- 10. Feature Matrix
- 11. Network Protocol
- 12. Debugging
- 13. Compatibility Testing
- 14. Developers
- 15. Docs Index
- 16. FAQ
- 17. Credits
1. What It Is
VeryMcProto is a Paper plugin that re-implements the network protocols and data collection expected by several Fabric protocol mods on a standard Paper 1.21.11 server, so that a "Fabric client + Paper server" combination behaves exactly like a "Fabric client + vanilla Fabric server mod" combination.
It is a protocol-layer port, not a port of the Fabric mods themselves. The client keeps using masa's / endte's / JEI's own Fabric mods; our job is to implement on the Paper server the custom network channels + server→client data delivery + server-side behavior cooperation they expect.
Why this is necessary:
- The server-side parts of these protocol mods rely heavily on NMS internals (
NaturalSpawner.SpawnState,ServerTickRateManager,ChunkAccess.getAllReferences(),StructureStart.createTag(),Recipe.CODEC+NbtOps,BlockEntity.saveWithFullMetadata(), etc.) — unreachable via the pure Paper API. - They use Mojang's vanilla
CustomPacketPayloadmechanism (Fabric'sServerPlayNetworkingis merely a registration wrapper around this vanilla mechanism). Paper's plugin messaging channels map directly to vanilla custom payload channels, and S2C large packets can be sent via NMSClientboundCustomPayloadPacketto bypass plugin messaging size limits. - Server-side cooperative features (e.g. EasyPlace) use Mixin in the original; Paper has no Mixin runtime, so an equivalent is implemented via PacketEvents.
This project uses paperweight userdev to reference fully-deobfuscated Mojang NMS at dev time; the artifact is converted by reobfJar into a jar that standard Paper loads directly. It depends on no server patch / Mixin / private fork.
2. Protocol Mods
| Mod | Client Mod | Nature | Status |
|---|---|---|---|
| Servux | masa's MiniHUD / Litematica / Tweakeroo | Server→client one-way broadcast (6 providers) | ✅ Full |
| JEI Recipe Bridge | JEI + JEIRecipeBridge | One-shot S2C recipe sync on player join | ✅ Full |
| Syncmatica | endte syncmatica | Bidirectional, stateful, multi-player shared schematic repository | ✅ Full |
1. Servux
A server-side protocol mod that delivers data to masa's client mods (MiniHUD / Litematica / Tweakeroo) via servux:* custom channels:
- World metadata (difficulty/weather/spawn point/seed), TPS / MobCap periodic logging
- Structure bounding boxes (periodic chunk scanning; rendered by the structure debugger / MiniHUD)
- Litematica schematic transmit / paste (S2C delivery of
.litematic; C2S receives client uploads and pastes them into the world) - Entity / block-entity NBT query (client selects, server returns full NBT)
- EasyPlace server-side precise placement protocol (Tweakeroo cooperation; implemented via PacketEvents)
6 channels (the network channel name ≠ the provider logical name; source-verified in ServuxReference.java):
| Channel (network name) | Provider (logical name) | Protocol version | Purpose |
|---|---|---|---|
servux:main |
servux_main |
— | Config main channel (ConfigProvider; permanently enabled; sends no network packets; only carries global settings) |
servux:hud_metadata |
hud_data |
2 | HUD: world metadata / spawn point / weather / TPS / MobCap / recipes |
servux:entity_data |
entity_data |
1 | Entities: block-entity / entity NBT query |
servux:tweaks |
tweaks_data |
1 | Tweaks: entity / block-entity NBT (same pattern as Entities) |
servux:structures |
structure_bounding_boxes |
2 | Structures: structure bounding boxes (periodic chunk scan) |
servux:litematics |
litematic_data |
1 | Litematics: schematic transmit / paste / bulk entities |
Handshake field
MOD_STRING = servux-paper-1.21.11-1.0.0(keeps theservux-prefix so masa's client recognizes that the server runs the Servux protocol; concrete version negotiation goes through each channel's protocol version).
2. JEI Recipe Bridge
On player join, syncs the server's complete recipe table to the JEI client, routed by client brand over two vanilla custom payload channels:
- Fabric client →
fabric:recipe_sync - NeoForge client →
neoforge:recipe_content
Sent directly via NMS ClientboundCustomPayloadPacket (bypasses the plugin messaging size limit — recipe packs routinely exceed 32KiB). Pure S2C / one-shot / a single enabled config option. Handshake field jei-recipe-bridge-paper-1.21.11-1.0.0.
3. Syncmatica
Fundamentally different from Servux (one-way broadcast):
- The server acts as a central repository storing
.litematicfiles; multiple players can upload / download / collaboratively modify placement positions. - Bidirectional and stateful: a single physical channel
syncmatica:main+ 18 logical PacketTypes + an Exchange session layer (request-acknowledgement state machine). - File storage + JSON persistence + upload quota / debug services.
- On handshake, both sides exchange a FeatureSet to negotiate the optional-field encoding of metadata / position packets.
Feature enum (negotiated on handshake): CORE FEATURE MODIFY MESSAGE QUOTA DEBUG CORE_EX VERSION DISPLAY_NAME. This server advertises the full FeatureSet (combined with MOD_VERSION=1.0.0 to trigger FEATURE exchange so both sides encode with the full set).
3. Requirements
Server
| Item | Requirement |
|---|---|
| Server | Paper 1.21.11 (api-version: 1.21; standard Paper, no patch / fork needed) |
| Java | 21 |
| Optional | PacketEvents 2.13.0 (only for EasyPlace; if absent, EasyPlace is gracefully skipped — other features are unaffected) |
Client
| Feature family | Client must install |
|---|---|
| All of Servux (HUD / structures / NBT query / schematic paste / EasyPlace) | MiniHUD + Litematica + Tweakeroo (the masa suite, 1.21.11 LTS) |
| JEI recipe sync | JEI + JEIRecipeBridge |
| Schematic sharing | Syncmatica (endte client, 1.21.11 LTS) |
The client version must match the server's MC 1.21.11. The client is the "receiving end" of these features; every protocol field semantic and packet-reassembly behavior is verified against the client source (see
OriginImpl/for litematica / malilib / syncmatica).
4. Installation
- Get
VeryMcProto-1.0.0.jarfrom the project Releases page, or build it with./gradlew build(the reobf artifact loads directly on standard Paper). - Drop it into the server's
plugins/directory. - (Optional, only for EasyPlace) Install the PacketEvents plugin.
- With PacketEvents installed, EasyPlace is enabled automatically; without it, it is skipped automatically.
- Restart /
/restartthe server. - Players join and install the corresponding client Fabric mods — handshake is automatic.
On startup the console shows:
[VeryMcProto] 启动中 (MC 1.21.11, paper)...
[VeryMcProto] 已注册协议 mod: servux
[VeryMcProto] 已注册协议 mod: jei_recipe_bridge
[VeryMcProto] 已注册协议 mod: syncmatica
[VeryMcProto] 服务端启动完成,已捕获 RegistryAccess 并加载 servux.json。
[VeryMcProto] 框架就绪。
Defensive design: the three mods are assembled each inside its own try-catch; any one failing only logs and degrades gracefully — it never blocks server startup and never affects the other mods.
5. Architecture
Package root verymc.top.veryMcProto, split into a framework layer and a protocol-mod layer:
verymc.top.veryMcProto
├── VeryMcProto Main class (JavaPlugin.onEnable assembles the framework + registers the three mods + registers commands)
├── framework/ Framework layer (infrastructure decoupled from any specific protocol mod)
│ ├── network/ plugin messaging channel wrappers, byte-stream codec, splitting, handler registry
│ ├── dataproviders/ Provider registry / scheduler / config hub (used by Servux)
│ ├── event/ Bukkit event → Provider lifecycle bridge (ServerLoad/Join/Quit/Respawn/RegisterChannel + tick)
│ ├── debug/ Generic debug logging engine (independent instances per mod; master + category orthogonal; persisted)
│ ├── permission/ Permission utility (replaces fabric-permissions-api)
│ ├── reflect/ NMS reflection utility (cached + defensive; degrades to defaults on version drift)
│ ├── nms/ Bukkit ↔ NMS conversion
│ ├── settings/ Servux config-option system (Bool/Int/String/StringList/List)
│ └── util/ JSON / string utilities (Gson pretty + atomic tmp/move write)
└── mod/ Protocol-mod layer (each ported Fabric protocol mod occupies one directory unit)
├── servux/ Servux (app/command/dataproviders/network/easyplace/loggers/schematic/util)
├── jeirecipebridge/ JEI Recipe Bridge
└── syncmatica/ Syncmatica (communication/exchange/data/litematica/service/...)
Assembly order (VeryMcProto.onEnable): initialize the framework (ChannelManager / DataProviderManager / LifecycleBridge) → register servux → jeirecipebridge → syncmatica in turn → register the /servux /jei /syncmatica commands.
Key replacements (Fabric → Paper), one-liners:
ModInitializer.onInitialize()→JavaPlugin.onEnable()- Mixin lifecycle hooks → Bukkit events (
ServerLoadEvent/PlayerJoinEvent/PlayerQuitEvent/PlayerRespawnEvent/PlayerRegisterChannelEvent) + BukkitRunnable tick scheduling - Mixin / AccessWidener (none on Paper) → reflection / Bukkit events / PacketEvents / degraded omission
- Fabric
ServerPlayNetworking→ PaperMessenger(plugin messaging) + NMSClientboundCustomPayloadPacketdirect send fabric-permissions-api→framework.permission.Perms(op-level mapping)
Original implementation archive:
OriginImpl/holds the original Fabric sources of every ported mod (servux / litematica / malilib / syncmatica / JEIRecipeBridge / tweakeroo / minihud / itemscroller / packetevents) for line-by-line comparison — in case of divergence, the real source wins.
6. Commands
/servux
Permission: servux.command (default: op)
/servux Show usage
/servux list List all providers and their enabled state
/servux info <provider:setting|setting> Show a setting's current value + default
/servux set <provider:setting|setting> <value> Modify a setting and persist immediately
/servux enable <provider> Enable a provider (e.g. hud_data)
/servux disable <provider> Disable a provider
/servux search <keyword> Fuzzy-search setting names
/servux reload Reload config from servux.json
/servux save Write current config to servux.json
/servux debug ... Debug toggles (see below)
/servux litematic ... Litematica schematic management (see below)
- A setting's qualified name is
<provider-logical-name>:<setting-name>, e.g.hud_data:share_seed,servux_main:permission_level; the provider prefix can be omitted when unambiguous. - Provider logical names are in the channel table in §2:
servux_main/hud_data/entity_data/tweaks_data/structure_bounding_boxes/litematic_data. servux_main(the config main channel) can never be disabled; the other 5 can beenabled/disabled.
/servux debug — debug logging hot-toggle (runtime-immediate, persisted to servux.json immediately):
/servux debug Show current debug state
/servux debug on|off Master switch on/off (master only; does not touch categories)
/servux debug status Show state
/servux debug cat all|none Enable all / clear all categories
/servux debug cat <name> Toggle a single category
Master and categories are two orthogonal dimensions; both must be on for output. Category values:
lifecyclehandshakenetworkpackettickpermissionproviderconfigeasyplace.
/servux litematic — server-side schematic file management (requires the litematic_data provider enabled):
/servux litematic list List .litematic files under schematics/
/servux litematic transmit <file> [player] Load a schematic and deliver it via servux:litematics
Running
transmitfrom the console requires a target player. Files live inplugins/VeryMcProto/schematics/.
/syncmatica
Permission: syncmatica.command (default: true — all players can use the base command)
/syncmatica Show usage
/syncmatica status Module state (protocol on/off + debug + config file) [admin]
/syncmatica save Save config to syncmatica-config.json [admin]
/syncmatica reload Reload from syncmatica-config.json [admin]
/syncmatica enable Enable the protocol (online players re-handshake) [admin]
/syncmatica disable Soft-disable the protocol (channel kept, no kicks) [admin]
/syncmatica load Register all unloaded .litematic under syncmatics/ as placements [load]
/syncmatica load <file> Register a single .litematic as a placement [load + load_each]
/syncmatica debug ... Debug toggles (see below) [debug]
Upload / download / modify / delete of placements all go through protocol exchanges (client-side actions); the command only registers a local file as a placement and broadcasts it.
[admin]requiressyncmatica.command.admin,[load]requiressyncmatica.command.load,[load_each]requiressyncmatica.command.load_each,[debug]requiressyncmatica.command.debug.
/syncmatica debug (uses syncmatica's own SyncmaticaDebug; independent from /servux debug):
/syncmatica debug Show state
/syncmatica debug on|off Master switch
/syncmatica debug status Show state
/syncmatica debug cat all|none Enable all / clear all categories
/syncmatica debug cat <name> Toggle a single category (lifecycle handshake network packet exchange)
/syncmatica debug s2c Show current S2C send path
/syncmatica debug s2c nms|msg Switch S2C path (NMS direct / plugin messaging) — diagnostic toggle, not persisted
S2C defaults to NMS
DiscardedPayloaddirect send (the pure Fabric syncmatica client is only reachable via NMS direct send; the plugin-messaging wire is unreachable, verified by testing)./syncmatica debug s2c msgtemporarily switches to plugin messaging for comparison/troubleshooting.
/jei
Permission: jei.command (default: op)
/jei Show current state + usage
/jei enable Enable join-time recipe sync (subsequent joiners get synced)
/jei disable Stop join-time push (channel kept, no kicks; already-online players are unaffected)
Scope of effect: only affects players who join afterward. Recipe sync is a one-shot join push with no persistent connection to tear down (unlike syncmatica's "interrupt in-progress transfers").
7. Permissions
7.1 Command Permissions
| Permission node | default | Purpose |
|---|---|---|
servux.command |
op | All /servux subcommands |
jei.command |
op | /jei enable|disable |
syncmatica.command |
true | Base /syncmatica command (incl. load) |
syncmatica.command.admin |
op | /syncmatica save|reload|enable|disable|status |
syncmatica.command.load |
true | /syncmatica load (bulk load) |
syncmatica.command.load_each |
true | /syncmatica load <file> (single load) |
syncmatica.command.debug |
op | /syncmatica debug |
7.2 Provider Permissions (Runtime)
Servux provider permissions do not use the Bukkit permission default; instead they are decided at runtime by framework.permission.Perms based on the permission_level setting + op level. Perms.check(player, node, level) semantics:
- If the player is explicitly granted / denied the Bukkit permission node (
isPermissionSet, e.g. set by LuckPerms / a permission attachment), that result wins; - Otherwise,
level <= 0→ allow everyone; - Otherwise, it falls back to the op binary (
isOp()true passes, satisfying alllevel >= 1management-class settings).
So
permission_leveleffectively only distinguishes "0 = everyone / ≥1 = op only". To differentiate levels (e.g. grant level 2 but not level 3), use LuckPerms to explicitly grant the corresponding permission node.
Base nodes look like servux.provider.<provider-logical-name>; refined nodes append a suffix to the base:
| Permission node | Governing setting (level source) | Controls |
|---|---|---|
servux.main.admin |
servux_main:permission_level_admin (default 3) |
ConfigProvider admin operations |
servux.main.easy_place |
servux_main:permission_level_easy_place (default 0) |
EasyPlace placement |
servux.provider.hud_data |
hud_data:permission_level (default 0) |
HUD metadata delivery |
servux.provider.hud_data.weather |
hud_data:weather_permission_level (default 0) |
Weather data |
servux.provider.hud_data.seed |
hud_data:seed_permission_level (default 2) |
Seed data |
servux.provider.hud_data.logger |
hud_data:logger_permission_level (default 0) |
Loggers master toggle |
servux.provider.hud_data.logger.tps |
hud_data:logger_permission_level |
TPS logger |
servux.provider.hud_data.logger.mob_caps |
hud_data:logger_permission_level |
MobCap logger |
servux.provider.entity_data |
entity_data:permission_level (default 0) |
Entities base |
servux.provider.entity_data.nbt_query_override |
entity_data:nbt_query_permission_level (default 2) |
NBT query override permission |
servux.provider.entity_data.nbt_allow_player_inventory |
entity_data:player_inventory_permission_level (default 2) |
Query a player's inventory |
servux.provider.entity_data.nbt_allow_player_ender_items |
entity_data:player_ender_items_permission_level (default 2) |
Query a player's ender chest |
servux.provider.tweaks_data |
tweaks_data:permission_level (default 0) |
Tweaks base |
servux.provider.structure_bounding_boxes |
structure_bounding_boxes:permission_level (default 0) |
Structures base |
servux.provider.litematic_data |
litematic_data:permission_level (default 0) |
Litematics base (transmit/receive) |
servux.provider.litematic_data.paste |
litematic_data:permission_level_paste (default 0) |
Paste a schematic into the world (requires creative mode) |
When
nbt_query_overrideis off, the Entities NBT query falls back to the vanilla permissionminecraft.command.data(level 2), aligning with the vanilla/datacommand permission.
7.3 LuckPerms Examples
Grant seed access (default is op-only):
commands:
- "lp user <player> permission set servux.provider.hud_data.seed true"
Grant paste access to a non-op:
commands:
- "lp user <player> permission set servux.provider.litematic_data.paste true"
8. Configuration
All config is JSON (Gson pretty + atomic tmp/move write), located under plugins/VeryMcProto/.
8.1 servux.json
Segmented by provider; each segment holds that provider's settings. Every key can also be changed via /servux set <provider:key> <value> (no need to hand-edit). Type notation: int ranges are written [min..max] default.
servux_main (servux:main)
The config main channel — permanently enabled, and sends no network packets (only carries global settings).
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | Base permission level (0 = everyone) |
permission_level_admin |
int [0..4] | 3 | Admin-operation permission level |
permission_level_easy_place |
int [0..4] | 0 | EasyPlace permission level |
easy_place_validator_enabled |
bool | true | EasyPlace placement validator |
default_language |
string | en_us |
Default language |
debug_log |
bool | false | Debug master switch |
debug_categories |
string[] | [] |
Enabled debug categories (orthogonal to debug_log) |
hud_data (servux:hud_metadata)
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | HUD base permission |
update_interval |
int [20..300] | 40 | HUD push interval (ticks) |
share_weather_status |
bool | false | Whether to deliver weather |
weather_permission_level |
int [0..4] | 0 | Weather-data permission |
share_seed |
bool | false | Whether to deliver the world seed |
seed_permission_level |
int [0..4] | 2 | Seed-data permission |
loggers_enabled |
bool | false | Whether loggers are enabled (TPS/MobCap periodic data) |
loggers_enable_list |
string[] | ["tps","mob_caps"] |
Enabled logger types |
logger_permission_level |
int [0..4] | 0 | Loggers-data permission |
entity_data (servux:entity_data)
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | Base permission |
nbt_query_override |
bool | false | Enable standalone NBT-query permission (otherwise falls back to minecraft.command.data) |
nbt_query_permission_level |
int [0..4] | 2 | NBT-query permission |
fix_allay_gathering |
bool | true | Fix Allay gathering NBT |
nbt_allow_player_inventory |
bool | true | Allow querying a player's inventory |
nbt_allow_player_ender_items |
bool | true | Allow querying a player's ender chest |
player_inventory_permission_level |
int [0..4] | 2 | Inventory-query permission |
player_ender_items_permission_level |
int [0..4] | 2 | Ender-chest-query permission |
tweaks_data (servux:tweaks)
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | Base permission |
update_interval |
int [40..1200] | 120 | Push interval (ticks) |
⛔ The original
stackable_shulkers/stackable_shulkers_count/stackable_shulkers_fixhave been removed — shulker-box stacking is impossible without Mixin on Paper (see the fallback matrix); keeping it would make the client's Tweakeroo enable stacking rendering while the server doesn't cooperate → inconsistency.
structure_bounding_boxes (servux:structures)
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | Base permission |
structures_blacklist_enabled |
bool | false | Enable structure blacklist |
structures_whitelist_enabled |
bool | false | Enable structure whitelist |
structures_blacklist |
string[] | ["minecraft:buried_treasure"] |
Blacklisted structure IDs |
structures_whitelist |
string[] | [] |
Whitelisted structure IDs |
update_interval |
int [1..1200] | 40 | Scan interval (ticks) |
timeout |
int [40..1200] | 600 | Structure-scan timeout (ticks) |
litematic_data (servux:litematics)
| key | type | default | description |
|---|---|---|---|
permission_level |
int [0..4] | 0 | Base permission (transmit/receive) |
permission_level_paste |
int [0..4] | 0 | Paste-into-world permission |
fix_rail_rotations |
bool | true | Fix rail orientation on paste |
fix_stairs_mirror |
bool | true | Fix stairs mirroring on paste |
fix_chest_mirror |
bool | true | Fix chest mirroring on paste |
8.2 jei-recipe-bridge.json
| key | type | default | description |
|---|---|---|---|
enabled |
bool | true | Whether to sync recipes to joining players (toggled by /jei enable|disable) |
A missing / corrupt file is rebuilt from defaults and persisted.
8.3 syncmatica-config.json
Segmented by service (each service is a sub-object); prefer managing via /syncmatica commands over hand-editing:
{
"quota": { // upload-quota service
"enabled": false, // whether upload byte-quota is enabled (default off)
"limit": 40000000 // per-player upload byte cap (default ~40MB; progress is not persisted, resets on restart)
},
"debug": {
"doPacketLogging": false // send/receive packet logging (default off)
},
"debugLog": { // SyncmaticaDebug runtime snapshot (master + categories; /syncmatica debug persists immediately)
"master": false,
"categories": []
}
}
Quota constrains only
DownloadExchange(player uploads);UploadExchange(player downloads) is not checked.
9. Data Layout
plugins/VeryMcProto/
├── servux.json Servux global config (6 provider segments)
├── jei-recipe-bridge.json JEI config (enabled toggle)
├── syncmatica-config.json Syncmatica config (quota / debug / debugLog segments)
├── placements.json Syncmatica placement-metadata persistence (+ .bak / .new atomic write)
├── syncmatics/ Syncmatica .litematic central repository (player upload / download / share)
│ └── <hash-uuid>.litematic Filename = hash UUID (/syncmatica load identifies files by this)
└── schematics/ Servux schematic transmit directory
└── *.litematic Loaded by /servux litematic transmit; written by receiveFileTransmit
schematics/andsyncmatics/are created automatically on first access. On server shutdown (onDisable),placements.jsonis atomically saved bySyncmaticManager(backup → current ← incoming); on startup it is read, and corrupt entries are skipped one-by-one via try/catch and rewritten with corrections.
10. Feature Matrix
The original Servux has 26 Mixins + 2 AccessWideners; Syncmatica has 5 server-side Mixins. Paper has no Mixin runtime, so each is handled per the table below:
| Feature | Original impl | This project's handling | Status |
|---|---|---|---|
| Protocol data collection (reading private fields) | Mixin @Accessor / AccessWidener |
Reflection / direct NMS access | ✅ |
| Collection triggers / lifecycle | Mixin @Inject hooks |
Bukkit events + tick scheduling | ✅ |
| EasyPlace (Tweakeroo server cooperation) | Mixin altering placement logic | PacketEvents intercepts PLAYER_BLOCK_PLACEMENT + manually replays BlockItem.place side effects |
✅ needs PacketEvents |
| Mirror fixes (chest/rail/stairs) | Mixin | Inlined fixes on paste (fix_chest_mirror / fix_rail_rotations / fix_stairs_mirror) |
✅ (rail/stairs may be less perfect than Mixin) |
| UpdateSuppression | Mixin adding interface to Level/LevelChunk |
⛔ Omitted (no Paper equivalent) | ❌ |
| Shulker-box stacking | Mixin altering a global NMS method | ⛔ Impossible + all code removed | ❌ |
Debug (SharedConstants.IS_RUNNING_IN_IDE) |
Mixin | Omitted | — |
EasyPlace Details
EasyPlaceListener intercepts the vanilla PLAYER_BLOCK_PLACEMENT, cancels the packet, then calls PlacementHandler.applyPlacementProtocolV3 to decode the precise state and manually replays BlockItem.place side effects (setBlock / setPlacedBy / placement sound / item shrink / ack). PacketEvents class references are isolated in EasyPlaceBootstrap (reflective load + catch(Throwable) fallback) — without the packetevents plugin installed, EasyPlace is gracefully skipped and the other channels are completely unaffected.
⚠️ Why shulker-box stacking is impossible: it alters a global NMS method's behavior; Paper has no Mixin and no equivalent (reflection can't change a method's return value; Bukkit events always fail given
maxStackSize=1; setting theMAX_STACK_SIZEcomponent pollutes serialization). ThereforeTweaksDataProviderdoes not deliverstackingShulkersmetadata — otherwise Tweakeroo on the client would enable stacking rendering while the server doesn't cooperate → inconsistency.
11. Network Protocol
This is the cornerstone of the entire port. See
docs/02-network-protocol.mdanddocs/09-DELIVERY.mdfor details.
S2C Paths
| Mod | S2C path | Notes |
|---|---|---|
| Servux | plugin messaging (ProtocolChannel.send → player.sendPluginMessage) |
Large packets split by PacketSplitter |
| JEI Recipe Bridge | NMS ClientboundCustomPayloadPacket(new DiscardedPayload(id, bytes)) direct send |
Recipe packs routinely exceed 32KiB; plugin messaging would reject them |
| Syncmatica | defaults to NMS DiscardedPayload direct send (S2C_VIA_NMS=true; builds a [Identifier][body] compound body) |
/syncmatica debug s2c msg switches to plugin messaging for comparison |
Byte Limits
- Bukkit
Messenger.MAX_MESSAGE_SIZE= 1,048,576 (~1MiB) — the plugin-messaging API no longer rejects at 32KiB (old docs claiming 32768 are outdated). - The real S2C bottleneck is the vanilla client's 32,767-byte decode limit on
ClientboundCustomPayload— exceeding it disconnects the client. PacketSplittersplit constants: S2CMAX_PAYLOAD_PER_PACKET_S2C = 31,995(leaves headroom for the VarInt header, defending the client's 32,767 limit); receive capDEFAULT_MAX_RECEIVE_SIZE_S2C = 64MB.- Large packets (Recipe / Litematic schematics / Structures / bulk entities) must be split by
PacketSplitter. Syncmatica file-splitting does not reusePacketSplitter; it implements its own stop-and-wait (BUFFER_SIZE=16384, per-chunk ack).
C2S & Handshake
- The vanilla Paper server kicks the player on an unregistered custom payload ("Invalid payload"). This plugin receives C2S via
Messenger.registerIncomingPluginChannel— registered channels are routed by Paper internally and do not kick. - Handshake pitfall: during the configuration phase,
sendPluginMessageis silently dropped. The framework usesPlayerRegisterChannelEvent(the client declaring a channel = it has the corresponding mod = configuration phase complete) as a reliable signal to resend metadata / initiate the handshake inIDataProvider.onPlayerRegisterChannel/ syncmaticaonPlayerRegisterChannel.
12. Debugging
Each mod has an independent debug engine (master switch + orthogonal categories; both must be on for output); toggles persist immediately and fully survive restart.
Servux
/servux debug on Master on
/servux debug cat all All categories on (or individually lifecycle/handshake/network/...)
Categories: lifecycle handshake network packet tick permission provider config easyplace.
Syncmatica
/syncmatica debug on
/syncmatica debug cat all Categories: lifecycle handshake network packet exchange
Diagnosing syncmatica not working: on then cat all (or individually handshake/network/packet), and watch the handshake chain: declare channel → tryStartHandshake → init pushes REGISTER_VERSION → client replies with version → FeatureSet → CONFIRM_USER → broadcastTargets.
S2C-path troubleshooting: /syncmatica debug s2c (inspect) → /syncmatica debug s2c nms|msg (switch).
JEI
JEI has no independent debug engine; check state via /jei and watch server logs for join-time sync.
Symptom Lookup
| Symptom | Where to look |
|---|---|
| Client connects but receives nothing | Check provider enabled (/servux list); check permission_level; enable the handshake category to see whether handshake succeeded |
| Large schematic transmit / paste fails | Check for the client 32,767 disconnect; enable network/packet to inspect splitting |
| EasyPlace does nothing | Confirm PacketEvents plugin is installed (softdepend); enable the easyplace category |
| Syncmatica client can't connect | Defaults to NMS direct send; confirm with /syncmatica debug s2c; enable handshake to inspect the chain |
| JEI recipes don't sync | Confirm enabled via /jei; note it only affects players joining afterward |
13. Compatibility Testing
See docs/10-testing-guide.md (Servux) and docs/24-syncmatica-testing-guide.md (Syncmatica).
Channel–Mod Mapping
| Channel | MiniHUD | Litematica | Tweakeroo |
|---|---|---|---|
servux:hud_metadata |
✅ HUD info | — | — |
servux:structures |
✅ Structure bounding boxes | — | — |
servux:entity_data |
✅ NBT query | — | — |
servux:tweaks |
— | — | ✅ NBT query |
servux:litematics |
— | ✅ Schematic transmit/paste | — |
| EasyPlace | — | ✅ Precise placement | ✅ Triggers placement protocol |
Test Points
- Install the matching masa mods on the client; after joining, enable their debug (e.g. MiniHUD's
debugMessages) and observe the handshake. - HUD: check whether world info/TPS/MobCap refresh and whether structure bounding boxes render.
- NBT query: with MiniHUD/Tweakeroo, select an entity/block-entity and check whether NBT is returned.
- Schematic:
/servux litematic transmitto deliver; paste-upload from within Litematica. - Syncmatica: handshake → upload → download → modify placement → restart to verify persistence → multi-player collaboration.
14. Developers
Build
./gradlew build # Produce the reobf jar (loads directly on standard Paper)
./gradlew runServer # Start a local 1.21.11 test server (2G heap)
./gradlew test # Pure-function unit tests (PacketSplitter/FeatureSet/LitematicaBitArray, etc.)
Build chain: paperweight userdev 2.0.0-beta.21 + paperDevBundle("1.21.11-R0.1-SNAPSHOT") (fully-deobfuscated Mojang NMS at dev time) → reobfJar converts to Spigot runtime mappings. Reflection uses Mojang names (reobf does not transform reflection strings, and Paper's runtime is the Mojang mapping → reflecting on Mojang names is naturally correct).
Optional dependency: PacketEvents compileOnly("com.github.retrooper:packetevents-spigot:2.13.0") + plugin.yml: softdepend: [packetevents] (class references isolated in EasyPlaceBootstrap).
NMS Constraints
CompoundTag:getBoolean/getInt/...returnOptional/OptionalInt; usegetBooleanOr/getIntOror.orElse();putXxxreturnsvoid(not chainable).FriendlyByteBuf: the core of protocol-body encoding (writeVarInt/writeNbt/readNbt).CustomPacketPayload:record Payload(...) implements CustomPacketPayload+static Type<Payload> ID+static StreamCodec<FriendlyByteBuf, Payload> CODEC.Identifier:Identifier.fromNamespaceAndPath("servux","hud_metadata")(= MojangResourceLocation).DiscardedPayload: the NMS direct-send custom-payload carrier (new DiscardedPayload(Identifier, byte[])).
Add a Servux Provider
- Add a class under
mod/servux/dataproviders/(extends DataProviderBase), declaring its settings. - Add the corresponding Handler + Packet under
mod/servux/network/(channel codec + byte layout). - Add the channel constant in
ServuxReference. - Register it in
ServuxModule.onRegister. - See
docs/03-dataproviders-detail.md.
Add a Protocol Mod
- Implement
ModModuleundermod/<newmod>/(or self-managed assembly like syncmatica). - Register it in
VeryMcProto.onEnable. - Add commands / permissions in
plugin.yml.
Upgrade Minecraft
- Re-run paperweight to align with the new dev bundle.
- Re-verify every reflection point in
docs/04-mixin-analysis.mdagainst NMS field / method-signature drift (especiallyFriendlyByteBuf,CustomPacketPayload, theCompoundTagOptional migration, theStructureStart.createTagsignature, and theDiscardedPayloadconstructor).
15. Docs Index
Strongly recommended to start with docs/00-INDEX.md for the full doc map and suggested reading order.
| Doc | Content |
|---|---|
docs/01-servux-architecture.md |
Original architecture overview: startup flow, DataProviderManager, lifecycle, config system |
docs/02-network-protocol.md ⭐ |
Core network protocol: CustomPacketPayload, PacketSplitter splitting, 6 channels, byte layout |
docs/03-dataproviders-detail.md |
The 6 providers' data contents + collection (TPS/MobCap) + permission nodes |
docs/04-mixin-analysis.md |
Itemized list of 26 Mixins + 2 AccessWideners and their migration destinations |
docs/05-schematic-system.md ⭐ |
Litematica schematic system: BitArray/Palette/Selection/Placement/Transmit |
docs/06-fabric-vs-paper.md |
Fabric ↔ Paper framework-diff comparison table |
docs/07-migration-architecture.md ⭐ |
Complete migration plan: architecture / network layer / data collection / fallback matrix |
docs/09-DELIVERY.md |
Delivery / byte-limit deep dive (with the client 32767 limit evidence) |
docs/10-testing-guide.md |
Servux client compatibility testing |
docs/20–24 |
Complete Syncmatica implementation notes (architecture / protocol / Mixin migration / plan / testing) |
16. FAQ
Q: Why must we use paperweight / NMS instead of the pure Paper API?
A: Data collection depends heavily on NMS internals (NaturalSpawner.SpawnState, ServerTickRateManager, ChunkAccess.getAllReferences(), StructureStart.createTag(), Recipe.CODEC + NbtOps, BlockEntity.saveWithFullMetadata()); the network layer reuses vanilla FriendlyByteBuf / CompoundTag; and JEI/Syncmatica large-packet S2C relies on NMS ClientboundCustomPayloadPacket. The pure Paper API cannot reach these.
Q: Why does Syncmatica default to NMS direct send instead of plugin messaging?
A: Testing showed the pure Fabric syncmatica client is unreachable over the plugin-messaging wire and only reachable via NMS DiscardedPayload direct send.
Q: Do shulker-box stacking / UpdateSuppression work?
A: ⛔ No. The former alters a global NMS method (no Mixin / no equivalent on Paper; all code removed); the latter needs a Mixin adding an interface to Level/LevelChunk, and is omitted.
Q: What happens if PacketEvents isn't installed for EasyPlace?
A: EasyPlace is skipped automatically (EasyPlaceBootstrap reflective load + catch(Throwable) fallback); all other Servux channels, JEI, and Syncmatica are completely unaffected.
Q: What's the difference between permission_level 2 and 3?
A: Under pure Bukkit op there is no difference (both go through the isOp() binary). To differentiate levels, use LuckPerms to explicitly grant the corresponding permission node (see §7.2).
Q: What does pasting a schematic require?
A: The player needs creative mode + the servux.provider.litematic_data.paste permission (governed by litematic_data:permission_level_paste, default 0 = everyone).
17. Credits
This project is a Paper protocol-layer port of the following Fabric protocol mods — full credit to the original authors and the maintainers who keep them alive:
- Servux — originally by masa (
maruohon/servux); now maintained by sakura-ryoko (sakura-ryoko/servux). The server-side protocol implementation delivering data to MiniHUD / Litematica / Tweakeroo. - Litematica / malilib / MiniHUD / Tweakeroo / Item Scroller — originally by masa (
maruohon/*); now maintained by sakura-ryoko since masa retired from active development — the 1.21.11 LTS builds all live under sakura-ryoko:sakura-ryoko/litematica·sakura-ryoko/malilib·sakura-ryoko/minihud·sakura-ryoko/tweakeroo·sakura-ryoko/itemscroller- These are the client-side receivers of the protocols.
- Syncmatica — originally by endte (
End-Tech/syncmatica); now maintained by sakura-ryoko (sakura-ryoko/syncmatica). The shared schematic central repository. - JEIRecipeBridge — by Mrbysco (
Mrbysco/JEIRecipeBridge). The JEI recipe bridge.
References
- Paper dev docs
- Paper plugin messaging
- PaperWeight guide
- Minecraft Protocol Wiki (
Custom Payloadpacket structure) - Fabric networking docs
- FabricMC Discussion #4430 (Spigot/Paper ↔ Fabric custom-channel evidence)
- Sister project VeryMcBot (paperweight userdev + NMS reflection paradigm reference)
License
This project is licensed under the GNU Lesser General Public License v3.0 only — SPDX identifier LGPL-3.0-only. See the LICENSE file.
The reference archives under
OriginImpl/belong to their respective authors and licenses:servux/litematica/malilib/minihud/tweakeroo/itemscroller(masa → sakura-ryoko) are LGPL-3.0;syncmatica(endte → sakura-ryoko) is CC0. VeryMcProto is an independent Paper re-implementation (a protocol-layer port), not a derivative of their source.
Built for Paper 1.21.11 · Java 21 · No Mixin / No patch / No private fork
A protocol-layer port: client uses the original Fabric mods; server uses standard Paper + this plugin.
- Ships as VeryMcProto-1.0.0-reobf.jar — drop this file into the mods folder
- Download size: 521 KB
- Download link checked 9 Aug 2026 — working
These come from our own check of the pack file, not from the source page.