From 7d6bdca55cc15f5cafce83457821d589a7a37c1f Mon Sep 17 00:00:00 2001 From: Nicklas Matzulla Date: Sat, 6 Sep 2025 17:20:26 +0200 Subject: [PATCH 1/5] Map chickens to playunlimited entity --- .../geysermc/geyser/entity/EntityDefinitions.java | 2 ++ .../org/geysermc/geyser/registry/Registries.java | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index 960369de746..b7ad104bbe5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -973,10 +973,12 @@ public final class EntityDefinitions { .build(); CHICKEN = EntityDefinition.inherited(ChickenEntity::new, ageableEntityBase) .type(EntityType.CHICKEN) + .identifier("playunlimited:playunlimited") .height(0.7f).width(0.4f) .properties(VanillaEntityProperties.CLIMATE_VARIANT) .addTranslator(MetadataTypes.CHICKEN_VARIANT, ChickenEntity::setVariant) .build(); + Registries.JAVA_ENTITY_IDENTIFIERS.get().put("playunlimited:playunlimited", CHICKEN); COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase) .type(EntityType.COW) .height(1.4f).width(0.9f) diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index d2c0e26b250..c0d3e1fe969 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -31,6 +31,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.biome.BiomeDefinitions; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; @@ -71,6 +72,7 @@ import java.util.EnumMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -206,6 +208,17 @@ public static void load() { // (by using the Items or Blocks class, which loads all the blocks) BEDROCK_ENTITY_IDENTIFIERS.load(); + // Add custom entity identifier for playunlimited + NbtMap identifiers = BEDROCK_ENTITY_IDENTIFIERS.get(); + List idList = new ArrayList<>(identifiers.getList("idlist", NbtType.COMPOUND)); + idList.add(NbtMap.builder() + .putString("id", "playunlimited:playunlimited") + .putShort("bid", (short) 0) + .putInt("rid", 0) + .putBoolean("summonable", true) + .putBoolean("hasSpawnEgg", false) + .build()); + BEDROCK_ENTITY_IDENTIFIERS.set(NbtMap.builder().putList("idlist", NbtType.COMPOUND, idList).build()); BIOMES_NBT.load(); BIOMES.load(); BIOME_IDENTIFIERS.load(); From db9020ce81a9258ef927869a428d2ae83fed0e16 Mon Sep 17 00:00:00 2001 From: Nicklas Matzulla Date: Sat, 6 Sep 2025 17:38:03 +0200 Subject: [PATCH 2/5] Load .mcaddon packs --- .../geysermc/geyser/registry/loader/ResourcePackLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java index 71aaa948cee..cedb01b0917 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java @@ -82,7 +82,7 @@ public class ResourcePackLoader implements RegistryLoader load(Path directory) { */ public static GeyserResourcePack.Builder readPack(Path path) throws IllegalArgumentException { if (!PACK_MATCHER.matches(path)) { - throw new IllegalArgumentException("Resource pack " + path.getFileName() + " must be a .zip or .mcpack file!"); + throw new IllegalArgumentException("Resource pack " + path.getFileName() + " must be a .zip, .mcpack or .mcaddon file!"); } ResourcePackManifest manifest = readManifest(path, path.getFileName().toString()); From 0ef30bbcd2e43818aad5ead8c03ba67847ea5afc Mon Sep 17 00:00:00 2001 From: Nicklas Matzulla Date: Sat, 6 Sep 2025 17:52:41 +0200 Subject: [PATCH 3/5] Assign unique runtime ID for PlayUnlimited entity --- .../src/main/java/org/geysermc/geyser/registry/Registries.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index c0d3e1fe969..5d89f49e1a2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -211,10 +211,11 @@ public static void load() { // Add custom entity identifier for playunlimited NbtMap identifiers = BEDROCK_ENTITY_IDENTIFIERS.get(); List idList = new ArrayList<>(identifiers.getList("idlist", NbtType.COMPOUND)); + int nextRid = idList.stream().mapToInt(map -> map.getInt("rid")).max().orElse(-1) + 1; idList.add(NbtMap.builder() .putString("id", "playunlimited:playunlimited") .putShort("bid", (short) 0) - .putInt("rid", 0) + .putInt("rid", nextRid) .putBoolean("summonable", true) .putBoolean("hasSpawnEgg", false) .build()); From ffefafb1dd2602e227a5ba47e249ad9a3fd63832 Mon Sep 17 00:00:00 2001 From: Nicklas Matzulla Date: Sat, 6 Sep 2025 18:03:29 +0200 Subject: [PATCH 4/5] Advertise and map custom core_rings entity --- .../geysermc/geyser/entity/EntityDefinitions.java | 5 +++++ .../geyser/entity/type/living/ArmorStandEntity.java | 12 ++++++++++++ .../org/geysermc/geyser/registry/Registries.java | 9 ++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index b7ad104bbe5..20028ba9ffa 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -181,6 +181,7 @@ public final class EntityDefinitions { public static final EntityDefinition CHERRY_CHEST_BOAT; public static final EntityDefinition CHEST_MINECART; public static final EntityDefinition CHICKEN; + public static final EntityDefinition CORE_RINGS; public static final EntityDefinition COD; public static final EntityDefinition COMMAND_BLOCK_MINECART; public static final EntityDefinition COW; @@ -651,6 +652,10 @@ public final class EntityDefinitions { .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setLeftLegRotation) .addTranslator(MetadataTypes.ROTATIONS, ArmorStandEntity::setRightLegRotation) .build(); + CORE_RINGS = EntityDefinition.inherited(ArmorStandEntity::new, ARMOR_STAND) + .identifier("playunlimited:core_rings") + .build(false); + Registries.JAVA_ENTITY_IDENTIFIERS.get().put("playunlimited:core_rings", CORE_RINGS); PLAYER = EntityDefinition.inherited(null, livingEntityBase) .type(EntityType.PLAYER) .height(1.8f).width(0.6f) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index afbdcca31f7..df2b9a74fcc 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -293,6 +293,18 @@ public void setBoots(GeyserItemStack boots) { public void setHand(GeyserItemStack hand) { super.setHand(hand); updateSecondEntityStatus(true); + + if (!hand.isEmpty() && hand.asItem() == Items.GRASS_BLOCK) { + if (this.definition != EntityDefinitions.CORE_RINGS) { + despawnEntity(); + this.definition = EntityDefinitions.CORE_RINGS; + spawnEntity(); + } + } else if (this.definition == EntityDefinitions.CORE_RINGS) { + despawnEntity(); + this.definition = EntityDefinitions.ARMOR_STAND; + spawnEntity(); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 5d89f49e1a2..adea197a205 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -208,13 +208,20 @@ public static void load() { // (by using the Items or Blocks class, which loads all the blocks) BEDROCK_ENTITY_IDENTIFIERS.load(); - // Add custom entity identifier for playunlimited + // Add custom entity identifiers for PlayUnlimited entities NbtMap identifiers = BEDROCK_ENTITY_IDENTIFIERS.get(); List idList = new ArrayList<>(identifiers.getList("idlist", NbtType.COMPOUND)); int nextRid = idList.stream().mapToInt(map -> map.getInt("rid")).max().orElse(-1) + 1; idList.add(NbtMap.builder() .putString("id", "playunlimited:playunlimited") .putShort("bid", (short) 0) + .putInt("rid", nextRid++) + .putBoolean("summonable", true) + .putBoolean("hasSpawnEgg", false) + .build()); + idList.add(NbtMap.builder() + .putString("id", "playunlimited:core_rings") + .putShort("bid", (short) 0) .putInt("rid", nextRid) .putBoolean("summonable", true) .putBoolean("hasSpawnEgg", false) From e85bc1360b4a8232c2ae93f13c9027f4714ddf43 Mon Sep 17 00:00:00 2001 From: Nicklas Matzulla Date: Sat, 6 Sep 2025 18:17:21 +0200 Subject: [PATCH 5/5] Replace chicken Bedrock identifier --- .../geysermc/geyser/registry/Registries.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index adea197a205..e1d601f5849 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -212,13 +212,21 @@ public static void load() { NbtMap identifiers = BEDROCK_ENTITY_IDENTIFIERS.get(); List idList = new ArrayList<>(identifiers.getList("idlist", NbtType.COMPOUND)); int nextRid = idList.stream().mapToInt(map -> map.getInt("rid")).max().orElse(-1) + 1; - idList.add(NbtMap.builder() - .putString("id", "playunlimited:playunlimited") - .putShort("bid", (short) 0) - .putInt("rid", nextRid++) - .putBoolean("summonable", true) - .putBoolean("hasSpawnEgg", false) - .build()); + + for (int i = 0; i < idList.size(); i++) { + NbtMap map = idList.get(i); + if ("minecraft:chicken".equals(map.getString("id"))) { + idList.set(i, NbtMap.builder() + .putString("id", "playunlimited:playunlimited") + .putShort("bid", map.getShort("bid")) + .putInt("rid", map.getInt("rid")) + .putBoolean("summonable", true) + .putBoolean("hasSpawnEgg", map.getBoolean("hasSpawnEgg")) + .build()); + break; + } + } + idList.add(NbtMap.builder() .putString("id", "playunlimited:core_rings") .putShort("bid", (short) 0) @@ -226,6 +234,7 @@ public static void load() { .putBoolean("summonable", true) .putBoolean("hasSpawnEgg", false) .build()); + BEDROCK_ENTITY_IDENTIFIERS.set(NbtMap.builder().putList("idlist", NbtType.COMPOUND, idList).build()); BIOMES_NBT.load(); BIOMES.load();