diff --git a/README.md b/README.md index 601b136f80b..ace19723e65 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ Special thanks to the DragonProxy project for being a trailblazer in protocol tr ## Supported Versions -| Edition | Supported Versions | -|---------|------------------------------------------------------------------------------------------------------------| +| Edition | Supported Versions | +|---------|---------------------------------------------------------------------------------------------------| | Bedrock | 26.0, 26.1, 26.2, 26.3, 26.10, 26.20, 26.21, 26.22, 26.23, 26.30, 26.31, 26.32, 26.33 | -| Java | 26.1 - 26.1.2 (For older versions, [see this guide](https://geysermc.org/wiki/geyser/supported-versions/)) | +| Java | 26.2 (For older versions, [see this guide](https://geysermc.org/wiki/geyser/supported-versions/)) | ## Setting Up Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index 389b721a436..714082a3c65 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -25,14 +25,12 @@ package org.geysermc.geyser.api.connection; -import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.Positive; import org.geysermc.api.connection.Connection; import org.geysermc.geyser.api.bedrock.camera.CameraData; import org.geysermc.geyser.api.bedrock.camera.CameraShake; import org.geysermc.geyser.api.command.CommandSource; import org.geysermc.geyser.api.entity.EntityData; -import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; import org.geysermc.geyser.api.skin.SkinData; import org.jspecify.annotations.Nullable; @@ -40,7 +38,6 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** * Represents a player connection used in Geyser. @@ -57,7 +54,7 @@ public interface GeyserConnection extends Connection, CommandSource { /** * Exposes the {@link EntityData} for this connection. - * It allows you to get entities by their Java entity ID, show emotes, and get the player entity. + * It allows you to look up other entities through various methods. * * @return the EntityData for this connection. */ @@ -164,14 +161,6 @@ public interface GeyserConnection extends Connection, CommandSource { */ void sendSkin(UUID player, SkinData skinData); - /** - * @param javaId the Java entity ID to look up. - * @return a {@link GeyserEntity} if present in this connection's entity tracker. - * @deprecated Use {@link EntityData#entityByJavaId(int)} instead - */ - @Deprecated - CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId); - /** * Displays a player entity as emoting to this client. * diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java b/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java index 44c0254e0ef..e6ff771ac7c 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/EntityData.java @@ -29,24 +29,57 @@ import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.entity.type.GeyserEntity; import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; +import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.Nullable; import java.util.UUID; import java.util.concurrent.CompletableFuture; /** - * This class holds all the methods that relate to entities. - * Can be accessed through {@link GeyserConnection#entities()}. + * Provides entity lookup and input-lock utilities for a specific connection. + * Accessed via {@link GeyserConnection#entities()}. */ public interface EntityData { /** - * Returns a {@link GeyserEntity} to e.g. make them play an emote. + * @deprecated use {@link #byJavaId(int)} + * @since 2.3.0 + */ + @Deprecated(since = "2.11.0") + CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId); + + /** + * Returns the {@link GeyserEntity} for the given Java entity ID if it is tracked + * in this connection's entity cache, or {@code null} if not found. * * @param javaId the Java entity ID to look up - * @return a {@link GeyserEntity} if present in this connection's entity tracker + * @return the entity, or {@code null} if not found + * @since 2.11.0 */ - CompletableFuture<@Nullable GeyserEntity> entityByJavaId(@NonNegative int javaId); + @ApiStatus.Experimental + @Nullable GeyserEntity byJavaId(@NonNegative int javaId); + + /** + * Returns the {@link GeyserEntity} for the given Java entity UUID if it is tracked + * in this connection's entity cache, or {@code null} if not found. + * + * @param javaUuid the Java entity UUID to look up + * @return the entity, or {@code null} if not found + * @since 2.11.0 + */ + @ApiStatus.Experimental + @Nullable GeyserEntity byUuid(UUID javaUuid); + + /** + * Returns the {@link GeyserEntity} for the given Geyser runtime entity ID if it is tracked + * in this connection's entity cache, or {@code null} if not found. + * + * @param geyserId the Geyser entity ID (as returned by {@link GeyserEntity#geyserId()}) + * @return the entity, or {@code null} if not found + * @since 2.11.0 + */ + @ApiStatus.Experimental + @Nullable GeyserEntity byGeyserId(@NonNegative long geyserId); /** * (Un)locks the client's movement inputs, so that they cannot move. @@ -79,7 +112,7 @@ public interface EntityData { void showEmote(GeyserPlayerEntity emoter, String emoteId); /** - * @deprecated Use {@link GeyserConnection#playerEntity} instead. + * @deprecated Use {@link GeyserConnection#playerEntity()} instead. */ @Deprecated(since = "2.9.3") GeyserPlayerEntity playerEntity(); diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/custom/CustomEntityDefinition.java b/api/src/main/java/org/geysermc/geyser/api/entity/custom/CustomEntityDefinition.java new file mode 100644 index 00000000000..e35c29ad800 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/custom/CustomEntityDefinition.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.custom; + +import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.entity.definition.GeyserEntityDefinition; +import org.geysermc.geyser.api.event.java.ServerAttachParrotsEvent; +import org.geysermc.geyser.api.event.java.ServerSpawnEntityEvent; +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents a Bedrock entity definition for a custom entity. + * These cannot be in the {@code minecraft} namespace, and have to be manually + * spawned using either the {@link ServerSpawnEntityEvent} or {@link ServerAttachParrotsEvent}. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public interface CustomEntityDefinition extends GeyserEntityDefinition { + + /** + * {@inheritDoc} + */ + @Override + @ApiStatus.Experimental + default boolean vanilla() { + return false; + } + + /** + * Creates or retrieves a custom entity definition by the Bedrock entity type identifier. + * + * @param identifier the Bedrock entity identifier + * @return customEntityDefinition + * @since 2.11.0 + */ + @ApiStatus.Experimental + static CustomEntityDefinition of(Identifier identifier) { + if (identifier.vanilla()) { + throw new IllegalArgumentException( + "Custom entity identifiers cannot use the 'minecraft' namespace. " + + "Use a non-vanilla namespace, e.g. 'mymod:my_entity'."); + } + return GeyserApi.api().provider(CustomEntityDefinition.class, identifier); + } + + /** + * Creates or retrieves a {@link CustomEntityDefinition} by the Bedrock entity type identifier. + * The identifier must not use the {@code minecraft} namespace. + * + * @param identifier the Bedrock entity identifier, in {@code namespace:path} format + * @return the custom entity definition + * @since 2.11.0 + */ + @ApiStatus.Experimental + static CustomEntityDefinition of(String identifier) { + return of(Identifier.of(identifier)); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/custom/package-info.java b/api/src/main/java/org/geysermc/geyser/api/entity/custom/package-info.java new file mode 100644 index 00000000000..30ed743b1c6 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/custom/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +@NullMarked +package org.geysermc.geyser.api.entity.custom; + +import org.jspecify.annotations.NullMarked; diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataType.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataType.java new file mode 100644 index 00000000000..59308a05819 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataType.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.data; + +import org.geysermc.geyser.api.entity.type.GeyserEntity; +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Objects; + +/** + * Represents a type of entity data that can be sent for an entity. + *

