forked from GeyserMC/Geyser
Block entity performance improvements (#1481)
* BlockEntity performance improvements * Use chunk cache if possible for block caching * Get new block state from ViaVersion if block entity * Add Javadoc for FlowerPotBlockEntityTranslator.isFlowerBlock * Remove debug line * Don't add all RequiresBlockState instances if cache chunks is enabled * Double chest map get optimization * Last changes Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
This commit is contained in:
parent
434a2e1500
commit
c64d57439f
28 changed files with 362 additions and 404 deletions
|
@ -43,16 +43,19 @@ import org.geysermc.connector.utils.FileUtils;
|
|||
import org.geysermc.connector.utils.GameRule;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
||||
|
||||
/**
|
||||
* The current client protocol version for ViaVersion usage.
|
||||
*/
|
||||
|
@ -99,8 +102,9 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
}
|
||||
// Only load in the biomes that are present in this version of Minecraft
|
||||
for (Biome enumBiome : Biome.values()) {
|
||||
if (biomes.has(enumBiome.toString())) {
|
||||
biomeToIdMap.put(enumBiome.ordinal(), biomes.get(enumBiome.toString()).intValue());
|
||||
JsonNode biome = biomes.get(enumBiome.toString());
|
||||
if (biome != null) {
|
||||
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
|
||||
", defaulting to 0");
|
||||
|
@ -127,30 +131,38 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
|
||||
public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
|
||||
if (isViaVersion) {
|
||||
return getLegacyBlock(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(), x, y, z, true);
|
||||
Player bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(bukkitPlayer.getUniqueId()).get(BlockStorage.class);
|
||||
return getLegacyBlock(storage, bukkitPlayer.getWorld(), x, y, z);
|
||||
} else {
|
||||
return BlockTranslator.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int getLegacyBlock(World world, int x, int y, int z, boolean isViaVersion) {
|
||||
if (isViaVersion) {
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
// Black magic that gets the old block state ID
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
||||
blockId = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData().getNewBlockId(blockId);
|
||||
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||
ProtocolVersion.v1_13.getId());
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
if (protocolList.get(i).getValue().getMappingData() == null) continue;
|
||||
blockId = protocolList.get(i).getValue().getMappingData().getNewBlockStateId(blockId);
|
||||
public static int getLegacyBlock(BlockStorage storage, World world, int x, int y, int z) {
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
// Black magic that gets the old block state ID
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
|
||||
blockId = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData().getNewBlockId(blockId);
|
||||
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||
ProtocolVersion.v1_13.getId());
|
||||
// Translate block entity differences - some information was stored in block tags and not block states
|
||||
if (storage.isWelcome(blockId)) { // No getOrDefault method
|
||||
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
|
||||
if (data != null && data.getReplacement() != -1) {
|
||||
blockId = data.getReplacement();
|
||||
}
|
||||
return blockId;
|
||||
} else {
|
||||
return BlockTranslator.AIR;
|
||||
}
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
if (mappingData != null) {
|
||||
blockId = mappingData.getNewBlockStateId(blockId);
|
||||
}
|
||||
}
|
||||
return blockId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,11 +174,13 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
return;
|
||||
}
|
||||
World world = bukkitPlayer.getWorld();
|
||||
if (this.isLegacy) {
|
||||
if (this.isLegacy) {
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(bukkitPlayer.getUniqueId()).get(BlockStorage.class);
|
||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ, true));
|
||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +190,7 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), 0);
|
||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.AIR);
|
||||
chunk.set(blockX, blockY, blockZ, id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ public class ItemFrameEntity extends Entity {
|
|||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setBlockPosition(bedrockPosition);
|
||||
// TODO 1.16.100 set to BEDROCK_AIR
|
||||
updateBlockPacket.setRuntimeId(0);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
|
@ -196,18 +197,6 @@ public class ItemFrameEntity extends Entity {
|
|||
return session.getItemFrameCache().getOrDefault(position, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the position contains an item frame.
|
||||
* Does largely the same thing as getItemFrameEntityId, but for speed purposes is implemented separately,
|
||||
* since every block destroy packet has to check for an item frame.
|
||||
* @param position position of block.
|
||||
* @param session GeyserSession.
|
||||
* @return true if position contains item frame, false if not.
|
||||
*/
|
||||
public static boolean positionContainsItemFrame(GeyserSession session, Vector3i position) {
|
||||
return session.getItemFrameCache().containsKey(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force-remove from the position-to-ID map so it doesn't cause conflicts.
|
||||
* @param session GeyserSession.
|
||||
|
|
|
@ -194,10 +194,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
session.sendUpstreamPacket(blockBreakPacket);
|
||||
}
|
||||
|
||||
if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) &&
|
||||
session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) {
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()),
|
||||
InteractAction.ATTACK, session.isSneaking());
|
||||
long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition());
|
||||
if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) {
|
||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking());
|
||||
session.sendDownstreamPacket(attackPacket);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -226,8 +226,14 @@ public class ItemRegistry {
|
|||
* @return an item entry from the given java edition identifier
|
||||
*/
|
||||
public static ItemEntry getItemEntry(String javaIdentifier) {
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values()
|
||||
.stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null));
|
||||
return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> {
|
||||
for (ItemEntry entry : ITEM_ENTRIES.values()) {
|
||||
if (entry.getJavaIdentifier().equals(key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,7 +51,6 @@ import java.util.*;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class ItemTranslator {
|
||||
|
||||
private static final Int2ObjectMap<ItemTranslator> ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>();
|
||||
private static final List<NbtItemStackTranslator> NBT_TRANSLATORS;
|
||||
|
||||
|
@ -220,7 +219,7 @@ public abstract class ItemTranslator {
|
|||
public abstract List<ItemEntry> getAppliedItems();
|
||||
|
||||
public NbtMap translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) {
|
||||
Map<String, Object> javaValue = new HashMap<>();
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
if (tag.getValue() != null && !tag.getValue().isEmpty()) {
|
||||
for (String str : tag.getValue().keySet()) {
|
||||
com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str);
|
||||
|
@ -228,11 +227,9 @@ public abstract class ItemTranslator {
|
|||
if (translatedTag == null)
|
||||
continue;
|
||||
|
||||
javaValue.put(javaTag.getName(), translatedTag);
|
||||
builder.put(javaTag.getName(), translatedTag);
|
||||
}
|
||||
}
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
javaValue.forEach(builder::put);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,20 +26,16 @@
|
|||
package org.geysermc.connector.network.translators.item.translators;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.NbtList;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.nbt.NbtType;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -49,54 +45,13 @@ import java.util.stream.Collectors;
|
|||
|
||||
@ItemRemapper
|
||||
public class BannerTranslator extends ItemTranslator {
|
||||
|
||||
private final List<ItemEntry> appliedItems;
|
||||
|
||||
public BannerTranslator() {
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
NbtMapBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.put("Patterns", convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry);
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
NbtMap nbtTag = itemData.getTag();
|
||||
if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
|
||||
List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
appliedItems = ItemRegistry.ITEM_ENTRIES.values()
|
||||
.stream()
|
||||
.filter(entry -> entry.getJavaIdentifier().endsWith("banner"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +88,6 @@ public class BannerTranslator extends ItemTranslator {
|
|||
|
||||
return NbtMap.builder()
|
||||
.putInt("Color", 15 - (int) pattern.get("Color").getValue())
|
||||
.putString("Pattern", (String) pattern.get("Pattern").getValue())
|
||||
.putString("Pattern", patternName)
|
||||
.build();
|
||||
}
|
||||
|
@ -147,8 +101,7 @@ public class BannerTranslator extends ItemTranslator {
|
|||
public static ListTag convertBannerPattern(List<NbtMap> patterns) {
|
||||
List<Tag> tagsList = new ArrayList<>();
|
||||
for (Object patternTag : patterns) {
|
||||
CompoundTag newPatternTag = getJavaBannerPattern((NbtMap) patternTag);
|
||||
tagsList.add(newPatternTag);
|
||||
tagsList.add(getJavaBannerPattern((NbtMap) patternTag));
|
||||
}
|
||||
|
||||
return new ListTag("Patterns", tagsList);
|
||||
|
@ -167,4 +120,51 @@ public class BannerTranslator extends ItemTranslator {
|
|||
|
||||
return new CompoundTag("", tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) {
|
||||
if (itemStack.getNbt() == null) {
|
||||
return super.translateToBedrock(itemStack, itemEntry);
|
||||
}
|
||||
|
||||
ItemData itemData = super.translateToBedrock(itemStack, itemEntry);
|
||||
|
||||
CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag");
|
||||
if (blockEntityTag.contains("Patterns")) {
|
||||
ListTag patterns = blockEntityTag.get("Patterns");
|
||||
|
||||
NbtMapBuilder builder = itemData.getTag().toBuilder();
|
||||
builder.put("Patterns", convertBannerPattern(patterns));
|
||||
|
||||
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build());
|
||||
}
|
||||
|
||||
return itemData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) {
|
||||
if (itemData.getTag() == null) {
|
||||
return super.translateToJava(itemData, itemEntry);
|
||||
}
|
||||
|
||||
ItemStack itemStack = super.translateToJava(itemData, itemEntry);
|
||||
|
||||
NbtMap nbtTag = itemData.getTag();
|
||||
if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) {
|
||||
List<NbtMap> patterns = nbtTag.getList("Patterns", NbtType.COMPOUND);
|
||||
|
||||
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
|
||||
blockEntityTag.put(convertBannerPattern(patterns));
|
||||
|
||||
itemStack.getNbt().put(blockEntityTag);
|
||||
}
|
||||
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemEntry> getAppliedItems() {
|
||||
return appliedItems;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,14 +45,13 @@ import org.geysermc.connector.utils.ChunkUtils;
|
|||
|
||||
@Translator(packet = ServerChunkDataPacket.class)
|
||||
public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPacket> {
|
||||
|
||||
/**
|
||||
* Determines if we should process non-full chunks
|
||||
*/
|
||||
private final boolean isCacheChunks;
|
||||
private final boolean cacheChunks;
|
||||
|
||||
public JavaChunkDataTranslator() {
|
||||
isCacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,7 +60,7 @@ public class JavaChunkDataTranslator extends PacketTranslator<ServerChunkDataPac
|
|||
ChunkUtils.updateChunkPosition(session, session.getPlayerEntity().getPosition().toInt());
|
||||
}
|
||||
|
||||
if (packet.getColumn().getBiomeData() == null && !isCacheChunks) {
|
||||
if (packet.getColumn().getBiomeData() == null && !cacheChunks) {
|
||||
// Non-full chunk without chunk caching
|
||||
session.getConnector().getLogger().debug("Not sending non-full chunk because chunk caching is off.");
|
||||
return;
|
||||
|
|
|
@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdate
|
|||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||
import org.geysermc.connector.network.translators.Translator;
|
||||
|
@ -40,6 +41,11 @@ import org.geysermc.connector.utils.ChunkUtils;
|
|||
|
||||
@Translator(packet = ServerUpdateTileEntityPacket.class)
|
||||
public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdateTileEntityPacket> {
|
||||
private final boolean cacheChunks;
|
||||
|
||||
public JavaUpdateTileEntityTranslator() {
|
||||
cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) {
|
||||
|
@ -48,16 +54,17 @@ public class JavaUpdateTileEntityTranslator extends PacketTranslator<ServerUpdat
|
|||
BlockEntityUtils.updateBlockEntity(session, null, packet.getPosition());
|
||||
return;
|
||||
}
|
||||
|
||||
BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id);
|
||||
// If not null then the BlockState is used in BlockEntityTranslator.translateTag()
|
||||
if (ChunkUtils.CACHED_BLOCK_ENTITIES.containsKey(packet.getPosition())) {
|
||||
int blockState = ChunkUtils.CACHED_BLOCK_ENTITIES.getOrDefault(packet.getPosition(), 0);
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(),
|
||||
blockState), packet.getPosition());
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.remove(packet.getPosition(), blockState);
|
||||
} else {
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), 0), packet.getPosition());
|
||||
}
|
||||
// The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies
|
||||
// between Java block states and Bedrock block entity data
|
||||
int blockState = cacheChunks ?
|
||||
// Cache chunks is enabled; use chunk cache
|
||||
session.getConnector().getWorldManager().getBlockAt(session, packet.getPosition()) :
|
||||
// Cache chunks is not enabled; use block entity cache
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(packet.getPosition());
|
||||
BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), blockState), packet.getPosition());
|
||||
|
||||
// If block entity is command block, OP permission level is appropriate, player is in creative mode and the NBT is not empty
|
||||
if (packet.getType() == UpdatedTileType.COMMAND_BLOCK && session.getOpPermissionLevel() >= 2 &&
|
||||
session.getGameMode() == GameMode.CREATIVE && packet.getNbt().size() > 5) {
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.util.Map;
|
|||
* Used for block entities if the Java block state contains Bedrock block information.
|
||||
*/
|
||||
public class BlockStateValues {
|
||||
|
||||
private static final Int2IntMap BANNER_COLORS = new Int2IntOpenHashMap();
|
||||
private static final Int2ByteMap BED_COLORS = new Int2ByteOpenHashMap();
|
||||
private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap();
|
||||
|
@ -52,7 +51,8 @@ public class BlockStateValues {
|
|||
|
||||
/**
|
||||
* Determines if the block state contains Bedrock block information
|
||||
* @param entry The String to JsonNode map used in BlockTranslator
|
||||
*
|
||||
* @param entry The String to JsonNode map used in BlockTranslator
|
||||
* @param javaBlockState the Java Block State of the block
|
||||
*/
|
||||
public static void storeBlockStateValues(Map.Entry<String, JsonNode> entry, int javaBlockState) {
|
||||
|
@ -101,7 +101,7 @@ public class BlockStateValues {
|
|||
}
|
||||
|
||||
JsonNode skullVariation = entry.getValue().get("variation");
|
||||
if(skullVariation != null) {
|
||||
if (skullVariation != null) {
|
||||
SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue());
|
||||
}
|
||||
|
||||
|
@ -124,10 +124,7 @@ public class BlockStateValues {
|
|||
* @return Banner color integer or -1 if no color
|
||||
*/
|
||||
public static int getBannerColor(int state) {
|
||||
if (BANNER_COLORS.containsKey(state)) {
|
||||
return BANNER_COLORS.get(state);
|
||||
}
|
||||
return -1;
|
||||
return BANNER_COLORS.getOrDefault(state, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,10 +135,7 @@ public class BlockStateValues {
|
|||
* @return Bed color byte or -1 if no color
|
||||
*/
|
||||
public static byte getBedColor(int state) {
|
||||
if (BED_COLORS.containsKey(state)) {
|
||||
return BED_COLORS.get(state);
|
||||
}
|
||||
return -1;
|
||||
return BED_COLORS.getOrDefault(state, (byte) -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,6 +151,7 @@ public class BlockStateValues {
|
|||
/**
|
||||
* All double chest values are part of the block state in Java and part of the block entity tag in Bedrock.
|
||||
* This gives the DoubleChestValue that can be calculated into the final tag.
|
||||
*
|
||||
* @return The map of all DoubleChestValues.
|
||||
*/
|
||||
public static Int2ObjectMap<DoubleChestValue> getDoubleChestValues() {
|
||||
|
@ -165,6 +160,7 @@ public class BlockStateValues {
|
|||
|
||||
/**
|
||||
* Get the Int2ObjectMap of flower pot block states to containing plant
|
||||
*
|
||||
* @return Int2ObjectMap of flower pot values
|
||||
*/
|
||||
public static Int2ObjectMap<String> getFlowerPotValues() {
|
||||
|
@ -173,6 +169,7 @@ public class BlockStateValues {
|
|||
|
||||
/**
|
||||
* Get the map of contained flower pot plants to Bedrock CompoundTag
|
||||
*
|
||||
* @return Map of flower pot blocks.
|
||||
*/
|
||||
public static Map<String, NbtMap> getFlowerPotBlocks() {
|
||||
|
@ -182,18 +179,17 @@ public class BlockStateValues {
|
|||
/**
|
||||
* The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock.
|
||||
* This gives an integer pitch that Bedrock can use.
|
||||
*
|
||||
* @param state BlockState of the block
|
||||
* @return note block note integer or -1 if not present
|
||||
*/
|
||||
public static int getNoteblockPitch(int state) {
|
||||
if (NOTEBLOCK_PITCHES.containsKey(state)) {
|
||||
return NOTEBLOCK_PITCHES.get(state);
|
||||
}
|
||||
return -1;
|
||||
return NOTEBLOCK_PITCHES.getOrDefault(state, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Int2BooleanMap showing if a piston block state is extended or not.
|
||||
*
|
||||
* @return the Int2BooleanMap of piston extensions.
|
||||
*/
|
||||
public static Int2BooleanMap getPistonValues() {
|
||||
|
@ -212,10 +208,7 @@ public class BlockStateValues {
|
|||
* @return Skull variant byte or -1 if no variant
|
||||
*/
|
||||
public static byte getSkullVariant(int state) {
|
||||
if (SKULL_VARIANTS.containsKey(state)) {
|
||||
return SKULL_VARIANTS.get(state);
|
||||
}
|
||||
return -1;
|
||||
return SKULL_VARIANTS.getOrDefault(state, (byte) -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,10 +219,7 @@ public class BlockStateValues {
|
|||
* @return Skull rotation value or -1 if no value
|
||||
*/
|
||||
public static byte getSkullRotation(int state) {
|
||||
if (SKULL_ROTATIONS.containsKey(state)) {
|
||||
return SKULL_ROTATIONS.get(state);
|
||||
}
|
||||
return -1;
|
||||
return SKULL_ROTATIONS.getOrDefault(state, (byte) -1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -241,9 +231,6 @@ public class BlockStateValues {
|
|||
* @return Shulker direction value or -1 if no value
|
||||
*/
|
||||
public static byte getShulkerBoxDirection(int state) {
|
||||
if (SHULKERBOX_DIRECTIONS.containsKey(state)) {
|
||||
return SHULKERBOX_DIRECTIONS.get(state);
|
||||
}
|
||||
return -1;
|
||||
return SHULKERBOX_DIRECTIONS.getOrDefault(state, (byte) -1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,39 +27,31 @@ package org.geysermc.connector.network.translators.world.block.entity;
|
|||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.network.translators.item.translators.BannerTranslator;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "Banner", regex = "banner")
|
||||
public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getBannerColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
int bannerColor = BlockStateValues.getBannerColor(blockState);
|
||||
if (bannerColor != -1) {
|
||||
tags.put("Base", 15 - bannerColor);
|
||||
builder.put("Base", 15 - bannerColor);
|
||||
}
|
||||
|
||||
if (tag.contains("Patterns")) {
|
||||
ListTag patterns = tag.get("Patterns");
|
||||
tags.put("Patterns", BannerTranslator.convertBannerPattern(patterns));
|
||||
builder.put("Patterns", BannerTranslator.convertBannerPattern(patterns));
|
||||
}
|
||||
|
||||
if (tag.contains("CustomName")) {
|
||||
tags.put("CustomName", tag.get("CustomName").getValue());
|
||||
builder.put("CustomName", tag.get("CustomName").getValue());
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,27 +26,23 @@
|
|||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "Bed", regex = "bed")
|
||||
public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getBedColor(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
byte bedcolor = BlockStateValues.getBedColor(blockState);
|
||||
// Just in case...
|
||||
if (bedcolor == -1) bedcolor = 0;
|
||||
tags.put("color", bedcolor);
|
||||
return tags;
|
||||
if (bedcolor == -1) {
|
||||
bedcolor = 0;
|
||||
}
|
||||
builder.put("color", bedcolor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
* Implemented only if a block is a block entity in Bedrock and not Java Edition.
|
||||
*/
|
||||
public interface BedrockOnlyBlockEntity {
|
||||
|
||||
/**
|
||||
* Update the block on Bedrock Edition.
|
||||
* @param session GeyserSession.
|
||||
|
@ -49,7 +48,7 @@ public interface BedrockOnlyBlockEntity {
|
|||
* @return Bedrock tag, or null if not a Bedrock-only Block Entity
|
||||
*/
|
||||
static NbtMap getTag(Vector3i position, int blockState) {
|
||||
if (new FlowerPotBlockEntityTranslator().isBlock(blockState)) {
|
||||
if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) {
|
||||
return FlowerPotBlockEntityTranslator.getTag(blockState, position);
|
||||
} else if (PistonBlockEntityTranslator.isBlock(blockState)) {
|
||||
return PistonBlockEntityTranslator.getTag(blockState, position);
|
||||
|
|
|
@ -41,10 +41,16 @@ import org.reflections.Reflections;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The class that all block entities (on both Java and Bedrock) should translate with
|
||||
*/
|
||||
public abstract class BlockEntityTranslator {
|
||||
|
||||
public static final Map<String, BlockEntityTranslator> BLOCK_ENTITY_TRANSLATORS = new HashMap<>();
|
||||
public static ObjectArrayList<RequiresBlockState> REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>();
|
||||
/**
|
||||
* A list of all block entities that require the Java block state in order to fill out their block entity information.
|
||||
* This list will be smaller with cache chunks on as we don't need to double-cache data
|
||||
*/
|
||||
public static final ObjectArrayList<RequiresBlockState> REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>();
|
||||
|
||||
/**
|
||||
* Contains a list of irregular block entity name translations that can't be fit into the regex
|
||||
|
@ -78,27 +84,33 @@ public abstract class BlockEntityTranslator {
|
|||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_entity.failed", clazz.getCanonicalName()));
|
||||
}
|
||||
}
|
||||
boolean cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks();
|
||||
for (Class<?> clazz : ref.getSubTypesOf(RequiresBlockState.class)) {
|
||||
GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName());
|
||||
|
||||
try {
|
||||
REQUIRES_BLOCK_STATE_LIST.add((RequiresBlockState) clazz.newInstance());
|
||||
RequiresBlockState requiresBlockState = (RequiresBlockState) clazz.newInstance();
|
||||
if (cacheChunks && !(requiresBlockState instanceof BedrockOnlyBlockEntity)) {
|
||||
// Not needed to put this one in the map; cache chunks takes care of that for us
|
||||
GeyserConnector.getInstance().getLogger().debug("Not adding because cache chunks is enabled.");
|
||||
continue;
|
||||
}
|
||||
REQUIRES_BLOCK_STATE_LIST.add(requiresBlockState);
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_state.failed", clazz.getCanonicalName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Map<String, Object> translateTag(CompoundTag tag, int blockState);
|
||||
public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState);
|
||||
|
||||
public NbtMap getBlockEntityTag(String id, CompoundTag tag, int blockState) {
|
||||
int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue()));
|
||||
int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue()));
|
||||
int z = Integer.parseInt(String.valueOf(tag.getValue().get("z").getValue()));
|
||||
int x = ((IntTag) tag.getValue().get("x")).getValue();
|
||||
int y = ((IntTag) tag.getValue().get("y")).getValue();
|
||||
int z = ((IntTag) tag.getValue().get("z")).getValue();
|
||||
|
||||
NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder();
|
||||
Map<String, Object> translatedTags = translateTag(tag, blockState);
|
||||
translatedTags.forEach(tagBuilder::put);
|
||||
translateTag(tagBuilder, tag, blockState);
|
||||
return tagBuilder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,22 +32,16 @@ import com.nukkitx.nbt.NbtMapBuilder;
|
|||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "Campfire", regex = "campfire")
|
||||
public class CampfireBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
ListTag items = tag.get("Items");
|
||||
int i = 1;
|
||||
for (com.github.steveice10.opennbt.tag.builtin.Tag itemTag : items.getValue()) {
|
||||
tags.put("Item" + i, getItem((CompoundTag) itemTag));
|
||||
builder.put("Item" + i, getItem((CompoundTag) itemTag));
|
||||
i++;
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
protected NbtMap getItem(CompoundTag tag) {
|
||||
|
|
|
@ -26,38 +26,33 @@
|
|||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "CommandBlock", regex = "command_block")
|
||||
public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
if (tag.size() < 5) {
|
||||
return map; // These values aren't here
|
||||
return; // These values aren't here
|
||||
}
|
||||
// Java infers from the block state, but Bedrock needs it in the tag
|
||||
map.put("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0));
|
||||
builder.put("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0));
|
||||
// Java and Bedrock values
|
||||
map.put("conditionMet", ((ByteTag) tag.get("conditionMet")).getValue());
|
||||
map.put("auto", ((ByteTag) tag.get("auto")).getValue());
|
||||
map.put("CustomName", MessageUtils.getBedrockMessage(((StringTag) tag.get("CustomName")).getValue()));
|
||||
map.put("powered", ((ByteTag) tag.get("powered")).getValue());
|
||||
map.put("Command", ((StringTag) tag.get("Command")).getValue());
|
||||
map.put("SuccessCount", ((IntTag) tag.get("SuccessCount")).getValue());
|
||||
map.put("TrackOutput", ((ByteTag) tag.get("TrackOutput")).getValue());
|
||||
map.put("UpdateLastExecution", ((ByteTag) tag.get("UpdateLastExecution")).getValue());
|
||||
builder.put("conditionMet", ((ByteTag) tag.get("conditionMet")).getValue());
|
||||
builder.put("auto", ((ByteTag) tag.get("auto")).getValue());
|
||||
builder.put("CustomName", MessageUtils.getBedrockMessage(((StringTag) tag.get("CustomName")).getValue()));
|
||||
builder.put("powered", ((ByteTag) tag.get("powered")).getValue());
|
||||
builder.put("Command", ((StringTag) tag.get("Command")).getValue());
|
||||
builder.put("SuccessCount", ((IntTag) tag.get("SuccessCount")).getValue());
|
||||
builder.put("TrackOutput", ((ByteTag) tag.get("TrackOutput")).getValue());
|
||||
builder.put("UpdateLastExecution", ((ByteTag) tag.get("UpdateLastExecution")).getValue());
|
||||
if (tag.get("LastExecution") != null) {
|
||||
map.put("LastExecution", ((LongTag) tag.get("LastExecution")).getValue());
|
||||
builder.put("LastExecution", ((LongTag) tag.get("LastExecution")).getValue());
|
||||
} else {
|
||||
map.put("LastExecution", (long) 0);
|
||||
builder.put("LastExecution", (long) 0);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,15 +33,11 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
import org.geysermc.connector.network.translators.world.block.DoubleChestValue;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity
|
||||
*/
|
||||
@BlockEntity(name = "Chest", regex = "chest")
|
||||
public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getDoubleChestValues().containsKey(blockState);
|
||||
|
@ -51,44 +47,39 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl
|
|||
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||
CompoundTag javaTag = getConstantJavaTag("chest", position.getX(), position.getY(), position.getZ());
|
||||
NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId("chest"), position.getX(), position.getY(), position.getZ()).toBuilder();
|
||||
translateTag(javaTag, blockState).forEach(tagBuilder::put);
|
||||
translateTag(tagBuilder, javaTag, blockState);
|
||||
BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
if (BlockStateValues.getDoubleChestValues().containsKey(blockState)) {
|
||||
DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState);
|
||||
if (chestValues != null) {
|
||||
int x = (int) tag.getValue().get("x").getValue();
|
||||
int z = (int) tag.getValue().get("z").getValue();
|
||||
// Calculate the position of the other chest based on the Java block state
|
||||
if (chestValues.isFacingEast) {
|
||||
if (chestValues.isDirectionPositive) {
|
||||
// East
|
||||
z = z + (chestValues.isLeft ? 1 : -1);
|
||||
} else {
|
||||
// West
|
||||
z = z + (chestValues.isLeft ? -1 : 1);
|
||||
}
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().getOrDefault(blockState, null);
|
||||
if (chestValues != null) {
|
||||
int x = (int) tag.getValue().get("x").getValue();
|
||||
int z = (int) tag.getValue().get("z").getValue();
|
||||
// Calculate the position of the other chest based on the Java block state
|
||||
if (chestValues.isFacingEast) {
|
||||
if (chestValues.isDirectionPositive) {
|
||||
// East
|
||||
z = z + (chestValues.isLeft ? 1 : -1);
|
||||
} else {
|
||||
if (chestValues.isDirectionPositive) {
|
||||
// South
|
||||
x = x + (chestValues.isLeft ? -1 : 1);
|
||||
} else {
|
||||
// North
|
||||
x = x + (chestValues.isLeft ? 1 : -1);
|
||||
}
|
||||
// West
|
||||
z = z + (chestValues.isLeft ? -1 : 1);
|
||||
}
|
||||
tags.put("pairx", x);
|
||||
tags.put("pairz", z);
|
||||
if (!chestValues.isLeft) {
|
||||
tags.put("pairlead", (byte) 1);
|
||||
} else {
|
||||
if (chestValues.isDirectionPositive) {
|
||||
// South
|
||||
x = x + (chestValues.isLeft ? -1 : 1);
|
||||
} else {
|
||||
// North
|
||||
x = x + (chestValues.isLeft ? 1 : -1);
|
||||
}
|
||||
}
|
||||
builder.put("pairx", x);
|
||||
builder.put("pairz", z);
|
||||
if (!chestValues.isLeft) {
|
||||
builder.put("pairlead", (byte) 1);
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,16 +26,11 @@
|
|||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
|
||||
@BlockEntity(name = "Empty", regex = "")
|
||||
public class EmptyBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
return new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,21 +28,18 @@ package org.geysermc.connector.network.translators.world.block.entity;
|
|||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.nukkitx.nbt.NbtList;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.nbt.NbtType;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "EndGateway", regex = "end_gateway")
|
||||
public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
tags.put("Age", (int) ((long) tag.get("Age").getValue()));
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
builder.put("Age", (int) ((long) tag.get("Age").getValue()));
|
||||
// Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist
|
||||
// Linked coordinates
|
||||
IntList tagsList = new IntArrayList();
|
||||
|
@ -50,8 +47,7 @@ public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
|||
tagsList.add(getExitPortalCoordinate(tag, "X"));
|
||||
tagsList.add(getExitPortalCoordinate(tag, "Y"));
|
||||
tagsList.add(getExitPortalCoordinate(tag, "Z"));
|
||||
tags.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList));
|
||||
return tags;
|
||||
builder.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList));
|
||||
}
|
||||
|
||||
private int getExitPortalCoordinate(CompoundTag tag, String axis) {
|
||||
|
@ -60,6 +56,7 @@ public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator {
|
|||
LinkedHashMap<?, ?> compoundTag = (LinkedHashMap<?, ?>) tag.get("ExitPortal").getValue();
|
||||
IntTag intTag = (IntTag) compoundTag.get(axis);
|
||||
return intTag.getValue();
|
||||
} return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,30 +35,19 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
|
||||
public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return (BlockStateValues.getFlowerPotValues().containsKey(blockState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(blockState));
|
||||
updateBlockPacket.setBlockPosition(position);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
||||
/**
|
||||
* @param blockState the Java block state of a potential flower pot block
|
||||
* @return true if the block is a flower pot
|
||||
*/
|
||||
public static boolean isFlowerBlock(int blockState) {
|
||||
return BlockStateValues.getFlowerPotValues().containsKey(blockState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Nukkit CompoundTag of the flower pot.
|
||||
*
|
||||
* @param blockState Java block state of flower pot.
|
||||
* @param position Bedrock position of flower pot.
|
||||
* @param position Bedrock position of flower pot.
|
||||
* @return Bedrock tag of flower pot.
|
||||
*/
|
||||
public static NbtMap getTag(int blockState, Vector3i position) {
|
||||
|
@ -80,4 +69,23 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, R
|
|||
}
|
||||
return tagBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return isFlowerBlock(blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
||||
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
|
||||
updateBlockPacket.setDataLayer(0);
|
||||
updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(blockState));
|
||||
updateBlockPacket.setBlockPosition(position);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK);
|
||||
updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY);
|
||||
session.sendUpstreamPacket(updateBlockPacket);
|
||||
BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,21 +27,16 @@ package org.geysermc.connector.network.translators.world.block.entity;
|
|||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
|
||||
@BlockEntity(name = "JigsawBlock", regex = "jigsaw")
|
||||
public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("joint", ((StringTag) tag.get("joint")).getValue());
|
||||
map.put("name", ((StringTag) tag.get("name")).getValue());
|
||||
map.put("target_pool", ((StringTag) tag.get("pool")).getValue());
|
||||
map.put("final_state", ((StringTag) tag.get("final_state")).getValue());
|
||||
map.put("target", ((StringTag) tag.get("target")).getValue());
|
||||
return map;
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
builder.put("joint", ((StringTag) tag.get("joint")).getValue());
|
||||
builder.put("name", ((StringTag) tag.get("name")).getValue());
|
||||
builder.put("target_pool", ((StringTag) tag.get("pool")).getValue());
|
||||
builder.put("final_state", ((StringTag) tag.get("final_state")).getValue());
|
||||
builder.put("target", ((StringTag) tag.get("target")).getValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,21 +36,20 @@ import org.geysermc.connector.utils.ChunkUtils;
|
|||
* Does not implement BlockEntityTranslator because it's only a block entity in Bedrock
|
||||
*/
|
||||
public class NoteblockBlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getNoteblockPitch(blockState) != -1;
|
||||
}
|
||||
|
||||
public static void translate(GeyserSession session, Position position) {
|
||||
int blockState = ChunkUtils.CACHED_BLOCK_ENTITIES.getOrDefault(position, 0);
|
||||
int blockState = session.getConnector().getConfig().isCacheChunks() ?
|
||||
session.getConnector().getWorldManager().getBlockAt(session, position) :
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(position);
|
||||
BlockEventPacket blockEventPacket = new BlockEventPacket();
|
||||
blockEventPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ()));
|
||||
blockEventPacket.setEventType(0);
|
||||
blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState));
|
||||
session.sendUpstreamPacket(blockEventPacket);
|
||||
|
||||
ChunkUtils.CACHED_BLOCK_ENTITIES.remove(position);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
|||
* Pistons are a special case where they are only a block entity on Bedrock.
|
||||
*/
|
||||
public class PistonBlockEntityTranslator {
|
||||
|
||||
/**
|
||||
* Used in ChunkUtils to determine if the block is a piston.
|
||||
*
|
||||
* @param blockState Java BlockState of block.
|
||||
* @return if block is a piston or not.
|
||||
*/
|
||||
|
@ -46,8 +46,9 @@ public class PistonBlockEntityTranslator {
|
|||
|
||||
/**
|
||||
* Calculates the Nukkit CompoundTag to send to the client on chunk
|
||||
*
|
||||
* @param blockState Java block state of block.
|
||||
* @param position Bedrock position of piston.
|
||||
* @param position Bedrock position of piston.
|
||||
* @return Bedrock tag of piston.
|
||||
*/
|
||||
public static NbtMap getTag(int blockState, Vector3i position) {
|
||||
|
@ -57,14 +58,13 @@ public class PistonBlockEntityTranslator {
|
|||
.putInt("z", position.getZ())
|
||||
.putByte("isMovable", (byte) 1)
|
||||
.putString("id", "PistonArm");
|
||||
if (BlockStateValues.getPistonValues().containsKey(blockState)) {
|
||||
boolean extended = BlockStateValues.getPistonValues().get(blockState);
|
||||
// 1f if extended, otherwise 0f
|
||||
tagBuilder.putFloat("Progress", (extended) ? 1.0f : 0.0f);
|
||||
// 1 if sticky, 0 if not
|
||||
tagBuilder.putByte("Sticky", (byte)((BlockStateValues.isStickyPiston(blockState)) ? 1 : 0));
|
||||
}
|
||||
|
||||
boolean extended = BlockStateValues.getPistonValues().get(blockState);
|
||||
// 1f if extended, otherwise 0f
|
||||
tagBuilder.putFloat("Progress", (extended) ? 1.0f : 0.0f);
|
||||
// 1 if sticky, 0 if not
|
||||
tagBuilder.putByte("Sticky", (byte) ((BlockStateValues.isStickyPiston(blockState)) ? 1 : 0));
|
||||
|
||||
return tagBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,23 +26,18 @@
|
|||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "ShulkerBox", regex = "shulker_box")
|
||||
public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
byte direction = BlockStateValues.getShulkerBoxDirection(blockState);
|
||||
// Just in case...
|
||||
if (direction == -1) direction = 1;
|
||||
tags.put("facing", direction);
|
||||
return tags;
|
||||
if (direction == -1) {
|
||||
direction = 1;
|
||||
}
|
||||
builder.put("facing", direction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,51 +27,12 @@ package org.geysermc.connector.network.translators.world.block.entity;
|
|||
|
||||
import com.github.steveice10.mc.protocol.data.message.MessageSerializer;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
import org.geysermc.connector.utils.SignUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "Sign", regex = "sign")
|
||||
public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
|
||||
StringBuilder signText = new StringBuilder();
|
||||
for(int i = 0; i < 4; i++) {
|
||||
int currentLine = i+1;
|
||||
String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), "");
|
||||
signLine = MessageUtils.getBedrockMessage(MessageSerializer.fromString(signLine));
|
||||
|
||||
// Check the character width on the sign to ensure there is no overflow that is usually hidden
|
||||
// to Java Edition clients but will appear to Bedrock clients
|
||||
int signWidth = 0;
|
||||
StringBuilder finalSignLine = new StringBuilder();
|
||||
for (char c : signLine.toCharArray()) {
|
||||
signWidth += SignUtils.getCharacterWidth(c);
|
||||
if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) {
|
||||
finalSignLine.append(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Java Edition 1.14 added the ability to change the text color of the whole sign using dye
|
||||
if (tag.contains("Color")) {
|
||||
signText.append(getBedrockSignColor(tag.get("Color").getValue().toString()));
|
||||
}
|
||||
|
||||
signText.append(finalSignLine.toString());
|
||||
signText.append("\n");
|
||||
}
|
||||
|
||||
tags.put("Text", MessageUtils.getBedrockMessage(MessageSerializer.fromString(signText.toString())));
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a color stored in a sign's Color tag to a Bedrock Edition formatting code.
|
||||
* <br>
|
||||
|
@ -133,4 +94,36 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator {
|
|||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
StringBuilder signText = new StringBuilder();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int currentLine = i + 1;
|
||||
String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), "");
|
||||
signLine = MessageUtils.getBedrockMessage(MessageSerializer.fromString(signLine));
|
||||
|
||||
// Check the character width on the sign to ensure there is no overflow that is usually hidden
|
||||
// to Java Edition clients but will appear to Bedrock clients
|
||||
int signWidth = 0;
|
||||
StringBuilder finalSignLine = new StringBuilder();
|
||||
for (char c : signLine.toCharArray()) {
|
||||
signWidth += SignUtils.getCharacterWidth(c);
|
||||
if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) {
|
||||
finalSignLine.append(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Java Edition 1.14 added the ability to change the text color of the whole sign using dye
|
||||
if (tag.contains("Color")) {
|
||||
signText.append(getBedrockSignColor(tag.get("Color").getValue().toString()));
|
||||
}
|
||||
|
||||
signText.append(finalSignLine.toString());
|
||||
signText.append("\n");
|
||||
}
|
||||
|
||||
builder.put("Text", MessageUtils.getBedrockMessage(MessageSerializer.fromString(signText.toString())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,29 +25,26 @@
|
|||
|
||||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "Skull", regex = "skull")
|
||||
public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState {
|
||||
|
||||
@Override
|
||||
public boolean isBlock(int blockState) {
|
||||
return BlockStateValues.getSkullVariant(blockState) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
byte skullVariant = BlockStateValues.getSkullVariant(blockState);
|
||||
float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f;
|
||||
// Just in case...
|
||||
if (skullVariant == -1) skullVariant = 0;
|
||||
tags.put("Rotation", rotation);
|
||||
tags.put("SkullType", skullVariant);
|
||||
return tags;
|
||||
if (skullVariant == -1) {
|
||||
skullVariant = 0;
|
||||
}
|
||||
builder.put("Rotation", rotation);
|
||||
builder.put("SkullType", skullVariant);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,63 +26,58 @@
|
|||
package org.geysermc.connector.network.translators.world.block.entity;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@BlockEntity(name = "MobSpawner", regex = "mob_spawner")
|
||||
public class SpawnerBlockEntityTranslator extends BlockEntityTranslator {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> translateTag(CompoundTag tag, int blockState) {
|
||||
Map<String, Object> tags = new HashMap<>();
|
||||
public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) {
|
||||
Tag current;
|
||||
|
||||
if (tag.get("MaxNearbyEntities") != null) {
|
||||
tags.put("MaxNearbyEntities", (short) tag.get("MaxNearbyEntities").getValue());
|
||||
if ((current = tag.get("MaxNearbyEntities")) != null) {
|
||||
builder.put("MaxNearbyEntities", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("RequiredPlayerRange") != null) {
|
||||
tags.put("RequiredPlayerRange", (short) tag.get("RequiredPlayerRange").getValue());
|
||||
if ((current = tag.get("RequiredPlayerRange")) != null) {
|
||||
builder.put("RequiredPlayerRange", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("SpawnCount") != null) {
|
||||
tags.put("SpawnCount", (short) tag.get("SpawnCount").getValue());
|
||||
if ((current = tag.get("SpawnCount")) != null) {
|
||||
builder.put("SpawnCount", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("MaxSpawnDelay") != null) {
|
||||
tags.put("MaxSpawnDelay", (short) tag.get("MaxSpawnDelay").getValue());
|
||||
if ((current = tag.get("MaxSpawnDelay")) != null) {
|
||||
builder.put("MaxSpawnDelay", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("Delay") != null) {
|
||||
tags.put("Delay", (short) tag.get("Delay").getValue());
|
||||
if ((current = tag.get("Delay")) != null) {
|
||||
builder.put("Delay", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("SpawnRange") != null) {
|
||||
tags.put("SpawnRange", (short) tag.get("SpawnRange").getValue());
|
||||
if ((current = tag.get("SpawnRange")) != null) {
|
||||
builder.put("SpawnRange", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("MinSpawnDelay") != null) {
|
||||
tags.put("MinSpawnDelay", (short) tag.get("MinSpawnDelay").getValue());
|
||||
if ((current = tag.get("MinSpawnDelay")) != null) {
|
||||
builder.put("MinSpawnDelay", current.getValue());
|
||||
}
|
||||
|
||||
if (tag.get("SpawnData") != null) {
|
||||
CompoundTag spawnData = tag.get("SpawnData");
|
||||
CompoundTag spawnData = tag.get("SpawnData");
|
||||
if (spawnData != null) {
|
||||
String entityID = (String) spawnData.get("id").getValue();
|
||||
tags.put("EntityIdentifier", entityID);
|
||||
builder.put("EntityIdentifier", entityID);
|
||||
|
||||
EntityType type = EntityType.getFromIdentifier(entityID);
|
||||
if (type != null) {
|
||||
tags.put("DisplayEntityWidth", type.getWidth());
|
||||
tags.put("DisplayEntityHeight", type.getHeight());
|
||||
tags.put("DisplayEntityScale", 1.0f);
|
||||
builder.put("DisplayEntityWidth", type.getWidth());
|
||||
builder.put("DisplayEntityHeight", type.getHeight());
|
||||
builder.put("DisplayEntityScale", 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
tags.put("id", "MobSpawner");
|
||||
tags.put("isMovable", (byte) 1);
|
||||
|
||||
return tags;
|
||||
builder.put("id", "MobSpawner");
|
||||
builder.put("isMovable", (byte) 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,17 +33,17 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
|
||||
|
||||
public class BlockEntityUtils {
|
||||
|
||||
private static final BlockEntityTranslator EMPTY_TRANSLATOR = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("Empty");
|
||||
|
||||
public static String getBedrockBlockEntityId(String id) {
|
||||
// These are the only exceptions when it comes to block entity ids
|
||||
if (BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.containsKey(id)) {
|
||||
return BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id);
|
||||
String value = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
id = id.replace("minecraft:", "")
|
||||
.replace("_", " ");
|
||||
.replace("_", " ");
|
||||
// Split at every space or capital letter - for the latter, some legacy Java block entity tags are the correct format already
|
||||
String[] words;
|
||||
if (!id.toUpperCase().equals(id)) { // Otherwise we get [S, K, U, L, L]
|
||||
|
@ -60,11 +60,10 @@ public class BlockEntityUtils {
|
|||
|
||||
public static BlockEntityTranslator getBlockEntityTranslator(String name) {
|
||||
BlockEntityTranslator blockEntityTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get(name);
|
||||
if (blockEntityTranslator == null) {
|
||||
return EMPTY_TRANSLATOR;
|
||||
if (blockEntityTranslator != null) {
|
||||
return blockEntityTranslator;
|
||||
}
|
||||
|
||||
return blockEntityTranslator;
|
||||
return EMPTY_TRANSLATOR;
|
||||
}
|
||||
|
||||
public static void updateBlockEntity(GeyserSession session, NbtMap blockEntity, Position position) {
|
||||
|
|
|
@ -72,9 +72,9 @@ import static org.geysermc.connector.network.translators.world.block.BlockTransl
|
|||
|
||||
@UtilityClass
|
||||
public class ChunkUtils {
|
||||
|
||||
/**
|
||||
* Temporarily stores positions of BlockState values that are needed for certain block entities actively
|
||||
* Temporarily stores positions of BlockState values that are needed for certain block entities actively.
|
||||
* Not used if cache chunks is enabled
|
||||
*/
|
||||
public static final Object2IntMap<Position> CACHED_BLOCK_ENTITIES = new Object2IntOpenHashMap<>();
|
||||
|
||||
|
@ -300,11 +300,16 @@ public class ChunkUtils {
|
|||
|
||||
public static void updateBlock(GeyserSession session, int blockState, Vector3i position) {
|
||||
// Checks for item frames so they aren't tripped up and removed
|
||||
if (ItemFrameEntity.positionContainsItemFrame(session, position) && blockState == AIR) {
|
||||
((ItemFrameEntity) session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, position))).updateBlock(session);
|
||||
return;
|
||||
} else if (ItemFrameEntity.positionContainsItemFrame(session, position)) {
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, position));
|
||||
long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, position);
|
||||
if (frameEntityId != -1) {
|
||||
// TODO: Very occasionally the item frame doesn't sync up when destroyed
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(frameEntityId);
|
||||
if (blockState == AIR && entity != null) { // Item frame is still present and no block overrides that; refresh it
|
||||
((ItemFrameEntity) entity).updateBlock(session);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise the item frame is gone
|
||||
if (entity != null) {
|
||||
session.getEntityCache().removeEntity(entity, false);
|
||||
} else {
|
||||
|
@ -342,7 +347,10 @@ public class ChunkUtils {
|
|||
((BedrockOnlyBlockEntity) requiresBlockState).updateBlock(session, blockState, position);
|
||||
break;
|
||||
}
|
||||
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
||||
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||
// Blocks aren't saved to a chunk cache; resort to this smaller cache
|
||||
CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState);
|
||||
}
|
||||
break; //No block will be a part of two classes
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue