mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-06 15:41:50 +00:00
Further refactor EntityDefinition, create a Base class
This commit is contained in:
@@ -42,6 +42,10 @@ public interface JavaEntityType {
|
||||
return javaIdentifier().equals(javaIdentifier);
|
||||
}
|
||||
|
||||
static JavaEntityType ofVanilla(@NonNull Identifier javaIdentifier) {
|
||||
return GeyserApi.api().provider(JavaEntityType.class, javaIdentifier);
|
||||
}
|
||||
|
||||
static JavaEntityType create(@NonNull Identifier javaIdentifier, @NonNegative int javaId) {
|
||||
return GeyserApi.api().provider(JavaEntityType.class, javaIdentifier, javaId);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,12 @@
|
||||
|
||||
package org.geysermc.geyser.entity;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.factory.EntityFactory;
|
||||
import org.geysermc.geyser.entity.properties.GeyserEntityProperties;
|
||||
import org.geysermc.geyser.entity.properties.type.PropertyType;
|
||||
@@ -53,120 +51,99 @@ import java.util.function.BiConsumer;
|
||||
*/
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class EntityDefinition<T extends Entity> {
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public abstract class EntityDefinition<T extends Entity> extends EntityDefinitionBase<T> {
|
||||
private final EntityFactory<T> factory;
|
||||
private final GeyserEntityType entityType;
|
||||
private final String identifier;
|
||||
private final float width;
|
||||
private final float height;
|
||||
private final float offset;
|
||||
private final String bedrockIdentifier;
|
||||
private final GeyserEntityProperties registeredProperties;
|
||||
private final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
|
||||
|
||||
/**
|
||||
* @param identifier the Bedrock identifier of this entity
|
||||
*/
|
||||
public EntityDefinition(EntityFactory<T> factory, GeyserEntityType entityType, String identifier,
|
||||
public EntityDefinition(EntityFactory<T> factory, GeyserEntityType entityType, String bedrockIdentifier,
|
||||
float width, float height, float offset, GeyserEntityProperties registeredProperties, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
super(width, height, offset, translators);
|
||||
this.factory = factory;
|
||||
this.entityType = entityType;
|
||||
this.identifier = identifier;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.offset = offset;
|
||||
this.bedrockIdentifier = bedrockIdentifier;
|
||||
this.registeredProperties = registeredProperties;
|
||||
this.translators = translators;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <M> void translateMetadata(T entity, EntityMetadata<M, ? extends MetadataType<M>> metadata) {
|
||||
EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>> translator = (EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>>) this.translators.get(metadata.getId());
|
||||
if (translator == null) {
|
||||
// This can safely happen; it means we don't translate this entity metadata
|
||||
return;
|
||||
}
|
||||
|
||||
if (translator.acceptedType() != metadata.getType()) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Metadata ID " + metadata.getId() + " was received with type " + metadata.getType() + " but we expected " + translator.acceptedType() + " for " + entity.getDefinition().entityType());
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(metadata.toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
translator.translate(entity, metadata);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Accessors(fluent = true, chain = true)
|
||||
public static abstract class Builder<T extends Entity> {
|
||||
public static abstract class Builder<T extends Entity> extends EntityDefinitionBase.Builder<T> {
|
||||
protected final EntityFactory<T> factory;
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected GeyserEntityType type;
|
||||
|
||||
protected String identifier;
|
||||
protected float width;
|
||||
protected float height;
|
||||
protected float offset = 0.00001f;
|
||||
protected String bedrockIdentifier;
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected GeyserEntityProperties.Builder propertiesBuilder;
|
||||
protected final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
|
||||
|
||||
protected Builder(EntityFactory<T> factory) {
|
||||
super();
|
||||
this.factory = factory;
|
||||
translators = new ObjectArrayList<>();
|
||||
}
|
||||
|
||||
protected Builder(EntityFactory<T> factory, GeyserEntityType type, String identifier, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
protected Builder(EntityFactory<T> factory, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
super(width, height, offset, translators);
|
||||
this.factory = factory;
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.offset = offset;
|
||||
this.translators = translators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height and width as one value
|
||||
* Resets the bedrock identifier as well
|
||||
*/
|
||||
public Builder<T> heightAndWidth(float value) {
|
||||
height = value;
|
||||
width = value;
|
||||
public Builder<T> type(GeyserEntityType type) {
|
||||
this.type = type;
|
||||
this.bedrockIdentifier = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> width(float width) {
|
||||
return (Builder<T>) super.width(width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> height(float height) {
|
||||
return (Builder<T>) super.height(height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> heightAndWidth(float value) {
|
||||
return (Builder<T>) super.heightAndWidth(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> offset(float offset) {
|
||||
this.offset = offset + 0.00001f;
|
||||
return this;
|
||||
return (Builder<T>) super.offset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U, EM extends EntityMetadata<U, ? extends MetadataType<U>>> Builder<T> addTranslator(MetadataType<U> type, BiConsumer<T, EM> translateFunction) {
|
||||
return (Builder<T>) super.addTranslator(type, translateFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> addTranslator(EntityMetadataTranslator<T, ?, ?> translator) {
|
||||
return (Builder<T>) super.addTranslator(translator);
|
||||
}
|
||||
|
||||
public Builder<T> property(PropertyType<?, ?> propertyType) {
|
||||
if (this.propertiesBuilder == null) {
|
||||
this.propertiesBuilder = new GeyserEntityProperties.Builder(this.identifier);
|
||||
this.propertiesBuilder = new GeyserEntityProperties.Builder(this.bedrockIdentifier);
|
||||
}
|
||||
propertiesBuilder.add(propertyType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <U, EM extends EntityMetadata<U, ? extends MetadataType<U>>> Builder<T> addTranslator(MetadataType<U> type, BiConsumer<T, EM> translateFunction) {
|
||||
translators.add(new EntityMetadataTranslator<>(type, translateFunction));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> addTranslator(EntityMetadataTranslator<T, ?, ?> translator) {
|
||||
translators.add(translator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityDefinition<T> build() {
|
||||
if (identifier == null && type != null) {
|
||||
identifier = type.javaIdentifier().toString();
|
||||
protected void validateTypeAndIdentifier() {
|
||||
if (type == null) {
|
||||
throw new IllegalStateException("Missing entity type!");
|
||||
} else if (bedrockIdentifier == null) {
|
||||
bedrockIdentifier = type.javaIdentifier().toString();
|
||||
}
|
||||
GeyserEntityProperties registeredProperties = propertiesBuilder == null ? null : propertiesBuilder.build();
|
||||
return new EntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.entity;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.translator.entity.EntityMetadataTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class EntityDefinitionBase<T extends Entity> {
|
||||
private final float width;
|
||||
private final float height;
|
||||
private final float offset;
|
||||
private final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
|
||||
|
||||
public EntityDefinitionBase(float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.offset = offset;
|
||||
this.translators = translators;
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> baseBuilder(Class<T> clazz) {
|
||||
return new Builder<>(clazz);
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> baseInherited(EntityDefinitionBase<? super T> parent) {
|
||||
return new Builder<>(parent.width(), parent.height(), parent.offset(), new ObjectArrayList<>(parent.translators()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <M> void translateMetadata(T entity, EntityMetadata<M, ? extends MetadataType<M>> metadata) {
|
||||
EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>> translator = (EntityMetadataTranslator<? super T, M, EntityMetadata<M, ? extends MetadataType<M>>>) this.translators.get(metadata.getId());
|
||||
if (translator == null) {
|
||||
// This can safely happen; it means we don't translate this entity metadata
|
||||
return;
|
||||
}
|
||||
|
||||
if (translator.acceptedType() != metadata.getType()) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Metadata ID " + metadata.getId() + " was received with type " + metadata.getType() + " but we expected " + translator.acceptedType() + " for " + entity.getDefinition().entityType());
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(metadata.toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
translator.translate(entity, metadata);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Accessors(fluent = true, chain = true)
|
||||
public static class Builder<T extends Entity> {
|
||||
protected float width;
|
||||
protected float height;
|
||||
protected float offset = 0.00001f;
|
||||
protected final List<EntityMetadataTranslator<? super T, ?, ?>> translators;
|
||||
|
||||
protected Builder() {
|
||||
translators = new ObjectArrayList<>();
|
||||
}
|
||||
|
||||
// Unused param so Java knows what entity we're talking about
|
||||
protected Builder(@SuppressWarnings("unused") Class<T> clazz) {
|
||||
this();
|
||||
}
|
||||
|
||||
protected Builder(float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.offset = offset;
|
||||
this.translators = translators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height and width as one value
|
||||
*/
|
||||
public Builder<T> heightAndWidth(float value) {
|
||||
height = value;
|
||||
width = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> offset(float offset) {
|
||||
this.offset = offset + 0.00001f;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <U, EM extends EntityMetadata<U, ? extends MetadataType<U>>> Builder<T> addTranslator(MetadataType<U> type, BiConsumer<T, EM> translateFunction) {
|
||||
translators.add(new EntityMetadataTranslator<>(type, translateFunction));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> addTranslator(EntityMetadataTranslator<T, ?, ?> translator) {
|
||||
translators.add(translator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityDefinitionBase<T> build() {
|
||||
return new EntityDefinitionBase<>(width, height, offset, translators);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,7 +364,7 @@ public final class EntityDefinitions {
|
||||
END_CRYSTAL = VanillaEntityDefinition.inherited(EnderCrystalEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.END_CRYSTAL)
|
||||
.heightAndWidth(2.0f)
|
||||
.identifier("minecraft:ender_crystal")
|
||||
.bedrockIdentifier("minecraft:ender_crystal")
|
||||
.addTranslator(MetadataTypes.OPTIONAL_BLOCK_POS, EnderCrystalEntity::setBlockTarget)
|
||||
.addTranslator(MetadataTypes.BOOLEAN,
|
||||
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
|
||||
@@ -372,17 +372,17 @@ public final class EntityDefinitions {
|
||||
EXPERIENCE_ORB = VanillaEntityDefinition.inherited(ExpOrbEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.EXPERIENCE_ORB)
|
||||
.addTranslator(null) // int determining xb orb texture
|
||||
.identifier("minecraft:xp_orb")
|
||||
.bedrockIdentifier("minecraft:xp_orb")
|
||||
.build();
|
||||
EVOKER_FANGS = VanillaEntityDefinition.inherited(EvokerFangsEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.EVOKER_FANGS)
|
||||
.height(0.8f).width(0.5f)
|
||||
.identifier("minecraft:evocation_fang")
|
||||
.bedrockIdentifier("minecraft:evocation_fang")
|
||||
.build();
|
||||
EYE_OF_ENDER = VanillaEntityDefinition.inherited(EnderEyeEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.EYE_OF_ENDER)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:eye_of_ender_signal")
|
||||
.bedrockIdentifier("minecraft:eye_of_ender_signal")
|
||||
.addTranslator(null) // Item
|
||||
.build();
|
||||
FALLING_BLOCK = VanillaEntityDefinition.<FallingBlockEntity>inherited(null, entityBase)
|
||||
@@ -393,14 +393,14 @@ public final class EntityDefinitions {
|
||||
FIREWORK_ROCKET = VanillaEntityDefinition.inherited(FireworkEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.FIREWORK_ROCKET)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:fireworks_rocket")
|
||||
.bedrockIdentifier("minecraft:fireworks_rocket")
|
||||
.addTranslator(MetadataTypes.ITEM_STACK, FireworkEntity::setFireworkItem)
|
||||
.addTranslator(MetadataTypes.OPTIONAL_UNSIGNED_INT, FireworkEntity::setPlayerGliding)
|
||||
.addTranslator(null) // Shot at angle
|
||||
.build();
|
||||
FISHING_BOBBER = VanillaEntityDefinition.<FishingHookEntity>inherited(null, entityBase)
|
||||
.type(BuiltinEntityType.FISHING_BOBBER)
|
||||
.identifier("minecraft:fishing_hook")
|
||||
.bedrockIdentifier("minecraft:fishing_hook")
|
||||
.addTranslator(MetadataTypes.INT, FishingHookEntity::setHookedEntity)
|
||||
.addTranslator(null) // Biting TODO check
|
||||
.build();
|
||||
@@ -451,7 +451,7 @@ public final class EntityDefinitions {
|
||||
.build();
|
||||
TEXT_DISPLAY = VanillaEntityDefinition.inherited(TextDisplayEntity::new, displayBase)
|
||||
.type(BuiltinEntityType.TEXT_DISPLAY)
|
||||
.identifier("minecraft:armor_stand")
|
||||
.bedrockIdentifier("minecraft:armor_stand")
|
||||
.offset(-0.5f)
|
||||
.addTranslator(MetadataTypes.COMPONENT, TextDisplayEntity::setText)
|
||||
.addTranslator(null) // Line width
|
||||
@@ -463,7 +463,7 @@ public final class EntityDefinitions {
|
||||
INTERACTION = VanillaEntityDefinition.inherited(InteractionEntity::new, entityBase)
|
||||
.type(BuiltinEntityType.INTERACTION)
|
||||
.heightAndWidth(1.0f) // default size until server specifies otherwise
|
||||
.identifier("minecraft:armor_stand")
|
||||
.bedrockIdentifier("minecraft:armor_stand")
|
||||
.addTranslator(MetadataTypes.FLOAT, InteractionEntity::setWidth)
|
||||
.addTranslator(MetadataTypes.FLOAT, InteractionEntity::setHeight)
|
||||
.addTranslator(MetadataTypes.BOOLEAN, InteractionEntity::setResponse)
|
||||
@@ -496,17 +496,17 @@ public final class EntityDefinitions {
|
||||
EXPERIENCE_BOTTLE = VanillaEntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase)
|
||||
.type(BuiltinEntityType.EXPERIENCE_BOTTLE)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:xp_bottle")
|
||||
.bedrockIdentifier("minecraft:xp_bottle")
|
||||
.build();
|
||||
SPLASH_POTION = VanillaEntityDefinition.inherited(ThrownPotionEntity::new, throwableItemBase)
|
||||
.type(BuiltinEntityType.SPLASH_POTION)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:splash_potion")
|
||||
.bedrockIdentifier("minecraft:splash_potion")
|
||||
.build();
|
||||
LINGERING_POTION = VanillaEntityDefinition.inherited(ThrownPotionEntity::new, throwableItemBase)
|
||||
.type(BuiltinEntityType.LINGERING_POTION)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:splash_potion")
|
||||
.bedrockIdentifier("minecraft:splash_potion")
|
||||
.build();
|
||||
SNOWBALL = VanillaEntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase)
|
||||
.type(BuiltinEntityType.SNOWBALL)
|
||||
@@ -516,12 +516,12 @@ public final class EntityDefinitions {
|
||||
EntityFactory<AbstractWindChargeEntity> windChargeSupplier = AbstractWindChargeEntity::new;
|
||||
BREEZE_WIND_CHARGE = VanillaEntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||
.type(BuiltinEntityType.BREEZE_WIND_CHARGE)
|
||||
.identifier("minecraft:breeze_wind_charge_projectile")
|
||||
.bedrockIdentifier("minecraft:breeze_wind_charge_projectile")
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
WIND_CHARGE = VanillaEntityDefinition.inherited(windChargeSupplier, entityBase)
|
||||
.type(BuiltinEntityType.WIND_CHARGE)
|
||||
.identifier("minecraft:wind_charge_projectile")
|
||||
.bedrockIdentifier("minecraft:wind_charge_projectile")
|
||||
.heightAndWidth(0.3125f)
|
||||
.build();
|
||||
|
||||
@@ -538,11 +538,11 @@ public final class EntityDefinitions {
|
||||
SPECTRAL_ARROW = VanillaEntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase)
|
||||
.type(BuiltinEntityType.SPECTRAL_ARROW)
|
||||
.heightAndWidth(0.25f)
|
||||
.identifier("minecraft:arrow")
|
||||
.bedrockIdentifier("minecraft:arrow")
|
||||
.build();
|
||||
TRIDENT = VanillaEntityDefinition.inherited(TridentEntity::new, abstractArrowBase) // TODO remove class
|
||||
.type(BuiltinEntityType.TRIDENT)
|
||||
.identifier("minecraft:thrown_trident")
|
||||
.bedrockIdentifier("minecraft:thrown_trident")
|
||||
.addTranslator(null) // Loyalty
|
||||
.addTranslator(MetadataTypes.BOOLEAN, (tridentEntity, entityMetadata) -> tridentEntity.setFlag(EntityFlag.ENCHANTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
|
||||
.build();
|
||||
@@ -588,7 +588,7 @@ public final class EntityDefinitions {
|
||||
.build();
|
||||
FURNACE_MINECART = VanillaEntityDefinition.inherited(FurnaceMinecartEntity::new, MINECART)
|
||||
.type(BuiltinEntityType.FURNACE_MINECART)
|
||||
.identifier("minecraft:minecart")
|
||||
.bedrockIdentifier("minecraft:minecart")
|
||||
.addTranslator(MetadataTypes.BOOLEAN, FurnaceMinecartEntity::setHasFuel)
|
||||
.build();
|
||||
HOPPER_MINECART = VanillaEntityDefinition.inherited(MINECART.factory(), MINECART)
|
||||
@@ -596,7 +596,7 @@ public final class EntityDefinitions {
|
||||
.build();
|
||||
SPAWNER_MINECART = VanillaEntityDefinition.inherited(SpawnerMinecartEntity::new, MINECART)
|
||||
.type(BuiltinEntityType.SPAWNER_MINECART)
|
||||
.identifier("minecraft:minecart")
|
||||
.bedrockIdentifier("minecraft:minecart")
|
||||
.build();
|
||||
TNT_MINECART = VanillaEntityDefinition.inherited(MINECART.factory(), MINECART)
|
||||
.type(BuiltinEntityType.TNT_MINECART)
|
||||
@@ -779,7 +779,7 @@ public final class EntityDefinitions {
|
||||
.type(BuiltinEntityType.GIANT)
|
||||
.height(1.8f).width(1.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie")
|
||||
.bedrockIdentifier("minecraft:zombie")
|
||||
.build();
|
||||
IRON_GOLEM = VanillaEntityDefinition.inherited(IronGolemEntity::new, mobEntityBase)
|
||||
.type(BuiltinEntityType.IRON_GOLEM)
|
||||
@@ -868,7 +868,7 @@ public final class EntityDefinitions {
|
||||
.type(BuiltinEntityType.ZOMBIE_VILLAGER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie_villager_v2")
|
||||
.bedrockIdentifier("minecraft:zombie_villager_v2")
|
||||
.addTranslator(MetadataTypes.BOOLEAN, ZombieVillagerEntity::setTransforming)
|
||||
.addTranslator(MetadataTypes.VILLAGER_DATA, ZombieVillagerEntity::setZombieVillagerData)
|
||||
.build();
|
||||
@@ -876,7 +876,7 @@ public final class EntityDefinitions {
|
||||
.type(BuiltinEntityType.ZOMBIFIED_PIGLIN)
|
||||
.height(1.95f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:zombie_pigman")
|
||||
.bedrockIdentifier("minecraft:zombie_pigman")
|
||||
.build();
|
||||
|
||||
DROWNED = VanillaEntityDefinition.inherited(ZOMBIE.factory(), ZOMBIE)
|
||||
@@ -931,7 +931,7 @@ public final class EntityDefinitions {
|
||||
TROPICAL_FISH = VanillaEntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase)
|
||||
.type(BuiltinEntityType.TROPICAL_FISH)
|
||||
.heightAndWidth(0.6f)
|
||||
.identifier("minecraft:tropicalfish")
|
||||
.bedrockIdentifier("minecraft:tropicalfish")
|
||||
.addTranslator(MetadataTypes.INT, TropicalFishEntity::setFishVariant)
|
||||
.build();
|
||||
|
||||
@@ -959,12 +959,12 @@ public final class EntityDefinitions {
|
||||
EVOKER = VanillaEntityDefinition.inherited(spellcasterEntityBase.factory(), spellcasterEntityBase)
|
||||
.type(BuiltinEntityType.EVOKER)
|
||||
.height(1.95f).width(0.6f)
|
||||
.identifier("minecraft:evocation_illager")
|
||||
.bedrockIdentifier("minecraft:evocation_illager")
|
||||
.build();
|
||||
ILLUSIONER = VanillaEntityDefinition.inherited(spellcasterEntityBase.factory(), spellcasterEntityBase)
|
||||
.type(BuiltinEntityType.ILLUSIONER)
|
||||
.height(1.95f).width(0.6f)
|
||||
.identifier("minecraft:evocation_illager")
|
||||
.bedrockIdentifier("minecraft:evocation_illager")
|
||||
.build();
|
||||
PILLAGER = VanillaEntityDefinition.inherited(PillagerEntity::new, raidParticipantEntityBase)
|
||||
.type(BuiltinEntityType.PILLAGER)
|
||||
@@ -1132,7 +1132,7 @@ public final class EntityDefinitions {
|
||||
.type(BuiltinEntityType.VILLAGER)
|
||||
.height(1.8f).width(0.6f)
|
||||
.offset(1.62f)
|
||||
.identifier("minecraft:villager_v2")
|
||||
.bedrockIdentifier("minecraft:villager_v2")
|
||||
.addTranslator(MetadataTypes.VILLAGER_DATA, VillagerEntity::setVillagerData)
|
||||
.build();
|
||||
WANDERING_TRADER = VanillaEntityDefinition.inherited(abstractVillagerEntityBase.factory(), abstractVillagerEntityBase)
|
||||
@@ -1205,7 +1205,7 @@ public final class EntityDefinitions {
|
||||
.build();
|
||||
TRADER_LLAMA = VanillaEntityDefinition.inherited(TraderLlamaEntity::new, LLAMA)
|
||||
.type(BuiltinEntityType.TRADER_LLAMA)
|
||||
.identifier("minecraft:llama")
|
||||
.bedrockIdentifier("minecraft:llama")
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -1240,7 +1240,7 @@ public final class EntityDefinitions {
|
||||
|
||||
// As of 1.18 these don't track entity data at all
|
||||
ENDER_DRAGON_PART = VanillaEntityDefinition.<EnderDragonPartEntity>builder(null)
|
||||
.identifier("minecraft:armor_stand") // Emulated
|
||||
.bedrockIdentifier("minecraft:armor_stand") // Emulated
|
||||
.build(false); // Never sent over the network
|
||||
|
||||
Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network
|
||||
@@ -1250,7 +1250,7 @@ public final class EntityDefinitions {
|
||||
return VanillaEntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
|
||||
new BoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
|
||||
.type(BuiltinEntityType)
|
||||
.identifier("minecraft:boat")
|
||||
.bedrockIdentifier("minecraft:boat")
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -1258,7 +1258,7 @@ public final class EntityDefinitions {
|
||||
return VanillaEntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
|
||||
new ChestBoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
|
||||
.type(BuiltinEntityType)
|
||||
.identifier("minecraft:chest_boat")
|
||||
.bedrockIdentifier("minecraft:chest_boat")
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -1339,7 +1339,7 @@ public final class EntityDefinitions {
|
||||
});
|
||||
|
||||
for (var definition : Registries.ENTITY_DEFINITIONS.get().values()) {
|
||||
if (!definition.registeredProperties().isEmpty()) {
|
||||
if (!definition.registeredProperties().isEmpty()) { // TODO Null or empty check??
|
||||
Registries.BEDROCK_ENTITY_PROPERTIES.get().add(definition.registeredProperties().toNbtMap(definition.identifier()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.api.entity.JavaEntityType;
|
||||
import org.geysermc.geyser.api.util.Identifier;
|
||||
import org.geysermc.geyser.impl.IdentifierImpl;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.BuiltinEntityType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
@@ -46,21 +47,29 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public record GeyserEntityType(Identifier javaIdentifier, int javaId) implements JavaEntityType {
|
||||
private static final Identifier UNREGISTERED = IdentifierImpl.of(Constants.GEYSER_CUSTOM_NAMESPACE, "unregistered_sadface");
|
||||
|
||||
private static final Map<BuiltinEntityType, GeyserEntityType> VANILLA = new EnumMap<>(BuiltinEntityType.class);
|
||||
private static final Int2ObjectMap<GeyserEntityType> CUSTOM = new Int2ObjectOpenHashMap<>();
|
||||
private static final Object2ObjectMap<Identifier, GeyserEntityType> CUSTOM_BY_IDENTIFIER = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public GeyserEntityType {
|
||||
if (!VANILLA.containsValue(this) && !CUSTOM.containsKey(javaId)) {
|
||||
throw new IllegalCallerException("Public constructor of GeyserEntityType should not be used; use one of the static factory methods instead");
|
||||
}
|
||||
}
|
||||
|
||||
private GeyserEntityType(BuiltinEntityType builtin) {
|
||||
this(Identifier.of(builtin.name().toLowerCase(Locale.ROOT)), builtin.id());
|
||||
}
|
||||
|
||||
private GeyserEntityType(int javaId) {
|
||||
this(Identifier.of(Constants.GEYSER_CUSTOM_NAMESPACE, "unregistered_sadface"), javaId);
|
||||
this(UNREGISTERED, javaId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnregistered() {
|
||||
return javaIdentifier.namespace().equals(Constants.GEYSER_CUSTOM_NAMESPACE) && javaIdentifier.path().equals("unregistered_sadface");
|
||||
return javaIdentifier.equals(UNREGISTERED);
|
||||
}
|
||||
|
||||
public boolean is(EntityType type) {
|
||||
@@ -71,6 +80,13 @@ public record GeyserEntityType(Identifier javaIdentifier, int javaId) implements
|
||||
return VANILLA.computeIfAbsent(builtin, GeyserEntityType::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException document this in API
|
||||
*/
|
||||
public static GeyserEntityType ofVanilla(Identifier javaIdentifier) {
|
||||
return ofVanilla(BuiltinEntityType.valueOf(javaIdentifier.path().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
public static GeyserEntityType of(int javaId) {
|
||||
if (javaId >= 0 && javaId < BuiltinEntityType.VALUES.length) {
|
||||
return ofVanilla(BuiltinEntityType.VALUES[javaId]);
|
||||
@@ -84,7 +100,7 @@ public record GeyserEntityType(Identifier javaIdentifier, int javaId) implements
|
||||
public static GeyserEntityType of(Key javaKey) {
|
||||
if (javaKey.namespace().equals(Key.MINECRAFT_NAMESPACE)) {
|
||||
try {
|
||||
return ofVanilla(BuiltinEntityType.valueOf(javaKey.value().toUpperCase(Locale.ROOT)));
|
||||
return ofVanilla(MinecraftKey.keyToIdentifier(javaKey));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -48,50 +48,37 @@ import java.util.function.BiConsumer;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class VanillaEntityDefinition<T extends Entity> extends EntityDefinition<T> {
|
||||
private final BuiltinEntityType builtinType;
|
||||
|
||||
/**
|
||||
* @param identifier the Bedrock identifier of this entity
|
||||
*/
|
||||
public VanillaEntityDefinition(EntityFactory<T> factory, GeyserEntityType entityType, String identifier,
|
||||
float width, float height, float offset, GeyserEntityProperties registeredProperties, List<EntityMetadataTranslator<? super T, ?, ?>> translators,
|
||||
BuiltinEntityType builtinType) {
|
||||
super(factory, entityType, identifier, width, height, offset, registeredProperties, translators);
|
||||
this.builtinType = builtinType;
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> inherited(EntityFactory<T> factory, EntityDefinition<? super T> parent) {
|
||||
return new Builder<>(factory, parent.entityType(), parent.identifier(), parent.width(), parent.height(), parent.offset(), new ObjectArrayList<>(parent.translators()));
|
||||
public VanillaEntityDefinition(EntityFactory<T> factory, GeyserEntityType entityType, String bedrockIdentifier,
|
||||
float width, float height, float offset, GeyserEntityProperties registeredProperties, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
super(factory, entityType, bedrockIdentifier, width, height, offset, registeredProperties, translators);
|
||||
}
|
||||
|
||||
public static <T extends Entity> Builder<T> builder(EntityFactory<T> factory) {
|
||||
return new Builder<>(factory);
|
||||
}
|
||||
|
||||
public static class Builder<T extends Entity> extends EntityDefinition.Builder<T> {
|
||||
private BuiltinEntityType builtinType;
|
||||
public static <T extends Entity> Builder<T> inherited(EntityFactory<T> factory, EntityDefinition<? super T> parent) {
|
||||
return new Builder<>(factory, parent.width(), parent.height(), parent.offset(), new ObjectArrayList<>(parent.translators()));
|
||||
}
|
||||
|
||||
private Builder(EntityFactory<T> factory) {
|
||||
public static class Builder<T extends Entity> extends EntityDefinition.Builder<T> {
|
||||
|
||||
protected Builder(EntityFactory<T> factory) {
|
||||
super(factory);
|
||||
}
|
||||
|
||||
public Builder(EntityFactory<T> factory, GeyserEntityType type, String identifier, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> entityMetadataTranslators) {
|
||||
super(factory, type, identifier, width, height, offset, entityMetadataTranslators);
|
||||
protected Builder(EntityFactory<T> factory, float width, float height, float offset, List<EntityMetadataTranslator<? super T, ?, ?>> translators) {
|
||||
super(factory, width, height, offset, translators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the identifier as well
|
||||
*/
|
||||
public Builder<T> type(BuiltinEntityType type) {
|
||||
this.type = GeyserEntityType.ofVanilla(type);
|
||||
builtinType = type;
|
||||
identifier(null);
|
||||
return this;
|
||||
return (Builder<T>) super.type(GeyserEntityType.ofVanilla(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> identifier(String identifier) {
|
||||
return (Builder<T>) super.identifier(identifier);
|
||||
public Builder<T> bedrockIdentifier(String bedrockIdentifier) {
|
||||
return (Builder<T>) super.bedrockIdentifier(bedrockIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,13 +125,11 @@ public class VanillaEntityDefinition<T extends Entity> extends EntityDefinition<
|
||||
* @param register whether to register this entity in the Registries for entity types. Generally this should be
|
||||
* set to false if we're not expecting this entity to spawn from the network.
|
||||
*/
|
||||
// TODO fix code duplication
|
||||
public VanillaEntityDefinition<T> build(boolean register) {
|
||||
if (identifier == null && type != null) {
|
||||
identifier = type.javaIdentifier().toString();
|
||||
}
|
||||
validateTypeAndIdentifier();
|
||||
|
||||
GeyserEntityProperties registeredProperties = propertiesBuilder == null ? null : propertiesBuilder.build();
|
||||
VanillaEntityDefinition<T> definition = new VanillaEntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators, builtinType);
|
||||
VanillaEntityDefinition<T> definition = new VanillaEntityDefinition<>(factory, type, bedrockIdentifier, width, height, offset, registeredProperties, translators);
|
||||
if (register && definition.entityType() != null) {
|
||||
Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition);
|
||||
Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent(type.javaIdentifier().toString(), definition);
|
||||
|
||||
@@ -70,7 +70,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Boolea
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
@@ -199,7 +198,7 @@ public class Entity implements GeyserEntity {
|
||||
|
||||
public void spawnEntity() {
|
||||
AddEntityPacket addEntityPacket = new AddEntityPacket();
|
||||
addEntityPacket.setIdentifier(definition.identifier());
|
||||
addEntityPacket.setIdentifier(definition.bedrockIdentifier());
|
||||
addEntityPacket.setRuntimeEntityId(geyserId);
|
||||
addEntityPacket.setUniqueEntityId(geyserId);
|
||||
addEntityPacket.setPosition(position);
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ProviderRegistryLoader implements RegistryLoader<Map<Class<?>, Prov
|
||||
providers.put(CameraPosition.Builder.class, args -> new GeyserCameraPosition.Builder());
|
||||
|
||||
// entities
|
||||
providers.put(JavaEntityType.class, args -> GeyserEntityType.createCustom((Identifier) args[0], (int) args[1]));
|
||||
providers.put(JavaEntityType.class, args -> args.length == 1 ? GeyserEntityType.ofVanilla((Identifier) args[0]) : GeyserEntityType.createCustom((Identifier) args[0], (int) args[1]));
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class TrialSpawnerBlockEntityTranslator extends BlockEntityTranslator {
|
||||
NbtMapBuilder spawnData = NbtMap.builder();
|
||||
EntityDefinition<?> definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityData.getString("id"));
|
||||
if (definition != null) {
|
||||
spawnData.putString("TypeId", definition.identifier());
|
||||
spawnData.putString("TypeId", definition.bedrockIdentifier());
|
||||
}
|
||||
spawnData.putInt("Weight", entityData.getInt("Size", 1)); // ??? presumably since these are the only other two extra attributes
|
||||
bedrockNbt.putCompound("spawn_data", spawnData.build());
|
||||
|
||||
@@ -50,7 +50,7 @@ public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetE
|
||||
|
||||
if (!(entity instanceof LivingEntity livingEntity)) {
|
||||
session.getGeyser().getLogger().debug("Attempted to add armor to a non-living entity (" +
|
||||
entity.getDefinition().identifier() + ").");
|
||||
entity.getDefinition().bedrockIdentifier() + ").");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user