mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-06 15:41:50 +00:00
API polishing; properly initialize height/width
This commit is contained in:
@@ -26,10 +26,7 @@
|
||||
package org.geysermc.geyser.entity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.api.entity.custom.CustomEntityDefinition;
|
||||
@@ -42,17 +39,10 @@ import org.geysermc.geyser.registry.Registries;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
@ToString
|
||||
public class BedrockEntityDefinition implements GeyserEntityDefinition, CustomEntityDefinition {
|
||||
private final @NonNull Identifier identifier;
|
||||
private final @NonNull GeyserEntityProperties registeredProperties;
|
||||
|
||||
public BedrockEntityDefinition(@NonNull Identifier identifier, @NonNull GeyserEntityProperties registeredProperties) {
|
||||
this.identifier = identifier;
|
||||
this.registeredProperties = registeredProperties;
|
||||
}
|
||||
public record BedrockEntityDefinition(
|
||||
@NonNull Identifier identifier,
|
||||
@NonNull GeyserEntityProperties registeredProperties
|
||||
) implements GeyserEntityDefinition, CustomEntityDefinition {
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
|
||||
@@ -215,7 +215,7 @@ public record GeyserEntityType(Identifier identifier, int javaId) implements Jav
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder defaultBedrockDefinition(@Nullable GeyserEntityDefinition defaultBedrockDefinition) {
|
||||
public Builder definition(@Nullable GeyserEntityDefinition defaultBedrockDefinition) {
|
||||
if (defaultBedrockDefinition == null) {
|
||||
this.defaultBedrockDefinition = null;
|
||||
} else if (defaultBedrockDefinition instanceof BedrockEntityDefinition bedrockEntityDefinition) {
|
||||
|
||||
@@ -38,12 +38,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.type.BuiltinEntityTy
|
||||
@ToString(callSuper = true)
|
||||
public class NonVanillaEntityTypeDefinition extends EntityTypeDefinition<Entity> {
|
||||
|
||||
/*
|
||||
Soooooooooooooo this is fun.
|
||||
- How should we expose entity metadata translators?
|
||||
- Extending "vanilla" classes / entities??? Geyser uses instanceof checks...
|
||||
*/
|
||||
|
||||
public NonVanillaEntityTypeDefinition(GeyserEntityType.Builder builder, GeyserEntityType entityType) {
|
||||
super(Entity::new, entityType, builder.getWidth(), builder.getHeight(), 0f, builder.getDefaultBedrockDefinition(), VanillaEntityBases.ENTITY.translators);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.entity.spawn;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -56,7 +55,6 @@ import java.util.function.Consumer;
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(fluent = true)
|
||||
@AllArgsConstructor
|
||||
public class EntitySpawnContext {
|
||||
private final GeyserSession session;
|
||||
private final EntityTypeDefinition<?> entityTypeDefinition;
|
||||
@@ -80,29 +78,51 @@ public class EntitySpawnContext {
|
||||
|
||||
public EntitySpawnContext(GeyserSession session, EntityTypeDefinition<?> type, int javaId, UUID uuid) {
|
||||
this(session, type, javaId, uuid, type.defaultBedrockDefinition(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0,
|
||||
type.height(), type.width(), type.offset(), null, null);
|
||||
type.height(), type.width(), type.offset(), null);
|
||||
}
|
||||
|
||||
public EntitySpawnContext(GeyserSession session, EntityTypeDefinition<?> type, int entityId, BedrockEntityDefinition definition, float height, float width, long geyserId) {
|
||||
this(session, type, entityId, null, definition, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, height, width, 0, geyserId, null);
|
||||
this(session, type, entityId, null, definition, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, height, width, 0, geyserId);
|
||||
}
|
||||
|
||||
public static EntitySpawnContext fromPacket(GeyserSession session, EntityTypeDefinition<?> definition, ClientboundAddEntityPacket packet) {
|
||||
Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||
Vector3f motion = packet.getMovement().toFloat();
|
||||
return new EntitySpawnContext(session, definition, packet.getEntityId(), packet.getUuid(), definition.defaultBedrockDefinition(),
|
||||
position, motion, packet.getYaw(), packet.getPitch(), packet.getHeadYaw(), definition.height(), definition.width(), definition.offset(), null, null);
|
||||
position, motion, packet.getYaw(), packet.getPitch(), packet.getHeadYaw(), definition.height(), definition.width(), definition.offset(), null);
|
||||
}
|
||||
|
||||
public static EntitySpawnContext inherited(GeyserSession session, EntityTypeDefinition<?> definition, Entity base, Vector3f position) {
|
||||
return new EntitySpawnContext(session, definition, 0, null, definition.defaultBedrockDefinition(), position, base.getMotion(), base.getYaw(),
|
||||
base.getPitch(), base.getHeadYaw(), definition.height(), definition.width(), definition.offset(), null, null);
|
||||
base.getPitch(), base.getHeadYaw(), definition.height(), definition.width(), definition.offset(), null);
|
||||
}
|
||||
|
||||
public void callServerSpawnEvent() {
|
||||
// TODO we should actually test this?
|
||||
public EntitySpawnContext(GeyserSession session, EntityTypeDefinition<?> definition, int javaId, UUID uuid, BedrockEntityDefinition bedrockEntityDefinition, Vector3f position,
|
||||
Vector3f motion, float yaw, float pitch, float headYaw, float height, float width, float offset, @Nullable Long geyserId) {
|
||||
this.session = session;
|
||||
this.entityTypeDefinition = definition;
|
||||
this.javaId = javaId;
|
||||
this.uuid = uuid;
|
||||
this.bedrockEntityDefinition = bedrockEntityDefinition;
|
||||
this.position = position;
|
||||
this.motion = motion;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.headYaw = headYaw;
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.offset = offset;
|
||||
this.geyserId = geyserId;
|
||||
this.consumers = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if an entity should be spawned
|
||||
*/
|
||||
public boolean callServerSpawnEvent() {
|
||||
// TODO add tests
|
||||
if (EnvironmentUtils.IS_UNIT_TESTING) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
GeyserImpl.getInstance().getEventBus().fire(new ServerSpawnEntityEvent(session) {
|
||||
@@ -158,9 +178,11 @@ public class EntitySpawnContext {
|
||||
consumers.add(consumer);
|
||||
}
|
||||
});
|
||||
|
||||
return bedrockEntityDefinition != null;
|
||||
}
|
||||
|
||||
public void callParrotEvent(PlayerEntity player, int variant, boolean right) {
|
||||
public boolean callParrotEvent(PlayerEntity player, int variant, boolean right) {
|
||||
GeyserImpl.getInstance().eventBus().fire(new ServerAttachParrotsEvent(session) {
|
||||
@Override
|
||||
public GeyserPlayerEntity player() {
|
||||
@@ -213,5 +235,7 @@ public class EntitySpawnContext {
|
||||
consumers.add(consumer);
|
||||
}
|
||||
});
|
||||
|
||||
return bedrockEntityDefinition != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class DisplayBaseEntity extends Entity {
|
||||
// On JE: custom name does not override text display.
|
||||
}
|
||||
|
||||
public void setTranslation(EntityMetadata<Vector3f, ?> translationMeta){
|
||||
public void setTranslation(EntityMetadata<Vector3f, ?> translationMeta) {
|
||||
this.baseTranslation = translationMeta.getValue();
|
||||
if (this.baseTranslation == null) {
|
||||
return;
|
||||
|
||||
@@ -108,6 +108,9 @@ public class Entity implements GeyserEntity {
|
||||
@Setter(AccessLevel.NONE)
|
||||
protected String nametag = "";
|
||||
|
||||
/**
|
||||
* The entity position, WITH vertical offset
|
||||
*/
|
||||
protected Vector3f position;
|
||||
protected Vector3f motion;
|
||||
|
||||
@@ -194,21 +197,18 @@ public class Entity implements GeyserEntity {
|
||||
this.valid = false;
|
||||
this.propertyManager = bedrockDefinition.registeredProperties().isEmpty() ? null : new GeyserEntityPropertyManager(bedrockDefinition.registeredProperties());
|
||||
|
||||
setPosition(context.position());
|
||||
setPosition(context.position().up(offset));
|
||||
setAirSupply(getMaxAir());
|
||||
|
||||
initializeMetadata();
|
||||
|
||||
// Allow API users to do things pre-spawn
|
||||
if (context.consumers() != null) {
|
||||
context.consumers().forEach(consumer -> consumer.accept(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on entity spawn. Used to populate the entity metadata and flags with default values.
|
||||
*/
|
||||
protected void initializeMetadata() {
|
||||
dirtyMetadata.put(EntityDataTypes.WIDTH, width);
|
||||
dirtyMetadata.put(EntityDataTypes.HEIGHT, height);
|
||||
dirtyMetadata.put(EntityDataTypes.SCALE, 1f);
|
||||
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) 0);
|
||||
dirtyMetadata.put(EntityDataTypes.AIR_SUPPLY_MAX, getMaxAir());
|
||||
@@ -699,8 +699,6 @@ public class Entity implements GeyserEntity {
|
||||
return this.valid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the suggestion that the client currently has on their screen for this entity (for example, "Feed" or "Ride")
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.entity.type.living.monster;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.entity.BedrockEntityDefinitions;
|
||||
import org.geysermc.geyser.entity.VanillaEntities;
|
||||
@@ -37,11 +36,13 @@ public class EnderDragonPartEntity extends Entity {
|
||||
|
||||
public EnderDragonPartEntity(GeyserSession session, int entityId, long geyserId, float width, float height) {
|
||||
super(dragonPartSpawnContext(session, entityId, geyserId, width, height));
|
||||
}
|
||||
|
||||
dirtyMetadata.put(EntityDataTypes.WIDTH, width);
|
||||
dirtyMetadata.put(EntityDataTypes.HEIGHT, height);
|
||||
@Override
|
||||
protected void initializeMetadata() {
|
||||
setFlag(EntityFlag.INVISIBLE, true);
|
||||
setFlag(EntityFlag.FIRE_IMMUNE, true);
|
||||
super.initializeMetadata();
|
||||
}
|
||||
|
||||
public static EntitySpawnContext dragonPartSpawnContext(GeyserSession session, int entityId, long geyserId, float width, float height) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
|
||||
import org.geysermc.geyser.entity.VanillaEntities;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
@@ -161,10 +162,16 @@ public class PlayerEntity extends AvatarEntity implements GeyserPlayerEntity {
|
||||
}
|
||||
// The parrot is a separate entity in Bedrock, but part of the player entity in Java
|
||||
EntitySpawnContext context = EntitySpawnContext.inherited(session, VanillaEntities.PARROT, this, position);
|
||||
context.callParrotEvent(this, variant.getAsInt(), !isLeft);
|
||||
if (context.callParrotEvent(this, variant.getAsInt(), !isLeft)) {
|
||||
GeyserImpl.getInstance().getLogger().debug("TODO");
|
||||
return;
|
||||
}
|
||||
ParrotEntity parrot = new ParrotEntity(context);
|
||||
parrot.spawnEntity();
|
||||
parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, variant.getAsInt());
|
||||
if (context.consumers() != null) {
|
||||
context.consumers().forEach(consumer -> consumer.accept(parrot));
|
||||
}
|
||||
parrot.spawnEntity();
|
||||
// Different position whether the parrot is left or right
|
||||
float offset = isLeft ? 0.4f : -0.4f;
|
||||
parrot.getDirtyMetadata().put(EntityDataTypes.SEAT_OFFSET, Vector3f.from(offset, -0.22, -0.1));
|
||||
|
||||
@@ -2403,7 +2403,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestHandSwap() {
|
||||
public void switchHands() {
|
||||
requestOffhandSwap();
|
||||
}
|
||||
|
||||
|
||||
@@ -101,8 +101,7 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
|
||||
return;
|
||||
}
|
||||
|
||||
context.callServerSpawnEvent();
|
||||
if (context.bedrockEntityDefinition() == null) {
|
||||
if (!context.callServerSpawnEvent()) {
|
||||
// TODO log warn
|
||||
return;
|
||||
}
|
||||
@@ -136,6 +135,11 @@ public class JavaAddEntityTranslator extends PacketTranslator<ClientboundAddEnti
|
||||
}
|
||||
}
|
||||
|
||||
// Call pre-spawn consumer
|
||||
if (context.consumers() != null) {
|
||||
context.consumers().forEach(consumer -> consumer.accept(entity));
|
||||
}
|
||||
|
||||
session.getEntityCache().spawnEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.cloudburstmc.protocol.bedrock.data.GameType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.entity.custom.CustomEntityDefinition;
|
||||
import org.geysermc.geyser.api.entity.custom.CustomJavaEntityType;
|
||||
import org.geysermc.geyser.api.entity.definition.GeyserEntityDefinition;
|
||||
import org.geysermc.geyser.api.entity.property.GeyserEntityProperty;
|
||||
@@ -430,13 +431,17 @@ public final class EntityUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(@NonNull GeyserEntityDefinition entityDefinition) {
|
||||
public Collection<CustomEntityDefinition> customEntities() {
|
||||
return Collections.unmodifiableCollection(customEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(@NonNull CustomEntityDefinition entityDefinition) {
|
||||
Objects.requireNonNull(entityDefinition);
|
||||
if (!(entityDefinition instanceof BedrockEntityDefinition bedrockEntityDefinition)) {
|
||||
throw new IllegalArgumentException("EntityDefinition must not be a custom implementation of BedrockEntityDefinition! Found " + entityDefinition.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
if (Registries.BEDROCK_ENTITY_DEFINITIONS.get().containsValue(bedrockEntityDefinition)) {
|
||||
if (entityDefinition.registered()) {
|
||||
throw new IllegalStateException("Duplicate custom entity definition: " + entityDefinition);
|
||||
}
|
||||
if (bedrockEntityDefinition.vanilla()) {
|
||||
|
||||
Reference in New Issue
Block a user