1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-27 10:49:10 +00:00

Continue splitting bedrock entities from java types

This commit is contained in:
onebeastchris
2025-11-23 17:54:18 +01:00
parent c57f2508cc
commit 142cbaee71
10 changed files with 80 additions and 37 deletions

View File

@@ -30,6 +30,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.entity.GeyserEntityDefinition;
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
import org.geysermc.geyser.api.util.Identifier;
@@ -102,7 +103,7 @@ public class BedrockEntityDefinition implements GeyserEntityDefinition {
return this;
}
public Builder properties(GeyserEntityProperties.Builder propertiesBuilder) {
public Builder properties(GeyserEntityProperties.@Nullable Builder propertiesBuilder) {
this.propertiesBuilder = propertiesBuilder;
return this;
}

View File

@@ -0,0 +1,33 @@
/*
* 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;
public class BedrockEntityDefinitions {
// TODO re-usable Bedrock entity definitions??????????
// Or rather... looking up otherwise??
}

View File

@@ -53,12 +53,6 @@ public record GeyserEntityType(Identifier identifier, int javaId) implements Jav
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(IdentifierImpl.of(builtin.name().toLowerCase(Locale.ROOT)), builtin.id());
}

View File

@@ -168,6 +168,7 @@ import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity;
import org.geysermc.geyser.entity.type.player.AvatarEntity;
import org.geysermc.geyser.entity.type.player.MannequinEntity;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.impl.IdentifierImpl;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataTypes;
@@ -335,10 +336,6 @@ public final class VanillaEntities {
* Is not sent over the network
*/
public static final VanillaEntityType<EnderDragonPartEntity> ENDER_DRAGON_PART;
/**
* Special Bedrock type
*/
public static final VanillaEntityType<WitherSkullEntity> WITHER_SKULL_DANGEROUS;
public static final float PLAYER_ENTITY_OFFSET;
@@ -469,7 +466,7 @@ public final class VanillaEntities {
INTERACTION = VanillaEntityType.inherited(InteractionEntity::new, entityBase)
.type(BuiltinEntityType.INTERACTION)
.heightAndWidth(1.0f) // default size until server specifies otherwise
.bedrockIdentifier("minecraft:armor_stand")
.bedrockDefinition(ARMOR_STAND.defaultBedrockDefinition())
.addTranslator(MetadataTypes.FLOAT, InteractionEntity::setWidth)
.addTranslator(MetadataTypes.FLOAT, InteractionEntity::setHeight)
.addTranslator(MetadataTypes.BOOLEAN, InteractionEntity::setResponse)
@@ -613,8 +610,19 @@ public final class VanillaEntities {
.heightAndWidth(0.3125f)
.addTranslator(MetadataTypes.BOOLEAN, WitherSkullEntity::setDangerous)
.build();
WITHER_SKULL_DANGEROUS = VanillaEntityType.inherited(WITHER_SKULL.factory(), WITHER_SKULL)
.build(false);
// Bedrock exclusive entity
IdentifierImpl dangerousSkull = IdentifierImpl.of("wither_skull_dangerous");
BedrockEntityDefinition bedrockDefinition = BedrockEntityDefinition.builder()
.height(WITHER_SKULL.height)
.width(WITHER_SKULL.width)
.offset(WITHER_SKULL.offset)
.identifier(dangerousSkull)
.build();
Registries.BEDROCK_ENTITY_DEFINITIONS.get().put(dangerousSkull, bedrockDefinition);
// WITHER_SKULL_DANGEROUS = VanillaEntityType.inherited(WITHER_SKULL.factory(), WITHER_SKULL)
// .build(false);
}
// Boats
@@ -1246,7 +1254,7 @@ public final class VanillaEntities {
// As of 1.18 these don't track entity data at all
ENDER_DRAGON_PART = VanillaEntityType.<EnderDragonPartEntity>builder(null)
.bedrockIdentifier("minecraft:armor_stand") // Emulated
.bedrockDefinition(ARMOR_STAND.defaultBedrockDefinition()) // Emulated
.build(false); // Never sent over the network
PLAYER_ENTITY_OFFSET = PLAYER.defaultBedrockDefinition().offset();

View File

@@ -70,6 +70,7 @@ public class VanillaEntityType<T extends Entity> extends EntityTypeDefinition<T>
public static class Builder<T extends Entity> extends EntityTypeDefinition.Builder<T> {
protected GeyserEntityType type;
protected BedrockEntityDefinition bedrockDefinition;
protected Builder(EntityFactory<T> factory) {
super(factory);
@@ -128,6 +129,11 @@ public class VanillaEntityType<T extends Entity> extends EntityTypeDefinition<T>
return (Builder<T>) super.addTranslator(translator);
}
public Builder<T> bedrockDefinition(BedrockEntityDefinition bedrockDefinition) {
this.bedrockDefinition = bedrockDefinition;
return this;
}
@Override
public VanillaEntityType<T> build() {
return build(true);
@@ -136,8 +142,17 @@ public class VanillaEntityType<T extends Entity> extends EntityTypeDefinition<T>
private void validateTypeAndIdentifier() {
if (type == null) {
throw new IllegalStateException("Missing entity type!");
} else if (bedrockIdentifier == null) {
bedrockIdentifier = type.identifier().toString();
}
if (bedrockDefinition == null) {
bedrockDefinition = BedrockEntityDefinition.builder()
.height(height)
.width(width)
.properties(propertiesBuilder)
.offset(offset)
.identifier(Identifier.of(bedrockIdentifier))
.build();
Registries.BEDROCK_ENTITY_DEFINITIONS.get().put(Identifier.of(bedrockIdentifier), bedrockDefinition);
}
}
@@ -148,16 +163,6 @@ public class VanillaEntityType<T extends Entity> extends EntityTypeDefinition<T>
public VanillaEntityType<T> build(boolean register) {
validateTypeAndIdentifier();
BedrockEntityDefinition bedrockDefinition = BedrockEntityDefinition.builder()
.height(height)
.width(width)
.properties(propertiesBuilder)
.offset(offset)
.identifier(Identifier.of(bedrockIdentifier))
.build();
// TODO TEST!!!
Registries.BEDROCK_ENTITY_DEFINITIONS.get().put(Identifier.of(bedrockIdentifier), bedrockDefinition);
VanillaEntityType<T> definition = new VanillaEntityType<>(factory, type, bedrockDefinition, translators);
if (register && definition.entityType() != null) {
Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition);

View File

@@ -31,7 +31,6 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
@@ -106,7 +105,7 @@ public class GeyserEntityProperties {
}
public static class Builder {
private GeyserEntityProperties properties;
private GeyserEntityProperties properties = new GeyserEntityProperties();
private final String identifier;
public Builder(String identifier) {
@@ -122,7 +121,7 @@ public class GeyserEntityProperties {
return this;
}
public @Nullable GeyserEntityProperties build() {
public @NonNull GeyserEntityProperties build() {
return properties;
}
}

View File

@@ -38,7 +38,8 @@ public interface PropertyType<Type, NetworkRepresentation extends EntityProperty
NetworkRepresentation createValue(int index, @Nullable Type value);
default void apply(GeyserEntityPropertyManager manager, Type value) {
default void apply(@Nullable GeyserEntityPropertyManager manager, Type value) {
if (manager == null) return;
manager.addProperty(this, value);
}
}

View File

@@ -87,7 +87,7 @@ public class Entity implements GeyserEntity {
protected final GeyserSession session;
@Accessors(fluent = true)
protected final BedrockEntityDefinition definition;
protected BedrockEntityDefinition definition;
protected EntityTypeDefinition<?> javaDefinition;
protected int entityId;
@@ -152,7 +152,7 @@ public class Entity implements GeyserEntity {
@Setter(AccessLevel.PROTECTED) // For players
private boolean flagsDirty = false;
protected final GeyserEntityPropertyManager propertyManager;
protected final @Nullable GeyserEntityPropertyManager propertyManager;
public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityTypeDefinition<?> definition, BedrockEntityDefinition bedrockDefinition,
Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
@@ -171,7 +171,7 @@ public class Entity implements GeyserEntity {
this.valid = false;
// TODO null or empty check
this.propertyManager = bedrockDefinition.registeredProperties() == null ? null : new GeyserEntityPropertyManager(bedrockDefinition.registeredProperties());
this.propertyManager = bedrockDefinition.registeredProperties().isEmpty() ? null : new GeyserEntityPropertyManager(bedrockDefinition.registeredProperties());
setPosition(position);
setAirSupply(getMaxAir());

View File

@@ -28,7 +28,8 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.BedrockEntityDefinition;
import org.geysermc.geyser.entity.EntityTypeDefinition;
import org.geysermc.geyser.entity.VanillaEntities;
import org.geysermc.geyser.impl.IdentifierImpl;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
@@ -36,6 +37,7 @@ import java.util.UUID;
public class WitherSkullEntity extends FireballEntity {
private boolean isCharged;
private static final IdentifierImpl DANGEROUS_SKULL = IdentifierImpl.of("wither_skull_dangerous");
public WitherSkullEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityTypeDefinition<?> definition, BedrockEntityDefinition bedrockDefinition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, bedrockDefinition, position, motion, yaw, pitch, headYaw);
@@ -48,7 +50,7 @@ public class WitherSkullEntity extends FireballEntity {
if (newDangerous != isCharged) {
isCharged = newDangerous;
// Is an entirely new entity in Bedrock but just a metadata type in Java
javaDefinition = isCharged ? VanillaEntities.WITHER_SKULL_DANGEROUS : VanillaEntities.WITHER_SKULL;
definition = isCharged ? Registries.BEDROCK_ENTITY_DEFINITIONS.get(DANGEROUS_SKULL) : javaDefinition.defaultBedrockDefinition();
despawnEntity();
spawnEntity();
}

View File

@@ -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.definition().identifier() + ").");
return;
}