From d69896b3810e216aff6042f30e049e2d0ce34c83 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 20 Dec 2020 20:40:21 -0500 Subject: [PATCH 1/4] Fix NPE when no item can be found from a block (#1718) This commit also removes an old map previously used for block entity translators --- .../world/block/BlockTranslator.java | 29 +++++-------------- .../connector/utils/InventoryUtils.java | 15 ++++++---- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index 4ec9bcac..e0821ae7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -30,15 +30,18 @@ import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.nukkitx.nbt.*; import it.unimi.dsi.fastutil.ints.*; -import it.unimi.dsi.fastutil.objects.*; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.world.block.entity.BlockEntity; import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; import java.io.DataInputStream; import java.io.InputStream; -import java.util.*; +import java.util.Iterator; +import java.util.Map; public class BlockTranslator { /** @@ -65,8 +68,6 @@ public class BlockTranslator { // Bedrock carpet ID, used in LlamaEntity.java for decoration public static final int CARPET = 171; - private static final Int2ObjectMap JAVA_ID_TO_BLOCK_ENTITY_MAP = new Int2ObjectOpenHashMap<>(); - public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap(); public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap(); public static final Int2ObjectMap JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>(); @@ -175,18 +176,6 @@ public class BlockTranslator { JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId); - // Used for adding all "special" Java block states to block state map - String identifier; - String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); - for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { - identifier = clazz.getAnnotation(BlockEntity.class).regex(); - // Endswith, or else the block bedrock gets picked up for bed - if (bedrockIdentifier.endsWith(identifier) && !identifier.equals("")) { - JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name()); - break; - } - } - BlockStateValues.storeBlockStateValues(entry, javaRuntimeId); String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; @@ -196,6 +185,8 @@ public class BlockTranslator { JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier); } + String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); + if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier); } @@ -356,10 +347,6 @@ public class BlockTranslator { return JAVA_ID_BLOCK_MAP.get(javaId); } - public static String getBlockEntityString(int javaId) { - return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId); - } - public static boolean isWaterlogged(int state) { return WATERLOGGED.contains(state); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index c1224e6e..e9d7f13a 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -219,12 +219,17 @@ public class InventoryUtils { } } - ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, - new ItemStack(ItemRegistry.getItemEntry(itemName).getJavaId())); - if ((slot - 36) != session.getInventory().getHeldItemSlot()) { - setHotbarItem(session, slot); + ItemEntry entry = ItemRegistry.getItemEntry(itemName); + if (entry != null) { + ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, + new ItemStack(entry.getJavaId())); + if ((slot - 36) != session.getInventory().getHeldItemSlot()) { + setHotbarItem(session, slot); + } + session.sendDownstreamPacket(actionPacket); + } else { + session.getConnector().getLogger().debug("Cannot find item for block " + itemName); } - session.sendDownstreamPacket(actionPacket); } } From b490dcfcbb441aa588ab3ac69a7a0fcb23423330 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 20 Dec 2020 20:41:07 -0500 Subject: [PATCH 2/4] Improve doDaylightCycle translation (#1711) Previously, we wouldn't send the time if the server was sending the same time with doDaylightCycle on. However, this isn't vanilla behavior (for Bedrock nor Java) and can occasionally cause irregularities. The time is now always sent to Bedrock clients, and a daylightCycle field is added to GeyserSession to keep track of the doDaylightCycle gamerule we need to send to Bedrock. Removing the map we used to store the time may also improve memory usage since this was never cleaned up. --- .../network/session/GeyserSession.java | 6 ++++ .../java/world/JavaUpdateTimeTranslator.java | 35 +++++++------------ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index cd420025..2e857cdd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -250,6 +250,12 @@ public class GeyserSession implements CommandSender { @Setter private ScheduledFuture movementSendIfIdle; + /** + * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless. + */ + @Setter + private boolean daylightCycle = true; + private boolean reducedDebugInfo = false; @Setter diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java index 8dc68918..dff78697 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java @@ -25,49 +25,38 @@ package org.geysermc.connector.network.translators.java.world; -import com.nukkitx.protocol.bedrock.data.GameRuleData; -import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; -import it.unimi.dsi.fastutil.longs.Long2LongMap; -import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; +import com.nukkitx.protocol.bedrock.packet.SetTimePacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; -import com.nukkitx.protocol.bedrock.packet.SetTimePacket; - @Translator(packet = ServerUpdateTimePacket.class) public class JavaUpdateTimeTranslator extends PacketTranslator { - // If negative, the last time is stored so we know it's not some plugin behavior doing weird things. - // Per-player for multi-world support - private static final Long2LongMap LAST_RECORDED_TIMES = new Long2LongOpenHashMap(); - @Override public void translate(ServerUpdateTimePacket packet, GeyserSession session) { - // Bedrock sends a GameRulesChangedPacket if there is no daylight cycle // Java just sends a negative long if there is no daylight cycle - long lastTime = LAST_RECORDED_TIMES.getOrDefault(session.getPlayerEntity().getEntityId(), 0); long time = packet.getTime(); - if (lastTime != time) { - // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day - SetTimePacket setTimePacket = new SetTimePacket(); - setTimePacket.setTime((int) Math.abs(time) % 24000); - session.sendUpstreamPacket(setTimePacket); - // TODO: Performance efficient to always do this? - LAST_RECORDED_TIMES.put(session.getPlayerEntity().getEntityId(), time); - } - if (lastTime < 0 && time >= 0) { + // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day + SetTimePacket setTimePacket = new SetTimePacket(); + setTimePacket.setTime((int) Math.abs(time) % 24000); + session.sendUpstreamPacket(setTimePacket); + if (!session.isDaylightCycle() && time >= 0) { + // Client thinks there is no daylight cycle but there is setDoDaylightCycleGamerule(session, true); - } else if (lastTime != time && time < 0) { + } else if (session.isDaylightCycle() && time < 0) { + // Client thinks there is daylight cycle but there isn't setDoDaylightCycleGamerule(session, false); } } private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) { session.sendGameRule("dodaylightcycle", doCycle); + // Save the value so we don't have to constantly send a daylight cycle gamerule update + session.setDaylightCycle(doCycle); } } From dbfdae63f1137ebe282d352adee822f2dfde90e5 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Sun, 20 Dec 2020 20:42:14 -0500 Subject: [PATCH 4/4] Add precautions to prevent stack traces on incomplete/unknown place sounds (#1717) --- .../java/world/JavaPlayBuiltinSoundTranslator.java | 8 ++++++-- .../network/translators/world/block/BlockTranslator.java | 6 +++++- connector/src/main/resources/mappings | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java index d849c917..1c057f45 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java @@ -34,8 +34,8 @@ import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.sound.SoundRegistry; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; @Translator(packet = ServerPlayBuiltinSoundPacket.class) public class JavaPlayBuiltinSoundTranslator extends PacketTranslator { @@ -82,7 +82,11 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator