Clear mob spawners if the Java server so requests (#4232)

* Clear mob spawners if the Java server so requests

* Empty spawners by replacing the spawner block with a new one instead of adding an invalid identifier to them.
Unfortunately, sending one UpdateBlockPacket that replaces the spawner does not work, we need to set the spawner to air first. Cool. But at least we don't summon particles for all empty spawners now

* store position vector (address review by @konicai)

* remove empty line
This commit is contained in:
chris 2023-12-01 10:27:42 +01:00 committed by GitHub
parent 0f50a3cbe6
commit 11945db7a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 7 deletions

View File

@ -221,6 +221,7 @@ public final class BlockRegistryPopulator {
GeyserBedrockBlock airDefinition = null;
BlockDefinition commandBlockDefinition = null;
BlockDefinition mobSpawnerBlockDefinition = null;
BlockDefinition waterDefinition = null;
BlockDefinition movingBlockDefinition = null;
Iterator<Map.Entry<String, JsonNode>> 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");
}

View File

@ -54,6 +54,7 @@ public class BlockMappings implements DefinitionRegistry<GeyserBedrockBlock> {
int[] remappedVanillaIds;
BlockDefinition commandBlock;
BlockDefinition mobSpawnerBlock;
Map<NbtMap, BlockDefinition> itemFrames;
Map<String, NbtMap> flowerPotBlocks;

View File

@ -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();

View File

@ -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);

View File

@ -62,7 +62,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
}
Vector3i position = packet.getPosition();
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(type, position.getX(), position.getY(), position.getZ(),
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(session, type, position.getX(), position.getY(), position.getZ(),
packet.getNbt(), blockState), packet.getPosition());
// Check for custom skulls.
boolean hasCustomHeadBlock = false;
@ -80,7 +80,7 @@ public class JavaBlockEntityDataTranslator extends PacketTranslator<ClientboundB
}
}
if (!hasCustomHeadBlock) {
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(type, position.getX(), position.getY(), position.getZ(),
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(session, type, position.getX(), position.getY(), position.getZ(),
packet.getNbt(), blockState), packet.getPosition());
}

View File

@ -421,7 +421,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
}
BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(type);
bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState));
bedrockBlockEntities.add(blockEntityTranslator.getBlockEntityTag(session, type, x + chunkBlockX, y, z + chunkBlockZ, tag, blockState));
// Check for custom skulls
if (session.getPreferencesCache().showCustomSkulls() && type == BlockEntityType.SKULL && tag != null && tag.contains("SkullOwner")) {