diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index 265c6b1f7..e3f4e685d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -221,6 +221,7 @@ public final class BlockRegistryPopulator { GeyserBedrockBlock airDefinition = null; BlockDefinition commandBlockDefinition = null; + BlockDefinition mobSpawnerBlockDefinition = null; BlockDefinition waterDefinition = null; BlockDefinition movingBlockDefinition = null; Iterator> blocksIterator = BLOCKS_JSON.fields(); @@ -269,6 +270,7 @@ public final class BlockRegistryPopulator { case "minecraft:air" -> airDefinition = bedrockDefinition; case "minecraft:water[level=0]" -> waterDefinition = bedrockDefinition; case "minecraft:command_block[conditional=false,facing=north]" -> commandBlockDefinition = bedrockDefinition; + case "minecraft:spawner" -> mobSpawnerBlockDefinition = bedrockDefinition; case "minecraft:moving_piston[facing=north,type=normal]" -> movingBlockDefinition = bedrockDefinition; } @@ -298,9 +300,13 @@ public final class BlockRegistryPopulator { if (commandBlockDefinition == null) { throw new AssertionError("Unable to find command block in palette"); } - builder.commandBlock(commandBlockDefinition); + if (mobSpawnerBlockDefinition == null) { + throw new AssertionError("Unable to find mob spawner block in palette"); + } + builder.mobSpawnerBlock(mobSpawnerBlockDefinition); + if (waterDefinition == null) { throw new AssertionError("Unable to find water in palette"); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index 80be3fbce..3d06cecac 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -54,6 +54,7 @@ public class BlockMappings implements DefinitionRegistry { int[] remappedVanillaIds; BlockDefinition commandBlock; + BlockDefinition mobSpawnerBlock; Map itemFrames; Map flowerPotBlocks; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index b89a2a547..7566e0d90 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -30,6 +30,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.BlockEntityUtils; /** @@ -41,7 +42,7 @@ public abstract class BlockEntityTranslator { public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); - public NbtMap getBlockEntityTag(BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(type), x, y, z); translateTag(tagBuilder, tag, blockState); return tagBuilder.build(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index d1af70d8d..0aa8af279 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -29,12 +29,44 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.GeyserSession; @BlockEntity(type = BlockEntityType.MOB_SPAWNER) public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { + + @Override + public NbtMap getBlockEntityTag(GeyserSession session, BlockEntityType type, int x, int y, int z, CompoundTag tag, int blockState) { + // Sending an empty EntityIdentifier to empty the spawner is ignored by the client, so we send a whole new spawner! + // Fixes https://github.com/GeyserMC/Geyser/issues/4214 + CompoundTag spawnData = tag.get("SpawnData"); + if (spawnData != null) { + CompoundTag entityTag = spawnData.get("entity"); + if (entityTag.isEmpty()) { + Vector3i position = Vector3i.from(x, y, z); + // Set to air and back to reset the spawner - "just" updating the spawner doesn't work + UpdateBlockPacket emptyBlockPacket = new UpdateBlockPacket(); + emptyBlockPacket.setDataLayer(0); + emptyBlockPacket.setBlockPosition(position); + emptyBlockPacket.setDefinition(session.getBlockMappings().getBedrockAir()); + session.sendUpstreamPacket(emptyBlockPacket); + + UpdateBlockPacket spawnerBlockPacket = new UpdateBlockPacket(); + spawnerBlockPacket.setDataLayer(0); + spawnerBlockPacket.setBlockPosition(position); + spawnerBlockPacket.setDefinition(session.getBlockMappings().getMobSpawnerBlock()); + session.sendUpstreamPacket(spawnerBlockPacket); + } + } + + return super.getBlockEntityTag(session, type, x, y, z, tag, blockState); + } + @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { Tag current; @@ -69,8 +101,8 @@ public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { CompoundTag spawnData = tag.get("SpawnData"); if (spawnData != null) { - StringTag idTag = ((CompoundTag) spawnData.get("entity")).get("id"); - if (idTag != null) { + CompoundTag entityTag = spawnData.get("entity"); + if (entityTag.get("id") instanceof StringTag idTag) { // As of 1.19.3, spawners can be empty String entityId = idTag.getValue(); builder.put("EntityIdentifier", entityId); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java index b86882d84..c67a6dee4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEntityDataTranslator.java @@ -62,7 +62,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator