mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-04 15:31:36 +00:00
Custom entity properties API (#5788)
* Custom entity properties API * Fix build fail * Resolve comments * Entity property registration improvements * oops * Add boolean and enum property sync API * default value + no packet if value unchanged * Don't send packet if no properties were updated * small refactor * the refactor, part two * Move updateProperties to GeyserEntity * Don't inherit properties from parent * temp * type-safe property updating * Address review * call the GeyserDefineEntityPropertiesEvent once, require specifying entity identifier instead of calling the event once for every entity type * Migrate to identifiers (from custom items v2, thanks eclipse), remove duplicate logic * fix test * Merge 1.21.9, update copper golem entity property usage * fixup javadocs --------- Co-authored-by: onebeastchris <github@onechris.mozmail.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.property;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntityPropertiesEvent;
|
||||
|
||||
/**
|
||||
* Collects property changes to be applied as a single, batched update to an entity.
|
||||
* <p>
|
||||
* Notes:
|
||||
* <ul>
|
||||
* <li>Passing {@code null} as a value resets the property to its default.</li>
|
||||
* <li>Numeric properties must be within declared ranges; enum properties must use an allowed value.</li>
|
||||
* <li>Multiple updates to the same property within a single batch will result in the last value being applied.</li>
|
||||
* <li>The updater is short-lived and should not be retained outside the batching callback.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <pre>{@code
|
||||
* entity.updatePropertiesBatched(updater -> {
|
||||
* updater.update(SOME_FLOAT_PROPERTY, 0.15f);
|
||||
* updater.update(SOME_BOOLEAN_PROPERTY, true);
|
||||
* updater.update(SOME_INT_PROPERTY, null); // reset to default
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BatchPropertyUpdater {
|
||||
|
||||
/**
|
||||
* Queues an update for the given property within the current batch.
|
||||
* <p>
|
||||
* If {@code value} is {@code null}, the property will be reset to its default value
|
||||
* as declared when the property was registered during the {@link GeyserDefineEntityPropertiesEvent}.
|
||||
*
|
||||
* @param property a {@link GeyserEntityProperty} registered for the target entity type
|
||||
* @param value the new value, or {@code null} to reset to the default
|
||||
* @param <T> the property's value type
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
<T> void update(@NonNull GeyserEntityProperty<T> property, @Nullable T value);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.property;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.util.Identifier;
|
||||
|
||||
/**
|
||||
* Represents a property that can be attached to an entity.
|
||||
* <p>
|
||||
* Entity properties are used to describe metadata about an entity, such as
|
||||
* integers, floats, booleans, or enums.
|
||||
* @see <a href="https://learn.microsoft.com/en-us/minecraft/creator/documents/introductiontoentityproperties?view=minecraft-bedrock-stable#number-of-entity-properties-per-entity-type">
|
||||
* Official documentation for info</a>
|
||||
*
|
||||
* @param <T> the type of value stored by this property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserEntityProperty<T> {
|
||||
|
||||
/**
|
||||
* Gets the unique name of this property.
|
||||
* Custom properties cannot use the vanilla namespace
|
||||
* to avoid collisions with vanilla entity properties.
|
||||
*
|
||||
* @return the property identifier
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@NonNull
|
||||
Identifier identifier();
|
||||
|
||||
/**
|
||||
* Gets the default value of this property which
|
||||
* is set upon spawning entities.
|
||||
*
|
||||
* @return the default value of this property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
@NonNull
|
||||
T defaultValue();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.property.type;
|
||||
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
|
||||
/**
|
||||
* Represents a boolean entity property.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserBooleanEntityProperty extends GeyserEntityProperty<Boolean> {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.property.type;
|
||||
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
|
||||
/**
|
||||
* Represents a Java enum-backed enum property.
|
||||
* There are a few key limitations:
|
||||
* <ul>
|
||||
* <li>There cannot be more than 16 values</li>
|
||||
* <li>Enum names cannot be longer than 32 chars, must start with a letter, and may contain numbers and underscores</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <E> the enum type
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserEnumEntityProperty<E extends Enum<E>> extends GeyserEntityProperty<E> {
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.property.type;
|
||||
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntityPropertiesEvent;
|
||||
import org.geysermc.geyser.api.util.Identifier;
|
||||
|
||||
/**
|
||||
* Represents a float-backed entity property with inclusive bounds.
|
||||
* Values associated with this property must be always within the {@code [min(), max()]} bounds.
|
||||
*
|
||||
* @see GeyserDefineEntityPropertiesEvent#registerFloatProperty(Identifier, Identifier, float, float, Float)
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserFloatEntityProperty extends GeyserEntityProperty<Float> {
|
||||
|
||||
/**
|
||||
* @return the inclusive lower bound for this property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
float min();
|
||||
|
||||
/**
|
||||
* @return the inclusive upper bound for this property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
float max();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.property.type;
|
||||
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineEntityPropertiesEvent;
|
||||
import org.geysermc.geyser.api.util.Identifier;
|
||||
|
||||
/**
|
||||
* Represents an int-backed entity property with inclusive bounds.
|
||||
* There are a few key limitations:
|
||||
* <ul>
|
||||
* <li>Values must be always within the {@code [min(), max()]} bounds</li>
|
||||
* <li>Molang evaluation uses floats under the hood; very large integers can lose precision.
|
||||
* Prefer keeping values in a practical range to avoid rounding issues.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see GeyserDefineEntityPropertiesEvent#registerIntegerProperty(Identifier, Identifier, int, int, Integer)
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserIntEntityProperty extends GeyserEntityProperty<Integer> {
|
||||
|
||||
/**
|
||||
* @return the inclusive lower bound for this property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
int min();
|
||||
|
||||
/**
|
||||
* @return the inclusive upper bound for this property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
int max();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.property.type;
|
||||
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a string-backed enum property.
|
||||
* There are a few key limitations:
|
||||
* <ul>
|
||||
* <li>There cannot be more than 16 values</li>
|
||||
* <li>The values' names cannot be longer than 32 chars, must start with a letter, and may contain numbers and underscores</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserStringEnumProperty extends GeyserEntityProperty<String> {
|
||||
|
||||
/**
|
||||
* @return an unmodifiable list of all registered values
|
||||
* @since 2.9.0
|
||||
*/
|
||||
List<String> values();
|
||||
}
|
||||
@@ -26,9 +26,17 @@
|
||||
package org.geysermc.geyser.api.entity.type;
|
||||
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
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 java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Represents a unique instance of an entity. Each {@link org.geysermc.geyser.api.connection.GeyserConnection}
|
||||
* 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.
|
||||
*/
|
||||
public interface GeyserEntity {
|
||||
@@ -37,4 +45,24 @@ public interface GeyserEntity {
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
* @param property a {@link GeyserEntityProperty} registered for this type in the {@link GeyserDefineEntityPropertiesEvent}
|
||||
* @param value the new property value
|
||||
* @param <T> the type of the value
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default <T> void updateProperty(@NonNull GeyserEntityProperty<T> property, @Nullable T value) {
|
||||
this.updatePropertiesBatched(consumer -> consumer.update(property, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates multiple properties with just one update packet.
|
||||
* @see BatchPropertyUpdater
|
||||
* @since 2.9.0
|
||||
*/
|
||||
void updatePropertiesBatched(Consumer<BatchPropertyUpdater> consumer);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.event.Event;
|
||||
import org.geysermc.geyser.api.entity.EntityData;
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
import org.geysermc.geyser.api.entity.property.type.GeyserBooleanEntityProperty;
|
||||
import org.geysermc.geyser.api.entity.property.type.GeyserEnumEntityProperty;
|
||||
import org.geysermc.geyser.api.entity.property.type.GeyserFloatEntityProperty;
|
||||
import org.geysermc.geyser.api.entity.property.type.GeyserIntEntityProperty;
|
||||
import org.geysermc.geyser.api.entity.property.type.GeyserStringEnumProperty;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
import org.geysermc.geyser.api.util.Identifier;
|
||||
|
||||
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
|
||||
* to be registered for a specific entity type.
|
||||
* <p>
|
||||
* Listeners can add new properties for any entity by passing the target entity's
|
||||
* identifier (e.g., {@code Identifier.of("player")}) to the registration methods.
|
||||
* The returned {@link GeyserEntityProperty} is used to identify the properties and to
|
||||
* update the value of a specific entity instance.
|
||||
*
|
||||
* <h2>Example usage</h2>
|
||||
* <pre>{@code
|
||||
* public void onDefine(GeyserDefineEntityPropertiesEvent event) {
|
||||
* Identifier player = Identifier.of("player");
|
||||
* GeyserFloatEntityProperty ANIMATION_SPEED =
|
||||
* event.registerFloatProperty(player, Identifier.of("my_group:animation_speed"), 0.0f, 1.0f, 0.1f);
|
||||
* GeyserBooleanEntityProperty SHOW_SHORTS =
|
||||
* event.registerBooleanProperty(player, Identifier.of("my_group:show_shorts"), false);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* <p><b>Notes:</b>
|
||||
* <ul>
|
||||
* <li>Default values must fall within the provided bounds.</li>
|
||||
* <li>There cannot be more than 32 properties registered per entity type in total</li>
|
||||
* <li>{@link #properties(Identifier)} returns properties registered for the given entity
|
||||
* (including those added earlier in the same callback), including vanilla properties.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface GeyserDefineEntityPropertiesEvent extends Event {
|
||||
|
||||
/**
|
||||
* Returns an <em>unmodifiable</em> view of all properties that have been registered
|
||||
* so far for the given entity type. This includes entity properties used for vanilla gameplay,
|
||||
* such as those used for creaking animations.
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @return an unmodifiable collection of registered properties
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
Collection<GeyserEntityProperty<?>> properties(@NonNull Identifier entityType);
|
||||
|
||||
/**
|
||||
* Registers a {@code float}-backed entity property.
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param min the minimum allowed value (inclusive)
|
||||
* @param max the maximum allowed value (inclusive)
|
||||
* @param defaultValue the default value assigned initially on entity spawn - if null, it will be the minimum value
|
||||
* @return the created float property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
GeyserFloatEntityProperty registerFloatProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, float min, float max, @Nullable Float defaultValue);
|
||||
|
||||
/**
|
||||
* Registers a {@code float}-backed entity property with a default value set to the minimum value.
|
||||
* @see #registerFloatProperty(Identifier, Identifier, float, float, Float)
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param min the minimum allowed value (inclusive)
|
||||
* @param max the maximum allowed value (inclusive)
|
||||
* @return the created float property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default GeyserFloatEntityProperty registerFloatProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, float min, float max) {
|
||||
return registerFloatProperty(entityType, propertyIdentifier, min, max, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an {@code int}-backed entity property.
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param min the minimum allowed value (inclusive)
|
||||
* @param max the maximum allowed value (inclusive)
|
||||
* @param defaultValue the default value assigned initially on entity spawn - if null, it will be the minimum value
|
||||
* @return the created int property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
GeyserIntEntityProperty registerIntegerProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, int min, int max, @Nullable Integer defaultValue);
|
||||
|
||||
/**
|
||||
* Registers an {@code int}-backed entity property with a default value set to the minimum value.
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param min the minimum allowed value (inclusive)
|
||||
* @param max the maximum allowed value (inclusive)
|
||||
* @return the created int property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default GeyserIntEntityProperty registerIntegerProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, int min, int max) {
|
||||
return registerIntegerProperty(entityType, propertyIdentifier, min, max, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@code boolean}-backed entity property.
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param defaultValue the default boolean value
|
||||
* @return the created boolean property handle
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
GeyserBooleanEntityProperty registerBooleanProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, boolean defaultValue);
|
||||
|
||||
/**
|
||||
* Registers a {@code boolean}-backed entity property with a default of {@code false}.
|
||||
* @see #registerBooleanProperty(Identifier, Identifier, boolean)
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @return the created boolean property
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default GeyserBooleanEntityProperty registerBooleanProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier) {
|
||||
return registerBooleanProperty(entityType, propertyIdentifier, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a typed {@linkplain Enum enum}-backed entity property.
|
||||
* <p>
|
||||
* The enum constants define the allowed values. If {@code defaultValue} is {@code null},
|
||||
* the first enum value is set as the default.
|
||||
* @see GeyserEnumEntityProperty for further limitations
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param enumClass the enum class that defines allowed values
|
||||
* @param defaultValue the default enum value, or {@code null} for the first enum value to be the default
|
||||
* @param <E> the enum type
|
||||
* @return the created enum property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
<E extends Enum<E>> GeyserEnumEntityProperty<E> registerEnumProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, @NonNull Class<E> enumClass, @Nullable E defaultValue);
|
||||
|
||||
/**
|
||||
* Registers a typed {@linkplain Enum enum}-backed entity property with the first value set as the default.
|
||||
* @see #registerEnumProperty(Identifier, Identifier, Class, Enum)
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param enumClass the enum class that defines allowed values
|
||||
* @param <E> the enum type
|
||||
* @return the created enum property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default <E extends Enum<E>> GeyserEnumEntityProperty<E> registerEnumProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, @NonNull Class<E> enumClass) {
|
||||
return registerEnumProperty(entityType, propertyIdentifier, enumClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a string-backed "enum-like" entity property where the set of allowed values
|
||||
* is defined by the provided list. If {@code defaultValue} is {@code null}, the first value is used as the default
|
||||
* on entity spawn. The default must be one of the values in {@code values}.
|
||||
* @see GeyserStringEnumProperty
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param values the allowed string values
|
||||
* @param defaultValue the default string value, or {@code null} for the first value to be used
|
||||
* @return the created string-enum property
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
GeyserStringEnumProperty registerEnumProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, @NonNull List<String> values, @Nullable String defaultValue);
|
||||
|
||||
/**
|
||||
* Registers a string-backed "enum-like" entity property with the first value as the default.
|
||||
* @see #registerEnumProperty(Identifier, Identifier, List, String)
|
||||
*
|
||||
* @param entityType the Java edition entity type identifier
|
||||
* @param propertyIdentifier the unique property identifier
|
||||
* @param values the allowed string values
|
||||
* @return the created string-enum property handle
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default GeyserStringEnumProperty registerEnumProperty(@NonNull Identifier entityType, @NonNull Identifier propertyIdentifier, @NonNull List<String> values) {
|
||||
return registerEnumProperty(entityType, propertyIdentifier, values, null);
|
||||
}
|
||||
}
|
||||
116
api/src/main/java/org/geysermc/geyser/api/util/Identifier.java
Normal file
116
api/src/main/java/org/geysermc/geyser/api/util/Identifier.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2024-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.util;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
|
||||
/**
|
||||
* An identifying object for representing unique objects.
|
||||
* This identifier consists of two parts:
|
||||
* <ul>
|
||||
* <li>
|
||||
* a namespace, which is usually a name identifying your work
|
||||
* </li>
|
||||
* <li>
|
||||
* a path, which holds a value.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* Examples of identifiers:
|
||||
* <ul>
|
||||
* <li>{@code minecraft:fox}</li>
|
||||
* <li>{@code geysermc:one_fun_example}</li>
|
||||
* </ul>
|
||||
*
|
||||
* If this identifier is referencing anything not in the
|
||||
* vanilla Minecraft game, the namespace cannot be "minecraft".
|
||||
* Further, paths cannot contain colons ({@code :}).
|
||||
*
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public interface Identifier {
|
||||
|
||||
/**
|
||||
* The namespace for Minecraft.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
String DEFAULT_NAMESPACE = "minecraft";
|
||||
|
||||
/**
|
||||
* Attempts to create a new identifier from a namespace and path.
|
||||
*
|
||||
* @return the identifier for this namespace and path
|
||||
* @throws IllegalArgumentException if either namespace or path are invalid.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
static Identifier of(@NonNull String namespace, @NonNull String path) {
|
||||
return GeyserApi.api().provider(Identifier.class, namespace, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to create a new identifier from a string representation.
|
||||
*
|
||||
* @return the identifier for this namespace and path
|
||||
* @throws IllegalArgumentException if either the namespace or path are invalid
|
||||
* @since 2.9.0
|
||||
*/
|
||||
static Identifier of(String identifier) {
|
||||
String[] split = identifier.split(":");
|
||||
String namespace;
|
||||
String path;
|
||||
if (split.length == 1) {
|
||||
namespace = DEFAULT_NAMESPACE;
|
||||
path = split[0];
|
||||
} else if (split.length == 2) {
|
||||
namespace = split[0];
|
||||
path = split[1];
|
||||
} else {
|
||||
throw new IllegalArgumentException("':' in identifier path: " + identifier);
|
||||
}
|
||||
return of(namespace, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the namespace of this identifier.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
String namespace();
|
||||
|
||||
/**
|
||||
* @return the path of this identifier.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
String path();
|
||||
|
||||
/**
|
||||
* Checks whether this identifier is using the "minecraft" namespace.
|
||||
* @since 2.9.0
|
||||
*/
|
||||
default boolean vanilla() {
|
||||
return namespace().equals(DEFAULT_NAMESPACE);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user