Zum Hauptinhalt springen

Java-zu-Bedrock-Konvertierung

ResourcePackManager kann das zusammengeführte Java-Ressourcenpaket in ein Bedrock-Ressourcenpaket umwandeln, damit GeyserMC-Clients dieselben benutzerdefinierten Inhalte wie Java-Clients sehen. Diese Funktion ist standardmäßig aktiviert.

Wann die Konvertierung läuft

Die Konvertierung ist daran gebunden, dass ein Bedrock-Ziel vorhanden ist. RSPM betrachtet ein Ziel als vorhanden, wenn eines der folgenden zutrifft:

  1. Geyser-Spigot ist auf diesem Backend installiert (Bedrock-Spieler treffen lokal auf Geyser).
  2. Floodgate ist auf diesem Backend installiert (typisches Proxy-Backend-Setup — Floodgate läuft lokal, Geyser ist anderswo).
  3. Der Netzwerkmodus ist aktiv — RSPM hat erkannt, dass es hinter einem Velocity-/BungeeCord-/Waterfall-Proxy läuft. Das Backend erzeugt sein Bedrock-Paket und stellt es über einen kleinen HTTP-Server bereit, damit das Proxy-Plugin es abholen kann.

Trifft keine dieser Bedingungen zu, ist der Konverter reiner Overhead und wird stillschweigend übersprungen. /rspm status erklärt genau, warum das Paket nicht erzeugt wurde.

Was konvertiert wird

Der Konverter ist namespace-agnostisch. Er durchläuft jede assets/<namespace>/items/**/*.json-Datei im Items-Definitionsformat 1.21.4+, rekursiv und einschließlich des minecraft-Namespace.

Weiterleitung flach vs. 3D

Für jedes Blattmodell entscheidet der Konverter, welche von zwei Pipelines verwendet wird. Modelle, die auf minecraft:item/generated oder minecraft:builtin/generated zurückgehen, bleiben auf dem flachen Pfad. Bei jeder anderen Elternkette geht ein Modell nur dann durch die 3D-Pipeline, wenn das zusammengeführte Modell ein nicht-leeres elements-Array trägt; ein Modell ohne Geometrie ist ein 2D-Sprite.

  • Flach — die layer0-Textur des Modells wird direkt nach textures/items/<hash>.png kopiert und als Geyser-Symbol registriert. Auf Bedrock zeigt das Item das korrekte 2D-Sprite im Inventar und in der Hand, genau so, wie Java es rendert.
  • 3D — der Konverter fügt einen Texturatlas zusammen, konvertiert die Java-Quader in Bedrock-Geometrie, erzeugt Halte-/Kopf-Animationen, rendert softwareseitig ein 64×64-Inventarsymbol und schreibt ein Attachable pro Zuordnung (Modell × Basis-Item × Prädikatform).

Warum die Geometrieprüfung wichtig ist: Ein flaches handgeführtes Werkzeug (Elternteil minecraft:item/handheld mit nur einer layer0-Textur und ohne Elemente) ist trotzdem ein 2D-Sprite. Frühere Versionen schoben flache handgeführte Items in die 3D-Pipeline, wo sie am Geometrieschritt scheiterten und auf Bedrock verschwanden oder auf das Vanilla-Basis-Item-Symbol zurückfielen. Besonders betroffen waren ItemsAdder-Pakete, die viele flache handgeführte Items ausliefern. Da elements aus der zusammengeführten Elternkette gelesen wird, wird ein nicht-generiertes Modell, das seine Geometrie von einem Elternteil erbt, weiterhin nach 3D geleitet.

Pro Zuordnung (Modell × Basis-Item × Prädikatform) wird ein eindeutiger Bedrock-Identifikator erzeugt, sodass ein einzelnes Schwertmodell, das mehreren Basis-Items oder Prädikatzweigen zugeordnet ist, auf der Geyser-Seite nicht kollidiert. Erzeugte Dateinamen sind kurze Inhalts-Hashes statt lesbarer Namen, weil vollständige Namespace-plus-Pfad-Namen regelmäßig Geysers Pfadlängen-Grenze von 80 Zeichen überschritten.

Veraltete Pakete vor 1.21.4

