-
-
Notifications
You must be signed in to change notification settings - Fork 67
26.2: Documentation for Custom Waypoints style API and Custom Entities #161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
26be38e
Write documentation for the new custom waypoints style API
eclipseisoffline 2a8e6bb
Update Rainbow's wiki page and add it to the index
eclipseisoffline 47c83ec
Add item display disclaimer to Rainbow wiki, reference to Rainbow in …
eclipseisoffline ef5ce6d
Some more waypoint style wiki and other small things
eclipseisoffline fac8746
Update wiki/geyser/custom-waypoints.mdx
onebeastchris ebbcc40
Document (custom) entity API (#164)
onebeastchris d3b1ad2
Java 26.2 (#167)
Novampr 0bcd57b
Rename "custom resource pack" section to "custom content", update doc…
onebeastchris 084f428
Apply suggestions from code review
onebeastchris File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,12 @@ | ||
| { | ||
| "bedrock": { | ||
| "supported": "26.0-26.30", | ||
| "supported": "26.0-26.32", | ||
| "latest": { | ||
| "id": 1001, | ||
| "name": "26.30" | ||
| "name": "26.32" | ||
| } | ||
| }, | ||
| "java": { | ||
| "supported": "26.1-26.1.2" | ||
| "supported": "26.2" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| --- | ||
| title: Geyser Entity API | ||
| description: Geyser extensions can register custom Bedrock entity definitions, modify current entities, and replace built-in types in entity spawning events. | ||
| --- | ||
|
|
||
| :::warning Experimental API | ||
| The (Custom) Entity API was introduced with Geyser API **2.11.0** (26.2 update) and is currently marked `@ApiStatus.Experimental`. This means that the API may change or be rewritten in parts in a future version without prior deprecation. | ||
| If you have feedback on this API, encounter issues, or wish to request further features, please reach out to us! | ||
|
|
||
| The `GeyserDefineEntityPropertiesEvent` has been available since **2.9.0**, but its identifier parameter changed in 2.11.0: it now takes a **Bedrock** entity identifier instead of a Java one. See [Entity Properties](#entity-properties) for details. | ||
| ::: | ||
|
|
||
| :::info | ||
| This API currently cannot be used via JSON mappings. In the future, we are planning to support entity variants, which would likely also usable through JSON mappings. | ||
| ::: | ||
|
|
||
| Custom entities currently (as of 26.2) do not exist in Minecraft: Java Edition. Instead, they can be simulated with armor stands holding item models, or item/block display entity combinations. | ||
| Unlike Java Edition, Bedrock does support custom entity types, but does not feature item or block displays. With this API, Geyser extensions can register custom entity definitions to use instead of Java | ||
| entity types in entity spawning events to properly support custom entities for Bedrock players. Further, it allows modifying entity properties and data for any entity sent to a Bedrock player at runtime. | ||
|
|
||
| Additionally to registering custom entity definitions, you will also need to provide a resource pack to players [defining custom entity textures and animations](https://wiki.bedrock.dev/guide/custom-entity). | ||
|
|
||
| ## Prerequisites: Vocabulary {#vocabulary} | ||
|
|
||
| - **Bedrock Entity Definition** (`GeyserEntityDefinition` / `CustomEntityDefinition`): Identifies the Bedrock entity type to spawn, either a built-in type, or custom | ||
| - **Entity Properties**: Bedrock Molang-queryable values (`query.property(...)`) registered per Bedrock entity type. See [here](https://learn.microsoft.com/en-us/minecraft/creator/documents/introductiontoentityproperties?view=minecraft-bedrock-stable) for official documentation. | ||
| - **Entity Data Types**: Properties on entities that can be changed dynamically, such as scale, size, hitboxes, and color. | ||
|
|
||
| ## Registering a Custom Entity Definition {#registering-entity-definition} | ||
|
|
||
| Custom entity definitions are registered using `GeyserDefineEntitiesEvent`, which fires once during Geyser's startup: | ||
|
|
||
| ```java | ||
| @Subscribe | ||
| public void onDefineEntities(GeyserDefineEntitiesEvent event) { | ||
| CustomEntityDefinition myEntity = CustomEntityDefinition.of(Identifier.of("mynamespace:my_entity")); | ||
| event.register(myEntity); | ||
| } | ||
| ``` | ||
|
|
||
| Do note: | ||
| - Custom entity definition type identifier must not use the `minecraft` namespace | ||
| - Entity types must have a unique identifier | ||
|
|
||
| ## Summoning custom entities {#custom-entity-spawning} | ||
|
|
||
| Whenever the Java server creates a new non-player entity for any connection, a `ServerSpawnEntityEvent` is fired. It can be used to change which Bedrock entity definition is sent to the Bedrock player or cancel the spawn entirely. | ||
| Each connection has its own entity cache, so different players will never share the same entity instance. | ||
|
|
||
| Example: | ||
|
|
||
| ```java | ||
|
|
||
| private static final Identifier ZOMBIE = Identifier.of("minecraft:zombie"); | ||
| private static final CustomEntityDefinition MY_ENTITY = CustomEntityDefinition.of(Identifier.of("mynamespace:my_entity")); | ||
|
|
||
| @Subscribe | ||
| public void onSpawn(ServerSpawnEntityEvent event) { | ||
| if (event.entityType().is(ZOMBIE)) { | ||
| event.definition(MY_ENTITY); // definition must be registered beforehand | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Optionally, a consumer for the resulting `GeyserEntity` can be provided to set initial entity data values before the entity is spawned: | ||
|
|
||
| ```java | ||
| private static final Identifier ZOMBIE = Identifier.of("minecraft:zombie"); | ||
| private static final CustomEntityDefinition MY_ENTITY = CustomEntityDefinition.of(Identifier.of("mynamespace:my_entity")); | ||
|
|
||
| @Subscribe | ||
| public void onSpawn(ServerSpawnEntityEvent event) { | ||
| if (!event.entityType().is(ZOMBIE)) { | ||
| return; | ||
| } | ||
| event.definition(MY_ENTITY); | ||
| event.preSpawnConsumer(entity -> { | ||
| entity.update(GeyserEntityDataTypes.SCALE, 2.0f); | ||
| entity.update(GeyserEntityDataTypes.COLOR, (byte) 5); | ||
| }); | ||
| } | ||
| ``` | ||
|
|
||
| ### Modifying shoulder parrots {#shoulder-parrots} | ||
|
|
||
| `ServerAttachParrotsEvent` fires when a parrot is attached to a player's shoulder. It extends `ServerSpawnEntityEvent`, so definition replacement, cancellation, and `preSpawnConsumer` are supported. | ||
|
|
||
| ```java | ||
| @Subscribe | ||
| public void onParrotAttach(ServerAttachParrotsEvent event) { | ||
| event.definition(myParrotReplacement); // can also be canceled | ||
| } | ||
| ``` | ||
|
|
||
| ## Modifying entity data {#entity-data} | ||
|
|
||
| Entity data consists of runtime-modifiable values such as scale, size, and hitboxes. All constants live in `GeyserEntityDataTypes`. Values for these types can be updated on a `GeyserEntity` | ||
| at any time using `entity.update(type, value)`, or set inside a pre-spawn consumer in the entity spawn events to modify it before the spawn packet is sent. | ||
|
onebeastchris marked this conversation as resolved.
Outdated
|
||
|
|
||
| Updating any of these values will override the value sent by the server until the override is removed. To remove an override, a `null` value can be used. | ||
|
|
||
| | Constant | Value Type | Description | | ||
| |------------------------------|----------------|------------------------------------------------------------------------| | ||
| | `COLOR` | `Byte` | Bedrock color component (0–15) | | ||
| | `VARIANT` | `Integer` | Numeric variant index, queryable via `query.variant` in resource packs | | ||
| | `WIDTH` | `Float` | Collision box width | | ||
| | `HEIGHT` | `Float` | Collision box height | | ||
| | `VERTICAL_OFFSET` | `Float` | Y-axis offset applied on top of the Java entity position | | ||
| | `SCALE` | `Float` | Visual scale multiplier | | ||
| | `HITBOXES` | `List<Hitbox>` | Custom hitboxes. Use an empty list to remove all hitboxes | | ||
| | `SEAT_OFFSET` | `Vector3f` | Riding position offset | | ||
| | `ROTATION_LOCKED_TO_VEHICLE` | `Boolean` | Whether the rider's rotation is locked to the vehicle's rotation | | ||
| | `ROTATE_RIDER_DEGREES` | `Float` | Rotation offset for the seat in degrees | | ||
|
|
||
| :::info | ||
| Hitbox `min`, `max` and `pivot` are absolute world coordinates, not relative to the entity's position. | ||
| ::: | ||
|
|
||
| ## Entity Properties {#entity-properties} | ||
|
|
||
| Entity properties expose Java-side state to Bedrock resource packs via `query.property('namespace:name')` in Molang. Entity properties can be registered for both custom, and vanilla entity types using the `GeyserDefineEntityPropertiesEvent`, which fires during Geyser startup. | ||
|
|
||
| :::warning Breaking Change in 2.11.0 | ||
| `GeyserDefineEntityPropertiesEvent` has been available since **2.9.0**, but its first parameter changed in 2.11.0: it now takes a **Bedrock** entity identifier (e.g. `minecraft:zombie`) instead of a Java entity identifier. | ||
| ::: | ||
|
|
||
| A maximum of 32 properties per entity type can be registered. | ||
|
|
||
| ```java | ||
| private GeyserFloatEntityProperty aggression = null; | ||
| private GeyserIntEntityProperty state = null; | ||
| private GeyserBooleanEntityProperty enraged = null; | ||
| private GeyserEnumEntityProperty<Phase> phase = null; | ||
| private GeyserStringEnumProperty mode = null; | ||
|
|
||
| @Subscribe | ||
| public void onDefineProperties(GeyserDefineEntityPropertiesEvent event) { | ||
| Identifier zombieType = Identifier.of("minecraft:zombie"); | ||
|
|
||
| // Float property: min, max, default (null default uses min) | ||
| aggression = event.registerFloatProperty(zombieType, Identifier.of("mynamespace:aggression"), 0f, 1f, 0f); | ||
|
|
||
| // Integer property | ||
| state = event.registerIntegerProperty(zombieType, Identifier.of("mynamespace:state"), 0, 10, null); | ||
|
|
||
| // Boolean property | ||
| enraged = event.registerBooleanProperty(zombieType, Identifier.of("mynamespace:enraged"), false); | ||
|
|
||
| // Enum from a Java enum class (max 16 values, names max 32 chars, must start with a letter) | ||
| phase = event.registerEnumProperty(zombieType, Identifier.of("mynamespace:phase"), Phase.class, Phase.IDLE); | ||
|
|
||
| // Enum from a string list | ||
| mode = event.registerEnumProperty(zombieType, Identifier.of("mynamespace:mode"), List.of("idle", "active", "fleeing"), "idle"); | ||
| } | ||
| ``` | ||
|
|
||
| Properties can be updated on a `GeyserEntity` instance at any time: | ||
|
|
||
| ```java | ||
| // Single property | ||
| entity.updateProperty(aggression, 0.5f); | ||
| ``` | ||
|
|
||
| ## Looking up entities {#looking-up-entities} | ||
|
|
||
| After an entity has spawned it can be looked up through `GeyserConnection#entities()`. All lookup methods are thread-safe. | ||
|
|
||
| ```java | ||
| EntityData entityData = connection.entities(); | ||
|
|
||
| // By Java entity ID (int) | ||
| GeyserEntity entity = entityData.byJavaId(javaId); | ||
|
|
||
| // By UUID | ||
| GeyserEntity entity = entityData.byUuid(uuid); | ||
|
|
||
| // By Geyser/Bedrock runtime ID (long) | ||
| GeyserEntity entity = entityData.byGeyserId(geyserId); | ||
| ``` | ||
|
|
||
| All three return `null` if no entity is found. A `GeyserEntity` exposes various properties, such as the entity uuid, current passengers / vehicle if applicable, and it can further be used to update | ||
| entity properties or entity data type values. | ||
|
|
||
| ## Full Example {#full-example} | ||
|
|
||
| <details> | ||
| <summary>Expand for a full extension example</summary> | ||
|
|
||
| ```java | ||
| public class MyExtension implements Extension { | ||
| // Create a custom entity definition | ||
| private final CustomEntityDefinition enhancedZombie = CustomEntityDefinition.of(Identifier.of("myext:enhanced_zombie")); | ||
| private GeyserFloatEntityProperty healthFraction = null; | ||
|
|
||
| // Register the custom entity type | ||
| @Subscribe | ||
| public void onDefineEntities(GeyserDefineEntitiesEvent event) { | ||
| event.register(enhancedZombie); | ||
| } | ||
|
|
||
| // Optionally: Register entity properties (Bedrock identifier) | ||
| @Subscribe | ||
| public void onDefineProperties(GeyserDefineEntityPropertiesEvent event) { | ||
| healthFraction = event.registerFloatProperty( | ||
| enhancedZombie.identifier(), | ||
| Identifier.of("myext:health_fraction"), | ||
| 0f, 1f, 1f | ||
| ); | ||
| } | ||
|
|
||
| // Replace a default Bedrock entity definition with our custom one | ||
| @Subscribe | ||
| public void onSpawn(ServerSpawnEntityEvent event) { | ||
| // Unless you want to replace everything, you should probably add checks for e.g., entity type, or entity UUID | ||
| event.definition(enhancedZombie); | ||
| event.preSpawnConsumer(entity -> { | ||
| entity.update(GeyserEntityDataTypes.SCALE, 1.5f); | ||
| entity.update(GeyserEntityDataTypes.COLOR, (byte) 4); | ||
| }); | ||
| } | ||
| } | ||
| ``` | ||
| </details> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.