+ * Entity data types define the values stored for a particular piece of metadata, + * such as a {@code Byte}, {@code Integer}, {@code Float}; and the identifier associated with the types. + *

+ * Unlike properties of custom items or blocks, it is possible to update entity metadata at runtime, + * which can be done using {@link GeyserEntity#override(GeyserEntityDataType, Object)}. + *

+ * Only the built-in types in {@link GeyserEntityDataTypes} are supported. Attempting to use a type + * not provided by Geyser will throw an {@link IllegalArgumentException} at runtime. + * + * @param the value type associated with this entity data type + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract sealed class GeyserEntityDataType permits GeyserEntityDataType.SimpleType, GeyserListEntityDataType { + + private final Identifier identifier; + private final Class typeClass; + + @ApiStatus.Internal + GeyserEntityDataType(Identifier identifier, Class typeClass) { + this.identifier = Objects.requireNonNull(identifier); + this.typeClass = Objects.requireNonNull(typeClass); + } + + /** + * Gets the identifier associated with this entity data type. + * + * @return the identifier for this type + * @since 2.11.0 + */ + @ApiStatus.Experimental + public final Identifier identifier() { + return identifier; + } + + /** + * Gets the Java class representing the value type associated with this data type. + * + * @return the class of the value used by this entity data type + * @since 2.11.0 + */ + @ApiStatus.Experimental + public final Class typeClass() { + return typeClass; + } + + @Override + @ApiStatus.Experimental + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof GeyserEntityDataType that)) return false; + return identifier.equals(that.identifier); + } + + @Override + @ApiStatus.Experimental + public final int hashCode() { + return identifier.hashCode(); + } + + @Override + @ApiStatus.Experimental + public String toString() { + return "GeyserEntityDataType{" + identifier + ", " + typeClass.getSimpleName() + "}"; + } + + @ApiStatus.Internal + static GeyserEntityDataType create(Identifier identifier, Class typeClass) { + return new SimpleType<>(identifier, typeClass); + } + + @ApiStatus.Internal + static final class SimpleType extends GeyserEntityDataType { + @ApiStatus.Internal + SimpleType(Identifier identifier, Class typeClass) { + super(identifier, typeClass); + } + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataTypes.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataTypes.java new file mode 100644 index 00000000000..4e57dcbeff4 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserEntityDataTypes.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.data; + +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.api.entity.data.types.Hitbox; +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +/** + * Contains {@link GeyserEntityDataType} types which can be used to change the + * current value stored for a specific entity data type. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public final class GeyserEntityDataTypes { + + /** + * Represents a single-byte value used for the main color, ranged 0 to 15. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType COLOR = + GeyserEntityDataType.create(Identifier.of("color"), Byte.class); + + /** + * Represents a numeric variant index that can be queried in resource packs. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType VARIANT = + GeyserEntityDataType.create(Identifier.of("variant"), Integer.class); + + /** + * Represents the entity's collision box width. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType WIDTH = + GeyserEntityDataType.create(Identifier.of("geysermc", "width"), Float.class); + + /** + * Represents the entity's collision box height. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType HEIGHT = + GeyserEntityDataType.create(Identifier.of("geysermc", "height"), Float.class); + + /** + * Represents the entity's vertical offset applied on top of the Java position sent by the server. + * Some entities, such as players, boats, and minecarts need such an offset to be displayed in the correct position. + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType VERTICAL_OFFSET = + GeyserEntityDataType.create(Identifier.of("geysermc", "vertical_offset"), Float.class); + + /** + * Represents the scale multiplier for visual size. + * + * @see Official documentation" + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType SCALE = + GeyserEntityDataType.create(Identifier.of("scale"), Float.class); + + /** + * Represents custom hitboxes for entities, or an empty list if none are set. + * To set no hitbox, update hitboxes to an empty list. To restore default behavior, update it to null. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserListEntityDataType HITBOXES = + GeyserListEntityDataType.createList(Identifier.of("custom_hit_test"), Hitbox.class); + + /** + * Represents the entity's seat offset, which is used when riding another entity. + * Equivalent to "seats" in the {@code minecraft:rideable} entity component, but set on the rider instead of the vehicle. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType SEAT_OFFSET = + GeyserEntityDataType.create(Identifier.of("geysermc", "seat_offset"), Vector3f.class); + + /** + * Whether the entity's rotation is locked to the vehicle it is riding. + * This is used for boats and happy ghasts in the vanilla game. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType ROTATION_LOCKED_TO_VEHICLE = + GeyserEntityDataType.create(Identifier.of("rotation_locked_to_vehicle"), Boolean.class); + + /** + * The degrees of rotation a rider may rotate within, set on the rider entity. + * This is used for boats and happy ghasts in the vanilla game to prevent "looking backwards" while riding it + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType SEAT_LOCK_RIDER_ROTATION_DEGREES = + GeyserEntityDataType.create(Identifier.of("seat_lock_rider_rotation_degrees"), Float.class); + + /** + * Whether an entity riding another vehicle entity is sitting on a seat which has a rotation. + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType SEAT_HAS_ROTATION = + GeyserEntityDataType.create(Identifier.of("geysermc", "seat_has_rotation"), Boolean.class); + + /** + * The degrees of rotation that this seat is offset by. Equivalent to "rotate_rider_by" in the {@code minecraft:rideable} entity component. + * This is used for boats to make the player face forward, and is equivalent to {@code rotate_rider_by} in the {@code minecraft:rideable} entity component. + * + * @see Official documentation + * @since 2.11.0 + */ + @ApiStatus.Experimental + public static final GeyserEntityDataType ROTATE_RIDER_DEGREES = + GeyserEntityDataType.create(Identifier.of("rotate_rider_by"), Float.class); + + @ApiStatus.Internal + private GeyserEntityDataTypes() { + // no-op + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserListEntityDataType.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserListEntityDataType.java new file mode 100644 index 00000000000..cca9b08cf28 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/GeyserListEntityDataType.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.data; + +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +/** + * Represents a list of objects for specific entity data types. + * For example, there can be multiple hitboxes on an entity. + * + * @param the object type in the list + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract sealed class GeyserListEntityDataType extends GeyserEntityDataType> + permits GeyserListEntityDataType.SimpleListType { + + @SuppressWarnings("unchecked") + @ApiStatus.Internal + GeyserListEntityDataType(Identifier identifier) { + super(identifier, (Class>) (Class) List.class); + } + + /** + * @return the class of the list entries + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract Class listEntryClass(); + + @ApiStatus.Internal + static GeyserListEntityDataType createList(Identifier identifier, Class listEntryClass) { + return new SimpleListType<>(identifier, listEntryClass); + } + + @ApiStatus.Internal + static final class SimpleListType extends GeyserListEntityDataType { + private final Class listEntryClass; + + @ApiStatus.Internal + SimpleListType(Identifier identifier, Class listEntryClass) { + super(identifier); + this.listEntryClass = listEntryClass; + } + + /** + * {@inheritDoc} + */ + @Override + public Class listEntryClass() { + return listEntryClass; + } + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/package-info.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/package-info.java new file mode 100644 index 00000000000..4111ccac8d6 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +@NullMarked +package org.geysermc.geyser.api.entity.data; + +import org.jspecify.annotations.NullMarked; diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/types/Hitbox.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/types/Hitbox.java new file mode 100644 index 00000000000..2e8ed790806 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/types/Hitbox.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.data.types; + +import org.checkerframework.common.returnsreceiver.qual.This; +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.api.GeyserApi; +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents an entity hitbox, with min/max representing absolute coordinates. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public interface Hitbox { + + /** + * The min "corner" of the hitbox as a position in the world. + * + * @return the vector of the corner + * @since 2.11.0 + */ + @ApiStatus.Experimental + Vector3f min(); + + /** + * The max "corner" of the hitbox as a position in the world. + * + * @return the vector of the corner + * @since 2.11.0 + */ + @ApiStatus.Experimental + Vector3f max(); + + /** + * The pivot of the hitbox + * + * @return the pivot + * @since 2.11.0 + */ + @ApiStatus.Experimental + Vector3f pivot(); + + /** + * Creates a new builder for a hitbox. + * + * @return a new builder + * @since 2.11.0 + */ + @ApiStatus.Experimental + static Builder builder() { + return GeyserApi.api().provider(Builder.class); + } + + /** + * The builder for an entity hitbox. + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + interface Builder { + + /** + * Sets the min corner of the hitbox + * + * @param min the vector of the corner + * @return this builder + * @since 2.11.0 + */ + @ApiStatus.Experimental + @This Builder min(Vector3f min); + + /** + * Sets the max corner of the hitbox. + * + * @param max the vector of the corner + * @return this builder + * @since 2.11.0 + */ + @ApiStatus.Experimental + @This Builder max(Vector3f max); + + /** + * Sets the pivot of the hitbox. + * + * @param pivot the pivot vector + * @return this builder + * @since 2.11.0 + */ + @ApiStatus.Experimental + @This Builder pivot(Vector3f pivot); + + /** + * Builds this hitbox, defaulting to {@code Vector3f.ZERO} if + * any one vector was not provided. + * + * @return a new hitbox + * @since 2.11.0 + */ + @ApiStatus.Experimental + Hitbox build(); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/data/types/package-info.java b/api/src/main/java/org/geysermc/geyser/api/entity/data/types/package-info.java new file mode 100644 index 00000000000..13e48938f5f --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/data/types/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +@NullMarked +package org.geysermc.geyser.api.entity.data.types; + +import org.jspecify.annotations.NullMarked; diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/definition/GeyserEntityDefinition.java b/api/src/main/java/org/geysermc/geyser/api/entity/definition/GeyserEntityDefinition.java new file mode 100644 index 00000000000..3aa59e805f2 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/definition/GeyserEntityDefinition.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.definition; + +import org.geysermc.geyser.api.GeyserApi; +import org.geysermc.geyser.api.entity.property.GeyserEntityProperty; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntitiesEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntityPropertiesEvent; +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +/** + * Represents a Bedrock entity definition registered in the {@link GeyserDefineEntitiesEvent}. + * @since 2.11.0 + */ +@ApiStatus.Experimental +public interface GeyserEntityDefinition { + + /** + * This entity's identifier as it's known to Bedrock clients and used in resource packs. + * See the official docs for further information + * + * @return the Bedrock entity identifier + * @since 2.11.0 + */ + @ApiStatus.Experimental + Identifier identifier(); + + /** + * Returns the entity properties registered in the {@link GeyserDefineEntityPropertiesEvent} for this entity type. + * + * @see GeyserEntityProperty + * @return an unmodifiable list containing entity properties registered for this entity type + * @since 2.11.0 + */ + @ApiStatus.Experimental + List> properties(); + + /** + * Indicates whether this entity exists in Minecraft: Bedrock Edition, or whether it is a custom entity. + * + * @return whether this entity exists in the vanilla base game + * @since 2.11.0 + */ + @ApiStatus.Experimental + boolean vanilla(); + + /** + * Returns whether this definition is currently registered via {@link GeyserDefineEntitiesEvent}. + * Unregistered definitions cannot be sent to Bedrock clients! + * + * @return whether this definition is registered + * @since 2.11.0 + */ + @ApiStatus.Experimental + boolean registered(); + + /** + * Retrieves a registered {@link GeyserEntityDefinition} by its Bedrock entity type identifier, + * or returns a new unregistered definition if none is found. + * + * @param identifier the Bedrock entity identifier + * @return the GeyserEntityDefinition for the given identifier + * @since 2.11.0 + */ + @ApiStatus.Experimental + static GeyserEntityDefinition of(Identifier identifier) { + return GeyserApi.api().provider(GeyserEntityDefinition.class, identifier); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/definition/JavaEntityType.java b/api/src/main/java/org/geysermc/geyser/api/entity/definition/JavaEntityType.java new file mode 100644 index 00000000000..8dffc557718 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/definition/JavaEntityType.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.entity.definition; + +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.Nullable; + +/** + * Represents a Java edition entity type. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public interface JavaEntityType { + + /** + * Each entity type on Java edition has an identifier, such as {@code "minecraft:pig"} that uniquely identifies it. + * Modded entities cannot be in the minecraft namespace! + * + * @return the Java identifier of the entity type + * @since 2.11.0 + */ + @ApiStatus.Experimental + Identifier identifier(); + + /** + * Indicates whether this entity type exists in the Minecraft: Java Edition base game, or whether it is a custom entity. + * Note: As of API 2.11.0, this would always be true! + * + * @return whether this entity exists in the vanilla base game + * @since 2.11.0 + */ + @ApiStatus.Experimental + boolean vanilla(); + + /** + * This entity type's default width, not respective of pose-adjusted width. + * + * @return the default width of the Java entity type + * @since 2.11.0 + */ + @ApiStatus.Experimental + float width(); + + /** + * This entity type's default height, not respective of pose-adjusted height. + * + * @return the default height of the Java entity type + * @since 2.11.0 + */ + @ApiStatus.Experimental + float height(); + + /** + * Compares two entity identifiers. + * + * @param javaIdentifier the other entity identifier + * @return true if the entity identifier is the same + * @since 2.11.0 + */ + @ApiStatus.Experimental + default boolean is(Identifier javaIdentifier) { + return identifier().equals(javaIdentifier); + } + + /** + * Gets the default Bedrock entity definition which is associated with this Minecraft: Java Edition entity type. + * + * @return the default Bedrock entity definition + * @since 2.11.0 + */ + @ApiStatus.Experimental + @Nullable GeyserEntityDefinition defaultBedrockDefinition(); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/definition/package-info.java b/api/src/main/java/org/geysermc/geyser/api/entity/definition/package-info.java new file mode 100644 index 00000000000..3ccab92d450 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/entity/definition/package-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +@NullMarked +package org.geysermc.geyser.api.entity.definition; + +import org.jspecify.annotations.NullMarked; diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/type/GeyserEntity.java b/api/src/main/java/org/geysermc/geyser/api/entity/type/GeyserEntity.java index 922c87491a8..9d48289997d 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/type/GeyserEntity.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/type/GeyserEntity.java @@ -26,31 +26,142 @@ package org.geysermc.geyser.api.entity.type; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.Positive; +import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.custom.CustomEntityDefinition; +import org.geysermc.geyser.api.entity.data.GeyserEntityDataType; +import org.geysermc.geyser.api.entity.data.GeyserEntityDataTypes; +import org.geysermc.geyser.api.entity.definition.GeyserEntityDefinition; import org.geysermc.geyser.api.entity.property.BatchPropertyUpdater; import org.geysermc.geyser.api.entity.property.GeyserEntityProperty; import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntityPropertiesEvent; +import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.Nullable; +import java.util.List; +import java.util.UUID; import java.util.function.Consumer; /** - * Represents a unique instance of an entity. Each {@link GeyserConnection} - * have their own sets of entities - no two instances will share the same GeyserEntity instance. + * Represents a unique entity instance as seen by a specific {@link GeyserConnection}. + * Each connection maintains its own set of entity objects; no two connections share the same + * {@code GeyserEntity} instance. */ public interface GeyserEntity { + /** - * @return the entity ID that the server has assigned to this entity. + * @return the entity ID that the server has assigned to this entity, or -1 if none is present */ @NonNegative int javaId(); /** - * Updates an entity property with a new value. - * If the new value is null, the property is reset to the default value. + * The entity id used by Geyser to identify this entity with the Bedrock client. + * + * @return the Geyser entity id that the Bedrock client sees + * @since 2.11.0 + */ + @Positive + @ApiStatus.Experimental + long geyserId(); + + /** + * The entity's UUID, only null if the server has not spawned this entity. + * + * @return the entity UUID that the server has assigned to this entity, + * or null if this entity isn't known to the Java server + * @since 2.11.0 + */ + @Nullable + @ApiStatus.Experimental + UUID uuid(); + + /** + * The Bedrock entity definition for this entity, which can also be a {@link CustomEntityDefinition}. + * + * @return the Bedrock entity definition + * @since 2.11.0 + */ + @ApiStatus.Experimental + GeyserEntityDefinition definition(); + + /** + * The position of this entity as reported by the Java server, without any Bedrock vertical + * offset applied. + * + * @return the position of the entity as known to the Java server + * @since 2.11.0 + */ + @ApiStatus.Experimental + Vector3f position(); + + /** + * The vehicle this entity is currently mounted on. + * + * @return the vehicle of this entity, or {@code null} if this entity is not a passenger + * @since 2.11.0 + */ + @Nullable + @ApiStatus.Experimental + GeyserEntity vehicle(); + + /** + * The passengers currently riding this entity. + * + * @return an immutable snapshot of this entity's passengers, or an empty list if none + * @since 2.11.0 + */ + @ApiStatus.Experimental + List passengers(); + + /** + * Reads the current value of a given {@link GeyserEntityDataType} which + * would currently be sent to players - either the {@link #override(GeyserEntityDataType)}, or the + * base value, if one is sent by default. + * + * @see GeyserEntityDataTypes + * @param dataType the entity data type to query + * @param the type of the value + * @return the current value, or {@code null} if none is known + * @since 2.11.0 + */ + @ApiStatus.Experimental + @Nullable T value(GeyserEntityDataType dataType); + + /** + * Reads the current override of a given {@link GeyserEntityDataType}, or + * null if no override was defined. + * + * @see GeyserEntityDataTypes + * @param dataType the entity data type override to query + * @param the type of the value + * @return the current override value, or {@code null} if no override has been set + * @since 2.11.0 + */ + @ApiStatus.Experimental + @Nullable T override(GeyserEntityDataType dataType); + + /** + * Overrides an entity data value for this entity. + * If {@code value} is {@code null}, the override is cleared and the default value + * (from the Java server or entity type definition) is restored. + * + * @param dataType an entity data type, such as a constant from {@link GeyserEntityDataTypes} + * @param value the new value, or {@code null} to reset the override + * @param the type of the value + * @since 2.11.0 + */ + @ApiStatus.Experimental + void override(GeyserEntityDataType dataType, @Nullable T value); + + /** + * Convenience method to update a single entity property. + * Equivalent to {@link #updatePropertiesBatched(Consumer, boolean) updatePropertiesBatched} + * with a single-property consumer and {@code immediate = false}. * * @param property a {@link GeyserEntityProperty} registered for this type in the {@link GeyserDefineEntityPropertiesEvent} - * @param value the new property value + * @param value the new property value, or {@code null} to reset * @param the type of the value * @since 2.9.0 */ @@ -59,24 +170,24 @@ default void updateProperty(GeyserEntityProperty property, @Nullable T va } /** - * Updates multiple properties with just one update packet. - * @see BatchPropertyUpdater - * - * @param consumer a batch updater + * @deprecated use {@link #updateProperty(GeyserEntityProperty, Object)} instead * @since 2.9.0 */ + @Deprecated(since = "2.11.0") default void updatePropertiesBatched(Consumer consumer) { this.updatePropertiesBatched(consumer, false); } /** - * Updates multiple properties with just one update packet, which can be sent immediately to the client. - * Usually, sending updates immediately is not required except for specific situations where packet batching - * would result in update order issues. - * @see BatchPropertyUpdater + * Updates multiple entity properties with a single update, optionally sending it immediately. + *

+ * Usually, sending immediately is unnecessary; batched updates are flushed once per tick. + * Pass {@code immediate = true} only when packet ordering requires the properties to be + * applied before the next tick (e.g., to avoid a visual flicker on the client). * - * @param consumer a batch updater - * @param immediate whether this update should be sent immediately + * @param consumer a {@link BatchPropertyUpdater} callback that applies one or more property changes + * @param immediate {@code true} to send the packet immediately rather than at the next tick + * @see BatchPropertyUpdater * @since 2.9.1 */ void updatePropertiesBatched(Consumer consumer, boolean immediate); diff --git a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java index d31def99670..da2e286090b 100644 --- a/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java +++ b/api/src/main/java/org/geysermc/geyser/api/entity/type/player/GeyserPlayerEntity.java @@ -25,15 +25,7 @@ package org.geysermc.geyser.api.entity.type.player; -import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.api.entity.type.GeyserEntity; public interface GeyserPlayerEntity extends GeyserEntity { - - /** - * Gets the position of the player, as it is known to the Java server. - * - * @return the player's position - */ - Vector3f position(); } diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSpawnEntityEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSpawnEntityEvent.java new file mode 100644 index 00000000000..cfa3dcaa414 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSpawnEntityEvent.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.bedrock; + +import org.geysermc.event.Cancellable; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.EntityData; +import org.geysermc.geyser.api.entity.definition.GeyserEntityDefinition; +import org.geysermc.geyser.api.entity.type.GeyserEntity; +import org.geysermc.geyser.api.event.connection.ConnectionEvent; +import org.geysermc.geyser.api.event.java.ServerAttachParrotsEvent; +import org.geysermc.geyser.api.event.java.ServerSpawnEntityEvent; +import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntitiesEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * Base event for entity spawning visible to a specific Bedrock connection. + * Specific subtypes are {@link ServerSpawnEntityEvent} (non-player entities) and + * {@link ServerAttachParrotsEvent} (shoulder parrots). + *

+ * The event is cancellable; cancelling it suppresses spawning the entity on the Bedrock client. + * Setting the {@link #definition(GeyserEntityDefinition) definition} to + * {@code null} has the same effect. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract class SessionSpawnEntityEvent extends ConnectionEvent implements Cancellable { + + @ApiStatus.Internal + public SessionSpawnEntityEvent(GeyserConnection connection) { + super(connection); + } + + /** + * Returns the Bedrock entity definition that will be sent to the Bedrock client. + * Setting a definition to null will cancel this entity spawn! + * + * @return the entity definition, or {@code null} if none is currently set + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract @Nullable GeyserEntityDefinition definition(); + + /** + * Overrides the Bedrock entity definition when spawning this entity on the Bedrock client. + *

+ * The supplied definition must have been previously registered in the + * {@link GeyserDefineEntitiesEvent}; passing an unregistered definition will throw + * {@link IllegalStateException}. Passing {@code null} cancels the spawn for this connection. + * + * @param definition the replacement entity definition, or {@code null} to suppress the spawn + * @throws IllegalStateException if the provided definition has not been registered + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract void definition(@Nullable GeyserEntityDefinition definition); + + /** + * Registers a callback that is invoked with the {@link GeyserEntity} instance just before the entity is spawned. + * This means that {@link EntityData#byJavaId}, {@link EntityData#byUuid}, and related lookups + * will not find the entity from within the consumer. + *

+ * Use this callback to apply initial overrides such as entity data values (scale, width, + * height, hitboxes) or entity properties before the spawn packet is sent to the client. + * If multiple consumers are registered, they run in the order they were added. + *

+ * The consumer is not called if the event is cancelled. + * + * @param consumer the callback receiving the freshly created entity + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract void preSpawnConsumer(Consumer consumer); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/connection/SessionDefineCustomWaypointsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/connection/SessionDefineCustomWaypointsEvent.java new file mode 100644 index 00000000000..d286c066fb4 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/connection/SessionDefineCustomWaypointsEvent.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.connection; + +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.util.Identifier; +import org.geysermc.geyser.api.waypoint.CustomWaypointStyle; +import org.geysermc.geyser.api.waypoint.CustomWaypointStyleRegisterException; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +/** + * Called once for every {@link GeyserConnection} to register custom waypoint styles. Custom waypoint styles must be registered through this event. + * + *

{@link CustomWaypointStyle}s may be registered multiple times for different Java Edition waypoint style {@link Identifier}s, however, each Java Edition waypoint style + * may only have one {@link CustomWaypointStyle}.

+ * + * @see CustomWaypointStyle + * @since 2.11.0 + */ +@ApiStatus.NonExtendable +public abstract class SessionDefineCustomWaypointsEvent extends ConnectionEvent { + + @ApiStatus.Internal + public SessionDefineCustomWaypointsEvent(GeyserConnection connection) { + super(connection); + } + + /** + * Returns a map of all the currently registered custom waypoint styles for this {@link GeyserConnection}. + * + * @return an unmodifiable map of all currently registered custom waypoint styles + * @since 2.11.0 + */ + public abstract Map customWaypointStyles(); + + /** + * Registers a {@link CustomWaypointStyle} for this {@link GeyserConnection}, for the given Java Edition waypoint style {@code identifier}. + * + *

The given {@link CustomWaypointStyle} will be used for every waypoint that uses the given {@code identifier} as waypoint style. Vanilla + * waypoint styles, like {@code minecraft:default}, may be overridden.

+ * + *

When a waypoint style is already registered for the given {@code identifier}, this method will fail without throwing an exception, but an error will be logged.

+ * + * @param identifier the identifier of the waypoint style on Java Edition + * @param style the {@link CustomWaypointStyle} + * @throws CustomWaypointStyleRegisterException when an error occurred while registering the custom waypoint style + * @since 2.11.0 + */ + public abstract void register(Identifier identifier, CustomWaypointStyle style); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerAttachParrotsEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerAttachParrotsEvent.java new file mode 100644 index 00000000000..22ff1ff1b28 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerAttachParrotsEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.java; + +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity; +import org.geysermc.geyser.api.event.bedrock.SessionSpawnEntityEvent; +import org.jetbrains.annotations.ApiStatus; + +/** + * Called when the Java server attaches parrots to a player. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract class ServerAttachParrotsEvent extends SessionSpawnEntityEvent { + + @ApiStatus.Internal + public ServerAttachParrotsEvent(GeyserConnection connection) { + super(connection); + } + + /** + * The player for which the Java server attached parrots. + * + * @return the player with bird friends + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract GeyserPlayerEntity player(); + + /** + * The variant of the parrot. + * + * @return the parrot variant + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract int variant(); + + /** + * Whether this parrot is on the right shoulder of the player. + * + * @return true if parrot is on the right shoulder, left otherwise + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract boolean right(); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerSpawnEntityEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerSpawnEntityEvent.java new file mode 100644 index 00000000000..0766fe39872 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerSpawnEntityEvent.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.java; + +import org.geysermc.event.Cancellable; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.definition.JavaEntityType; +import org.geysermc.geyser.api.event.bedrock.SessionSpawnEntityEvent; +import org.jetbrains.annotations.ApiStatus; + +import java.util.UUID; + +/** + * Called when the downstream server spawns a non-player entity. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract class ServerSpawnEntityEvent extends SessionSpawnEntityEvent implements Cancellable { + + @ApiStatus.Internal + public ServerSpawnEntityEvent(GeyserConnection connection) { + super(connection); + } + + /** + * Gets the entity id of the entity being spawned, which is unique per session. + * + * @return the entity id of the entity being spawned + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract int entityId(); + + /** + * Gets the uuid of the entity being spawned. + * + * @return the uuid of the entity being spawned + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract UUID uuid(); + + /** + * Gets the Java entity type sent by the server. + * + * @return the Java edition entity type of the entity being spawned + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract JavaEntityType entityType(); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerUpdateEntityPassengersEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerUpdateEntityPassengersEvent.java new file mode 100644 index 00000000000..9bd7fa54281 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerUpdateEntityPassengersEvent.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2026 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.java; + +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.type.GeyserEntity; +import org.geysermc.geyser.api.event.connection.ConnectionEvent; +import org.jetbrains.annotations.ApiStatus; + +/** + * This event is called when an entity's passengers are updated. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +public abstract class ServerUpdateEntityPassengersEvent extends ConnectionEvent { + + /** + * The vehicle entity that gets a passenger update. + * + * @return the vehicle entity + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract GeyserEntity vehicle(); + + @ApiStatus.Internal + public ServerUpdateEntityPassengersEvent(GeyserConnection connection) { + super(connection); + } + + /** + * This event is called when entities are mounted to a vehicle. + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract static class Mount extends ServerUpdateEntityPassengersEvent { + @ApiStatus.Internal + public Mount(GeyserConnection connection) { + super(connection); + } + + /** + * @return the passenger that was added to the vehicle + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract GeyserEntity addedPassenger(); + } + + /** + * This event is called when entities are dismounted from a vehicle. + * + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract static class Dismount extends ServerUpdateEntityPassengersEvent { + @ApiStatus.Internal + public Dismount(GeyserConnection connection) { + super(connection); + } + + /** + * @return the passenger that was removed from the vehicle + * @since 2.11.0 + */ + @ApiStatus.Experimental + public abstract GeyserEntity removedPassenger(); + } +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntitiesEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntitiesEvent.java new file mode 100644 index 00000000000..a4e096b82d1 --- /dev/null +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntitiesEvent.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.api.event.lifecycle; + +import org.geysermc.event.Event; +import org.geysermc.geyser.api.entity.custom.CustomEntityDefinition; +import org.geysermc.geyser.api.entity.definition.GeyserEntityDefinition; +import org.geysermc.geyser.api.util.Identifier; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Collection; + +/** + * Called once during Geyser startup to allow users to register custom Bedrock entity types. + *

+ * All {@link CustomEntityDefinition}'s must be registered in this event before being used! + *

+ * To register a custom entity, create a definition with {@link CustomEntityDefinition#of(Identifier)} + * and pass it to {@link #register(CustomEntityDefinition)}. Additional Bedrock entity properties + * can be registered in the subsequent {@link GeyserDefineEntityPropertiesEvent}. + * + * @since 2.11.0 + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface GeyserDefineEntitiesEvent extends Event { + + /** + * Returns an immutable view of all currently registered Bedrock entity definitions, + * including both vanilla and any custom definitions registered so far in this event. + * + * @return an immutable collection of all registered entity definitions + * @since 2.11.0 + */ + @ApiStatus.Experimental + Collection entities(); + + /** + * Returns an immutable view of all custom entity definitions registered so far. + * + * @return an immutable collection of registered custom entity definitions + * @since 2.11.0 + */ + @ApiStatus.Experimental + Collection customEntities(); + + /** + * Registers a custom entity definition. Using the same identifier twice in different definitions + * or providing a definition in the vanilla namespace will throw an exception. + * + * @param definition the custom entity definition to register; must not be null + * @throws IllegalArgumentException if {@code definition} was not created via {@link CustomEntityDefinition#of} + * @throws IllegalStateException if a custom entity definition with this identifier has already been registered + * @since 2.11.0 + */ + @ApiStatus.Experimental + void register(CustomEntityDefinition definition); +} diff --git a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntityPropertiesEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntityPropertiesEvent.java index 1230e3551fe..d50054d2741 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntityPropertiesEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/lifecycle/GeyserDefineEntityPropertiesEvent.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.api.event.lifecycle; import org.geysermc.event.Event; +import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.api.entity.EntityData; import org.geysermc.geyser.api.entity.property.GeyserEntityProperty; import org.geysermc.geyser.api.entity.property.type.GeyserBooleanEntityProperty; @@ -39,7 +40,6 @@ import java.util.Collection; import java.util.List; -import java.util.function.Consumer; /** * Lifecycle event fired during Geyser's startup to allow custom entity properties @@ -61,10 +61,9 @@ * } * } * - * Retrieving entity instances is possible with the {@link EntityData#entityByJavaId(int)} method, or - * {@link EntityData#playerEntity()} for the connection player entity. - * To update the value of a property on a specific entity, use {@link GeyserEntity#updateProperty(GeyserEntityProperty, Object)}, - * or {@link GeyserEntity#updatePropertiesBatched(Consumer)} to update multiple properties efficiently at once. + * Retrieving entity instances is possible with, for example, the {@link EntityData#byJavaId(int)} method, or + * {@link GeyserConnection#playerEntity()} for the connection player entity. + * To update the value of a property on a specific entity, use {@link GeyserEntity#updateProperty(GeyserEntityProperty, Object)}. * *

Notes: *