Pakete, die noch das alte Format assets/minecraft/models/item/*.json + overrides[].predicate.custom_model_data verwenden, werden ebenfalls erfasst und in die moderne Range-Dispatch-Form überführt. Das ist Best-Effort: Die Konsole vermerkt, wie viele Items das veraltete Format verwendet haben, da sie auf Bedrock oft nicht korrekt dargestellt werden. Die eigentliche Lösung ist, das Quellpaket auf das Items-Definitionsformat 1.21.4+ zu migrieren.

Handgeschriebene Bedrock-Entity-Bundles

Ein Plugin kann native Bedrock-Entity-Assets direkt ausliefern, indem es sie in seinem Java-Paket unter assets/<namespace>/rspm_bedrock_pack/ ablegt. RSPM kopiert diese Dateien unverändert in das erzeugte Bedrock-Paket. Nur entity-bezogene Verzeichnisse werden akzeptiert (entity, models/entity, animations, animation_controllers, render_controllers, materials, textures/entity), damit ein beitragendes Plugin nicht das Paketmanifest oder den Symbol-Atlas überschatten kann. Zu lange Pfade werden automatisch gekürzt, wobei JSON-Querverweise passend umgeschrieben werden, sodass Geometrie- und Texturverweise weiterhin auflösen. Zwei Namespaces, die unterschiedliche Bytes an dasselbe Ziel schreiben, sind ein harter Fehler statt eines stillen Überschreibens.

Das ist der Mechanismus hinter echten benutzerdefinierten Bedrock-Entities — siehe Geyser-Erweiterung & benutzerdefinierte Entities. Ein Paket, das nur Entity-Bundles und null Item-Mappings enthält, wird trotzdem ausgeliefert.

Benutzerdefinierte Rüstungssets werden erkannt, wenn eine benachbarte Datei assets/<namespace>/equipment/<material>.json existiert. Der Konverter verdrahtet ein Rüstungs-Attachable, das die Vanilla-Rüstungsgeometrie mit der Java-Textur als sichtbarer Schicht kombiniert, sodass Bedrock-Spieler beim Tragen des Items die richtige Rüstungstextur sehen.

Die Header-/Modul-UUIDs im Manifest des Bedrock-Pakets werden deterministisch aus dem Versionsstring des Plugins abgeleitet (Seeds rspm_bedrock_header:<pluginVersion> und rspm_bedrock_module:<pluginVersion>), sodass sie über Rebuilds derselben Plugin-Version stabil bleiben und sich nur ändern, wenn sich die Plugin-Version ändert. Der sichtbare Header-Name ist das feste ResourcePackManager Bedrock Pack; er ist nicht Teil der UUID. Das Versions-Tripel wird pro Build aus einem Cache-Bust-Token hochgezählt, das aus einem SHA-256-Inhalts-Digest des bereitgestellten Bedrock-Pakets abgeleitet wird — identische Inhalte ergeben dieselbe Version (sodass No-Op-Rebuilds Geysers Cache nicht aufwirbeln), während echte Inhaltsänderungen Bedrocks über (uuid, version) indizierten Paket-Cache invalidieren. Die Build-Zeit (System.currentTimeMillis()) wird nur als Fallback verwendet, wenn der Inhalts-Digest nicht berechnet werden kann.

Live-Auslieferung pro Session (eigenständig)

Wenn Geyser-Spigot auf demselben Backend erkannt wird, registriert RSPM einen SessionLoadResourcePacksEvent-Subscriber. Jeder Bedrock-Spieler, der nach einem frischen Mix beitritt, erhält das neueste Bedrock-Paket direkt von der Festplatte ausgeliefert — für Textur- oder Modellbearbeitungen an bestehenden Items ist kein Serverneustart erforderlich.

Geysers Mappings für benutzerdefinierte Items (das JSON in custom_mappings/) sind weiterhin beim Booten eingefroren, daher erfordert das Hinzufügen neuer oder das Entfernen bestehender Custom-Items einen Serverneustart, bevor Bedrock-Clients diese Änderungen sehen. RSPM stellt die Mapping-Datei des vorherigen Laufs früh beim Startup bereit, damit Geysers Custom-Item-Registrierung sie beim Booten automatisch aufgreift.

Aktuell verbundene Bedrock-Spieler behalten das Paket, das sie zum Zeitpunkt ihres Beitritts erhalten haben — das ist eine Einschränkung des Bedrock-Protokolls, nichts, was das Plugin mitten in der Session überschreiben kann.

Wie es im Proxy-Modus funktioniert

In einem Proxy-Netzwerk registriert das Backend selbst keinen SessionLoadResourcePacks-Subscriber (es gibt kein lokales Geyser, bei dem man sich registrieren könnte). Stattdessen:

  1. Das Backend erzeugt output/ResourcePackManager_Bedrock.zip und, sofern Item-Mappings existieren, output/rspm_geyser_mappings.json.
  2. Das Backend startet einen kleinen HTTP-Server (automatisch abgeleiteter Port, standardmäßig mcPort + 1), der die Routen /bedrock.zip und /mappings.json bereitstellt, die bei jeder Anfrage die Datei frisch einlesen, und kündigt dem Proxy den genauen Port an, an den es gebunden hat.
  3. Das Proxy-Plugin pollt alle 5 Sekunden, bevorzugt starke ETags über If-None-Match und behält die If-Modified-Since-Kompatibilität für ältere Backends bei. Es lädt die Ausgaben jedes Backends herunter, wenn sie sich ändern, und wartet, bis der Posteingang stabil ist.
  4. Das Proxy-Plugin führt das Bedrock-Paket jedes Backends zu einem einzigen netzwerkweiten Paket zusammen und liefert es über das Geyser des Proxys an Bedrock-Clients aus.
  5. Wenn der Proxy den HTTP-Port eines Backends nicht direkt erreichen kann (häufig bei Shared-/Managed-Hosting, wo benachbarte Ports durch eine Firewall blockiert sind), schiebt das Backend seine Dateien an einen magmaguy.com-Relay-Endpunkt, und der Proxy holt sie dort ab.

Siehe Proxy-Netzwerke für die Einrichtung. Das Zusammenführen auf der Proxy-Seite läuft automatisch und hat keinen Aktivierungsschalter. Die Proxy-Konfiguration hat nur zwei Einstellungen: network-http-offset-v2, den Fallback-Port-Offset, der verwendet wird, bevor eine Endpunkt-Ankündigung eines Backends vorliegt, und geyser-extension-auto-install, das proxy-seitige Gegenstück zu geyserExtensionAutoInstall.

Ausgabedateien

Nach einem erfolgreichen Mix liegen die Bedrock-Dateien in:

plugins/ResourcePackManager/output/ResourcePackManager_Bedrock.zip
plugins/ResourcePackManager/output/rspm_geyser_mappings.json # only when item mappings exist

Wenn Auto-Deploy aktiviert ist und ein lokaler Geyser-Datenordner erkannt wurde, wird die Mapping-Datei zusätzlich kopiert nach:

<geyser-folder>/custom_mappings/rspm_geyser_mappings.json

Die Bedrock-Paket-ZIP wird nicht nach <geyser-folder>/packs/ kopiert — sie wird stattdessen live pro Session ausgeliefert. Wenn ein älteres RSPM-Release eine ResourcePackManager_Bedrock.zip in Geysers Paketverzeichnis hinterlassen hat, löscht das aktuelle Plugin sie nicht, während Geyser läuft: Geyser hat diesen Pfad bereits gescannt und hält die Datei möglicherweise noch im Speicher. RSPM überspringt für diesen Boot die Registrierung des Live-Providers und gibt den genauen Altpfad aus. Fahre den Server vollständig herunter, lösche nur diese Altdatei und starte den Server dann wieder. Ein /reload genügt nicht.

Wenn der Konverter nichts zum Veröffentlichen findet (keine konvertierbaren Item-Mappings und keine erlaubten Entity-Bundle-Dateien), löscht RSPM jede veraltete Bedrock-Ausgabe eines vorherigen Laufs, anstatt ein leeres Paket auszuliefern. Die /bedrock.zip-Route des Backends gibt dann sauber 404 zurück, was für den Proxy das richtige Signal ist, dass dieses Backend keinen Bedrock-Inhalt beizusteuern hat. Pakete, die nur Entities enthalten, werden weiterhin veröffentlicht.

Einstellungen in config.yml

# Toggles Java-to-Bedrock conversion altogether.
bedrockConversionEnabled: true

# Copies the Geyser custom mappings file into the detected Geyser folder's
# custom_mappings/ directory on each mix.
bedrockAutoDeployToGeyser: true

# Manual override for the Geyser data folder. Empty = auto-detect.
# Relative values are tried from the server working directory first, then
# relative to plugins/. Absolute paths work directly.
bedrockGeyserFolder: ""

# Installs and updates the universal ResourcePackManager.jar in Geyser's
# extensions/ folder, which is what makes custom Bedrock ENTITIES render
# instead of armor stands. Separate from pack conversion above — items,
# textures and models convert and serve normally either way.
# Setting this false stops future installation and update staging; it does NOT
# remove an extension jar that is already installed. Delete that by hand while
# Geyser is stopped. See the Geyser extension page.
geyserExtensionAutoInstall: true

# Verbose per-item / per-bone progress logging from the Bedrock pipeline.
# Default false — a clean run emits a single "Bedrock conversion complete: N
# mappings" summary instead of dozens to hundreds of per-item lines. Flip on
# when debugging a specific conversion issue.
bedrockConverterDebug: false

Die automatische Erkennung des Geyser-Ordners prüft in dieser Reihenfolge:

  1. bedrockGeyserFolder, falls gesetzt (wird zuerst genau so verwendet, wie er geschrieben steht, sodass relative Pfade vom Arbeitsverzeichnis des Servers aus aufgelöst werden; existiert der nicht, wird er relativ zu plugins/ versucht). Absolute Pfade funktionieren ebenfalls.
  2. plugins/Geyser-Spigot/
  3. plugins/Geyser-*/ (jede Variante)
  4. config/Geyser-*/ (für Fabric-/NeoForge-Setups)

Feinjustierung der Anzeige gehaltener Items: bedrock_display_offsets.yml

Bedrock rendert das gehaltene Item über einen Eltern-Bone, dessen Ruhepose von den Java-Transformationen für Ego- und Drittperson abweicht, sodass die algorithmische Konvertierung einen Basis-Offset zusätzlich zu dem anwenden muss, was die display-Transformation des Java-Modells vorgibt. Die Standard-Offsets funktionieren für typische rechtshändige Java-Modelle, aber Sonderfälle können Anpassungen erfordern.

Ego- und Drittpersonperspektive sind zwei vollständig getrennte Bedrock-Render-Durchläufe (unterschiedliche Eltern-Bones, unterschiedliche Ruheposen), daher hat jede ihren eigenen unabhängigen Satz von sechs Stellschrauben. Die eine zu tunen wirkt sich nicht auf die andere aus.

# ===== First-person (right hand, seen by the holder) =====
firstPersonBaseRotationX: -60.0 # pitch (tipping toward/away from camera)
firstPersonBaseRotationY: 123.0 # yaw (spinning around vertical line)
firstPersonBaseRotationZ: 170.0 # roll (around camera-forward axis)
firstPersonBasePositionX: -8.0 # vertical on screen (positive = up)
firstPersonBasePositionY: 7.5 # depth (positive = further into the scene)
firstPersonBasePositionZ: -5.0 # horizontal on screen (positive = right)

