From 2706536c7ded606a9a597fd5792892535e7e4045 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 7 May 2022 10:11:45 -0500 Subject: [PATCH] Revert "Remove entity work from main extension branch for now" This reverts commit fbaa6c1f5f5bd0752f633c722e8c316dd98e62d7. --- .../geyser/api/entity/EntityIdentifier.java | 97 +++++++++++++++++++ .../api/event/entity/DefineEntitiesEvent.java | 46 +++++++++ .../geyser/entity/GeyserEntityIdentifier.java | 85 ++++++++++++++++ .../provider/GeyserBuilderProvider.java | 3 + .../geyser/session/GeyserSession.java | 30 +++++- 5 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/entity/EntityIdentifier.java create mode 100644 api/geyser/src/main/java/org/geysermc/geyser/api/event/entity/DefineEntitiesEvent.java create mode 100644 core/src/main/java/org/geysermc/geyser/entity/GeyserEntityIdentifier.java diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/entity/EntityIdentifier.java b/api/geyser/src/main/java/org/geysermc/geyser/api/entity/EntityIdentifier.java new file mode 100644 index 000000000..1c82d3a63 --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/entity/EntityIdentifier.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019-2022 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; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.GeyserApi; + +/** + * Represents the data sent over to a client regarding + * an entity's identifier. + */ +public interface EntityIdentifier { + + /** + * Gets whether this entity has a spawn egg or not. + * + * @return whether this entity has a spawn egg or not + */ + boolean hasSpawnEgg(); + + /** + * Gets the entity's identifier that is sent to the client. + * + * @return the entity's identifier that is sent to the client. + */ + @NonNull + String identifier(); + + /** + * Gets whether the entity is summonable or not. + * + * @return whether the entity is summonable or not + */ + boolean isSummonable(); + + @NonNull + static Builder builder() { + return GeyserApi.api().providerManager().builderProvider().provideBuilder(Builder.class); + } + + interface Builder { + + /** + * Sets whether the entity has a spawn egg or not. + * + * @param spawnEgg whether the entity has a spawn egg or not + * @return the builder + */ + Builder spawnEgg(boolean spawnEgg); + + /** + * Sets the entity's identifier that is sent to the client. + * + * @param identifier the entity's identifier that is sent to the client + * @return the builder + */ + Builder identifier(String identifier); + + /** + * Sets whether the entity is summonable or not. + * + * @param summonable whether the entity is summonable or not + * @return the builder + */ + Builder summonable(boolean summonable); + + /** + * Builds the entity identifier. + * + * @return the entity identifier + */ + EntityIdentifier build(); + } +} diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/event/entity/DefineEntitiesEvent.java b/api/geyser/src/main/java/org/geysermc/geyser/api/event/entity/DefineEntitiesEvent.java new file mode 100644 index 000000000..9bdae3dba --- /dev/null +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/event/entity/DefineEntitiesEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019-2022 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.entity; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.EntityIdentifier; +import org.geysermc.geyser.api.event.Event; + +import java.util.List; + +/** + * Called when Geyser sends a list of available entities to the + * Bedrock client. This will typically contain all the available + * entities within vanilla, but can be modified to include any custom + * entity defined through a resource pack. + * + * @param connection the {@link GeyserConnection} that is receiving the entities + * @param identifiers a mutable list of all the {@link EntityIdentifier}s + * sent to the client + */ +public record DefineEntitiesEvent(@NonNull GeyserConnection connection, @NonNull List identifiers) implements Event { +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityIdentifier.java b/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityIdentifier.java new file mode 100644 index 000000000..9a4a5e5d5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserEntityIdentifier.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019-2022 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 com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.api.entity.EntityIdentifier; + +import java.util.concurrent.atomic.AtomicInteger; + +public record GeyserEntityIdentifier(NbtMap nbt) implements EntityIdentifier { + private static final AtomicInteger RUNTIME_ID_ALLOCATORS = new AtomicInteger(100000); + + @Override + public boolean hasSpawnEgg() { + return this.nbt.getBoolean("hasspawnegg"); + } + + @NonNull + @Override + public String identifier() { + return this.nbt.getString("id"); + } + + @Override + public boolean isSummonable() { + return this.nbt.getBoolean("summonable"); + } + + public static class EntityIdentifierBuilder implements EntityIdentifier.Builder { + private final NbtMapBuilder nbt = NbtMap.builder(); + + @Override + public Builder spawnEgg(boolean spawnEgg) { + this.nbt.putBoolean("hasspawnegg", spawnEgg); + return this; + } + + @Override + public Builder identifier(String identifier) { + this.nbt.putString("id", identifier); + return this; + } + + @Override + public Builder summonable(boolean summonable) { + this.nbt.putBoolean("summonable", summonable); + return this; + } + + @Override + public EntityIdentifier build() { + // Vanilla registry information + this.nbt.putString("bid", ""); + this.nbt.putInt("rid", RUNTIME_ID_ALLOCATORS.getAndIncrement()); + this.nbt.putBoolean("experimental", false); + + return new GeyserEntityIdentifier(this.nbt.build()); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/provider/GeyserBuilderProvider.java b/core/src/main/java/org/geysermc/geyser/registry/provider/GeyserBuilderProvider.java index e144fcd4f..57789ae55 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/provider/GeyserBuilderProvider.java +++ b/core/src/main/java/org/geysermc/geyser/registry/provider/GeyserBuilderProvider.java @@ -29,8 +29,10 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.command.CommandSource; +import org.geysermc.geyser.api.entity.EntityIdentifier; import org.geysermc.geyser.api.provider.BuilderProvider; import org.geysermc.geyser.command.GeyserCommandManager; +import org.geysermc.geyser.entity.GeyserEntityIdentifier; import org.geysermc.geyser.registry.ProviderRegistries; import org.geysermc.geyser.registry.SimpleMappedRegistry; @@ -46,6 +48,7 @@ public class GeyserBuilderProvider extends AbstractProvider implements BuilderPr @Override public void registerProviders(Map, ProviderSupplier> providers) { providers.put(Command.Builder.class, args -> new GeyserCommandManager.CommandBuilder<>((Class) args[0])); + providers.put(EntityIdentifier.Builder.class, args -> new GeyserEntityIdentifier.EntityIdentifierBuilder()); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index bf0360e1d..8e8bbd8fc 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -91,9 +91,12 @@ import org.geysermc.floodgate.util.BedrockData; import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.connection.GeyserConnection; +import org.geysermc.geyser.api.entity.EntityIdentifier; +import org.geysermc.geyser.api.event.entity.DefineEntitiesEvent; import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; +import org.geysermc.geyser.entity.GeyserEntityIdentifier; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; @@ -599,9 +602,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { biomeDefinitionListPacket.setDefinitions(Registries.BIOMES_NBT.get()); upstream.sendPacket(biomeDefinitionListPacket); - AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); - entityPacket.setIdentifiers(Registries.BEDROCK_ENTITY_IDENTIFIERS.get()); - upstream.sendPacket(entityPacket); + this.sendAvailableEntityIdentifiers(); CreativeContentPacket creativePacket = new CreativeContentPacket(); creativePacket.setContents(this.itemMappings.getCreativeItems()); @@ -631,6 +632,29 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { upstream.sendPacket(gamerulePacket); } + public void sendAvailableEntityIdentifiers() { + NbtMap nbt = Registries.BEDROCK_ENTITY_IDENTIFIERS.get(); + List idlist = nbt.getList("idlist", NbtType.COMPOUND); + List identifiers = new ArrayList<>(idlist.size()); + for (NbtMap identifier : idlist) { + identifiers.add(new GeyserEntityIdentifier(identifier)); + } + + DefineEntitiesEvent event = new DefineEntitiesEvent(this, identifiers); + this.geyser.eventBus().fire(event); + + NbtMapBuilder builder = nbt.toBuilder(); + builder.putList("idlist", NbtType.COMPOUND, event.identifiers() + .stream() + .map(identifer -> ((GeyserEntityIdentifier) identifer).nbt()) + .collect(Collectors.toList()) + ); + + AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); + entityPacket.setIdentifiers(builder.build()); + upstream.sendPacket(entityPacket); + } + public void authenticate(String username) { authenticate(username, ""); }