diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 890f5d656..af9c4547d 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -66,6 +66,22 @@ tasks { relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson") relocate("net.kyori", "org.geysermc.relocate.kyori") + + dependencies { + // Exclude everything EXCEPT KQueue and some DNS stuff required for HAProxyc + exclude(dependency("io.netty:netty-transport-classes-epoll:.*")) + exclude(dependency("io.netty:netty-transport-native-epoll:.*")) + exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) + exclude(dependency("io.netty:netty-transport-native-kqueue:.*")) + exclude(dependency("io.netty:netty-handler:.*")) + exclude(dependency("io.netty:netty-common:.*")) + exclude(dependency("io.netty:netty-buffer:.*")) + exclude(dependency("io.netty:netty-resolver:.*")) + exclude(dependency("io.netty:netty-transport:.*")) + exclude(dependency("io.netty:netty-codec:.*")) + exclude(dependency("io.netty:netty-resolver-dns:.*")) + exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*")) + } } remapJar { diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index b5ef4e69e..da4e5af33 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -44,6 +44,7 @@ tasks.withType { // We cannot shade Netty, or else native libraries will not load // Needed because older Spigot builds do not provide the haproxy module + exclude(dependency("io.netty:netty-transport-classes-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) exclude(dependency("io.netty:netty-transport-native-kqueue:.*")) diff --git a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts index 395beb104..dde85c33a 100644 --- a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts @@ -24,6 +24,11 @@ tasks { exclude(dependency(string)) } } + + sJar.dependencies { + exclude(dependency("org.checkerframework:checker-qual:.*")) + exclude(dependency("org.jetbrains:annotations:.*")) + } } } named("build") { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index a74f3f7a2..24cce78fe 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -304,6 +304,7 @@ public class ItemRegistryPopulator { Set javaOnlyItems = new ObjectOpenHashSet<>(); Collections.addAll(javaOnlyItems, "minecraft:spectral_arrow", "minecraft:debug_stick", "minecraft:knowledge_book", "minecraft:tipped_arrow", "minecraft:bundle"); + javaOnlyItems.add("minecraft:decorated_pot"); // TODO 1.19.80 resolve probs? if (!customItemsAllowed) { javaOnlyItems.add("minecraft:furnace_minecart"); } diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 9a233fad3..d88d1720c 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -738,7 +738,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + } }); } @@ -782,7 +786,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + } }); } @@ -856,7 +864,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { selectedProfile, service.getAccessToken() ); - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + return false; + } // Save our refresh token for later use geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java index 204981965..5a61b483d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java @@ -25,11 +25,14 @@ package org.geysermc.geyser.translator.inventory.item.nbt; +import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.item.ItemRemapper; import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator; @@ -43,28 +46,27 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { List newTags = new ArrayList<>(); - Tag enchantmentTag = itemTag.get("Enchantments"); + Tag enchantmentTag = itemTag.remove("Enchantments"); if (enchantmentTag instanceof ListTag listTag) { for (Tag tag : listTag.getValue()) { if (!(tag instanceof CompoundTag)) continue; - - CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); - newTags.add(bedrockTag); - } - itemTag.remove("Enchantments"); - } - enchantmentTag = itemTag.get("StoredEnchantments"); - if (enchantmentTag instanceof ListTag listTag) { - for (Tag tag : listTag.getValue()) { - if (!(tag instanceof CompoundTag)) continue; - - CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); + CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag); + if (bedrockTag != null) { + newTags.add(bedrockTag); + } + } + } + + // TODO consolidate this into EnchantedBookTranslator + enchantmentTag = itemTag.remove("StoredEnchantments"); + if (enchantmentTag instanceof ListTag listTag) { + for (Tag tag : listTag.getValue()) { + if (!(tag instanceof CompoundTag)) continue; + CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag); if (bedrockTag != null) { - bedrockTag.put(new ShortTag("GeyserStoredEnchantment", (short) 0)); newTags.add(bedrockTag); } } - itemTag.remove("StoredEnchantments"); } if (!newTags.isEmpty()) { @@ -99,7 +101,6 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); javaTag.setValue(javaValue); - if (geyserStoredEnchantmentTag != null) { tagValue.remove("GeyserStoredEnchantment"); storedEnchantments.add(javaTag); @@ -120,13 +121,20 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { } - private CompoundTag remapEnchantment(CompoundTag tag) { + private CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) { Tag javaEnchId = tag.get("id"); if (!(javaEnchId instanceof StringTag)) return null; Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); if (enchantment == null) { + if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) { + Tag javaEnchLvl = tag.get("lvl"); + int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0; + + addSweeping(session, rootTag, sweepingLvl); + return null; + } GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue()); return null; } @@ -140,4 +148,21 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { return bedrockTag; } -} + private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) { + CompoundTag displayTag = itemTag.get("display"); + if (displayTag == null) { + displayTag = new CompoundTag("display"); + itemTag.put(displayTag); + } + ListTag loreTag = displayTag.get("Lore"); + if (loreTag == null) { + loreTag = new ListTag("Lore"); + displayTag.put(loreTag); + } + + String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale()); + String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale()); + + loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation)); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java index 05e14c41b..7019838c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java @@ -47,21 +47,23 @@ import org.geysermc.geyser.translator.protocol.Translator; @Translator(packet = ClientboundGameEventPacket.class) public class JavaGameEventTranslator extends PacketTranslator { + // Strength of rainstorms and thunderstorms is a 0-1 float on Java, while on Bedrock it is a 0-65535 int + private static final int MAX_STORM_STRENGTH = 65535; @Override public void translate(GeyserSession session, ClientboundGameEventPacket packet) { PlayerEntity entity = session.getPlayerEntity(); switch (packet.getNotification()) { + // Yes, START_RAIN and STOP_RAIN are swapped in terms of what they cause the client to do. + // This is how the Mojang mappings name them, so we go with it + // It seems Mojang's intent was that START_RAIN would set the rain strength to 0 so that it can then be incremeneted on a gradient by the server + // The inverse is true for STOP_RAIN + // This is indeed the behavior of the vanilla server + // However, it seems most server software (at least Spigot and Paper) did not go along with this + // As a result many developers use these packets for the opposite of what their names implies + // Behavior last verified with Java 1.19.4 and Bedrock 1.19.71 case START_RAIN: - LevelEventPacket startRainPacket = new LevelEventPacket(); - startRainPacket.setType(LevelEventType.START_RAINING); - startRainPacket.setData(Integer.MAX_VALUE); - startRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(startRainPacket); - session.setRaining(true); - break; - case STOP_RAIN: LevelEventPacket stopRainPacket = new LevelEventPacket(); stopRainPacket.setType(LevelEventType.STOP_RAINING); stopRainPacket.setData(0); @@ -69,34 +71,35 @@ public class JavaGameEventTranslator extends PacketTranslator 0f; - // Java sends the rain level. Bedrock doesn't care, so we don't care if it's already raining. - if (isCurrentlyRaining != session.isRaining()) { - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING); - changeRainPacket.setData(Integer.MAX_VALUE); // Dunno what this does; used to be implemented with ThreadLocalRandom - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); - } + float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyRaining = rainStrength > 0f; + LevelEventPacket changeRainPacket = new LevelEventPacket(); + changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING); + // This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING + changeRainPacket.setData((int) (rainStrength * MAX_STORM_STRENGTH)); + changeRainPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(changeRainPacket); + session.setRaining(isCurrentlyRaining); break; case THUNDER_STRENGTH: // See above, same process - ThunderStrengthValue thunderValue = (ThunderStrengthValue) packet.getValue(); - boolean isCurrentlyThundering = thunderValue.getStrength() > 0f; - if (isCurrentlyThundering != session.isThunder()) { - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM); - changeThunderPacket.setData(Integer.MAX_VALUE); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); - } + float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyThundering = thunderStrength > 0f; + LevelEventPacket changeThunderPacket = new LevelEventPacket(); + changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM); + changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH)); + changeThunderPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(changeThunderPacket); + session.setThunder(isCurrentlyThundering); break; case CHANGE_GAMEMODE: GameMode gameMode = (GameMode) packet.getValue();