# ===== Third-person (right hand, seen by other players / F5) =====
thirdPersonBaseRotationX: 90.0 # pitch as observers see it
thirdPersonBaseRotationY: 0.0 # yaw
thirdPersonBaseRotationZ: 0.0 # roll around the item's long axis
thirdPersonBasePositionX: 0.0 # horizontal across the holder's body (positive = outward)
thirdPersonBasePositionY: 6.0 # vertical (positive = raises the model)
thirdPersonBasePositionZ: -10.0 # depth relative to holder (positive = forward)

Positionswerte sind in Pixeln angegeben, wobei 1 Pixel = 1/16 Block. Rotationen sind in Grad angegeben.

Ändere den Wert, führe /rspm reload aus und verbinde den Bedrock-Testclient neu, damit sein nächster Beitritt das neu gebaute Paket erhält. Iteriere, bis das gehaltene Item richtig aussieht.

Debug-Protokollierung

Es stehen zwei Debug-Oberflächen zur Verfügung:

  • Backend: bedrockConverterDebug: true in der config.yml aktiviert Protokollzeilen des Konverters pro Item, pro Attachable und pro Mapping. Nützlich, wenn du wissen musst, warum ein bestimmtes Item nicht ins Bedrock-Paket gelangt ist. Das ist getrennt von verboseLogging, das das Zusammenführen und Hosten von Paketen abdeckt statt der Bedrock-Pipeline — bei einem Konvertierungsproblem willst du bedrockConverterDebug.
  • Proxy (Velocity und BungeeCord): /rspm debug bedrock on schaltet den [RSPM-BedrockDebug]-Log-Stream um, der vom GeyserBinder des Proxys ausgegeben wird. Nützlich, wenn Bedrock-Spieler den Proxy betreten, aber das Paket nicht sehen. Die Einstellung wird bei einem Proxy-Neustart auf „aus" zurückgesetzt, damit sie nicht versehentlich aktiviert bleiben kann.

Einschränkungen und bekanntes Verhalten

  • 3D-Inventarsymbole werden softwareseitig aus der display.gui-Transformation des Java-Modells gerendert. Das Ergebnis ist passabel, aber nicht pixelgenau; wenn das Symbol falsch aussieht, ist die häufigste Ursache eine fehlende/falsch benannte Texturdatei, auf die das Modell verweist.
  • Flipbook-Texturen, die als Item-Symbole verwendet werden, werden auf Frame 0 zugeschnitten — Bedrocks item_texture.json unterstützt keine animierten Symbole, sondern nur animierte Block-/Terrain-Texturen über flipbook_textures.json.
  • Die Geometrie-Formatversion von Attachables ist fest auf 1.21.0 festgelegt; aktualisiere Geyser, falls deine Installation sie nicht parsen kann.
  • Veraltete Vanilla-Item-Model-Override-Dateien (alles unter assets/minecraft/models/item/, einschließlich shield.json und crossbow.json) werden paketübergreifend zusammengeführt, statt ein Paket vollständig gewinnen zu lassen: Es werden nur die overrides-Arrays kombiniert (dedupliziert nach Override-Schlüssel), während Nicht-Override-Felder weiterhin „höchste Priorität gewinnt" folgen. Keine Datei wird für eine Sonderbehandlung herausgegriffen.
  • Wenn der Konverter eine referenzierte Textur- oder Modelldatei nicht auflösen kann, wird dieses Blatt übersprungen und die restliche Pipeline läuft weiter. Aktiviere bedrockConverterDebug für detaillierte Auflösungs-Traces. Eine normale Warnung wird ausgegeben, wenn ein Item am Ende überhaupt keine gültigen Custom-Texturen hat oder ein referenziertes Modell-JSON nicht geparst werden kann.
  • Eine fehlerhafte Item-Definition ist ein anderer Fall und ist jetzt fatal für den Zyklus: Nicht parsbares JSON bricht die gesamte Konvertierung mit Bedrock conversion failed: ... ab, statt still ein unvollständiges Paket zu erzeugen. Ein Paket, das früher „größtenteils" konvertierte, sagt dir jetzt, dass es das nicht getan hat.
  • Banner- und Redstone-Basis-Items werden übersprungen. Benutzerdefinierte Items, deren Basis eines der 16 gefärbten Banner oder minecraft:redstone ist, erhalten kein Geyser-Custom-Item-Mapping, weil Geyser aus diesen Basen einen ungültigen Block-Platzierer ableitet. Bedrock zeigt für sie das Vanilla-Symbol. Die Konsole nennt die betroffenen Items, wenn das passiert.
  • Die Konvertierung ist kooperativ abbrechbar: Ein /rspm reload oder ein Herunterfahren mittendrin bricht sauber ab, statt halb geschriebene Ausgaben zu hinterlassen. Die Geyser-Mappings-Datei wird erst veröffentlicht, nachdem das Paket-Zip erfolgreich war, sodass du nie ein neues Paket mit veralteten Mappings kombiniert bekommst.
  • Wenn das zusammengeführte Paket weder konvertierbare Item-Mappings noch erlaubte Entity-Bundle-Dateien enthält, wird kein Bedrock-Paket erzeugt und jede Ausgabe eines vorherigen Laufs wird gelöscht. Ein Paket, das nur Entities enthält, ist trotzdem gültig und wird auch bei null Item-Mappings erzeugt.

Optimierung der Paketgröße

Bevor RSPM ein Bedrock-Paket veröffentlicht, dedupliziert es byteweise identische Texturdateien mit derselben Dateiendung und schreibt exakte JSON-Texturverweise auf die beibehaltene Datei um. Aliase werden bewusst beibehalten, wenn ein Verweis mehrdeutig ist, in einen größeren String eingebettet ist oder in fehlerhaftem/undurchsichtigem JSON gefunden wird, sodass die Optimierung keine Ressourcenverweise stillschweigend zerstört.