From 3b8d1758b3333780a050cceaa5e4fb6cb830dc05 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Mon, 20 Jul 2020 19:02:18 -0400 Subject: [PATCH 01/37] Initial update for 20w29a --- connector/pom.xml | 2 +- .../java/org/geysermc/connector/GeyserConnector.java | 7 +++---- .../translators/bedrock/BedrockActionTranslator.java | 5 +---- .../bedrock/BedrockAdventureSettingsTranslator.java | 11 ++--------- connector/src/main/resources/languages | 2 +- connector/src/main/resources/mappings | 2 +- 6 files changed, 9 insertions(+), 20 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index f58fb0be83c..b595ed32742 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.steveice10 mcprotocollib - 46b46001f6 + 20w29a-SNAPSHOT compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 89eccda5c4f..bdaabc52f5d 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -32,10 +32,10 @@ import com.nukkitx.protocol.bedrock.v407.Bedrock_v407; import lombok.Getter; import lombok.Setter; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.common.AuthType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.network.ConnectorServerEventHandler; @@ -51,17 +51,16 @@ import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.WorldManager; -import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DockerCheck; +import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LocaleUtils; import java.net.InetSocketAddress; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java index e7139353cea..118a8cbf366 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; @@ -73,9 +72,7 @@ public void translate(PlayerActionPacket packet, GeyserSession session) { break; case START_GLIDE: // Otherwise gliding will not work in creative - ClientPlayerAbilitiesPacket playerAbilitiesPacket = new ClientPlayerAbilitiesPacket( - false, false, false, session.getGameMode() == GameMode.CREATIVE - ); + ClientPlayerAbilitiesPacket playerAbilitiesPacket = new ClientPlayerAbilitiesPacket(false); session.sendDownstreamPacket(playerAbilitiesPacket); case STOP_GLIDE: ClientPlayerStatePacket glidePacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java index e741ca35c13..1bf301be47a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.connector.network.translators.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket; import com.nukkitx.protocol.bedrock.data.AdventureSetting; import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; @@ -39,14 +38,8 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator Date: Tue, 21 Jul 2020 00:45:38 +0100 Subject: [PATCH 02/37] Add piglin brutes (#989) --- .../entity/living/monster/BasePiglinEntity.java | 11 +++++++++++ .../connector/entity/living/monster/PiglinEntity.java | 2 +- .../geysermc/connector/entity/type/EntityType.java | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java new file mode 100644 index 00000000000..830c7ea3dd1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java @@ -0,0 +1,11 @@ +package org.geysermc.connector.entity.living.monster; + +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.connector.entity.type.EntityType; + +public class BasePiglinEntity extends MonsterEntity { + + public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + super(entityId, geyserId, entityType, position, motion, rotation); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java index 83027e30e42..7b0d71e17f5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java @@ -33,7 +33,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemRegistry; -public class PiglinEntity extends MonsterEntity { +public class PiglinEntity extends BasePiglinEntity { public PiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java index e32de056885..87f4c8b506d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java @@ -155,6 +155,7 @@ public enum EntityType { HOGLIN(AnimalEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"), ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"), PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"), + PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"), /** * Item frames are handled differently since they are a block in Bedrock. From 6b7dad148375361ec24a4f6284df398369c063d9 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Fri, 24 Jul 2020 10:39:10 -0400 Subject: [PATCH 03/37] Update for protocol 408 and 20w30a --- connector/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index b595ed32742..93501d01b04 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -32,7 +32,7 @@ com.nukkitx.protocol - bedrock-v407 + bedrock-v408 2.6.0-SNAPSHOT compile @@ -105,7 +105,7 @@ com.github.steveice10 mcprotocollib - 20w29a-SNAPSHOT + 20w30a-SNAPSHOT compile From ae77388b2e0df0e68375ac95dbd945c67f5e738e Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Fri, 24 Jul 2020 10:45:36 -0400 Subject: [PATCH 04/37] Allow compilation; update GeyserConnector --- connector/pom.xml | 6 +++--- .../main/java/org/geysermc/connector/GeyserConnector.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 93501d01b04..b999d842ee7 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -103,9 +103,9 @@ compile - com.github.steveice10 - mcprotocollib - 20w30a-SNAPSHOT + com.github.GeyserMC + MCProtocolLib + da45dc9165 compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index bdaabc52f5d..de465637b74 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -29,7 +29,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; -import com.nukkitx.protocol.bedrock.v407.Bedrock_v407; +import com.nukkitx.protocol.bedrock.v408.Bedrock_v408; import lombok.Getter; import lombok.Setter; import org.geysermc.connector.bootstrap.GeyserBootstrap; @@ -72,7 +72,7 @@ public class GeyserConnector { public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); - public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v407.V407_CODEC; + public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v408.V408_CODEC; public static final String NAME = "Geyser"; public static final String VERSION = "DEV"; // A fallback for running in IDEs From 523e30429027d7cabaf8c88687790e1252b931f3 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Fri, 24 Jul 2020 16:45:44 -0400 Subject: [PATCH 05/37] Update mappings --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 6bb50495ffc..536cde02e47 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 6bb50495ffc9c3ef74c90838ed2f6a4f784c0be4 +Subproject commit 536cde02e47416a341c6de4635a3e5a400d4b9a3 From bf07f1a9ba8e967617cd9e478f6235906c375efe Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 29 Jul 2020 21:05:18 -0400 Subject: [PATCH 06/37] Update to 1.16.2-pre1 --- bootstrap/spigot/pom.xml | 2 +- .../platform/spigot/world/GeyserSpigotWorldManager.java | 7 ++++--- connector/pom.xml | 2 +- connector/src/main/resources/mappings | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index e05ad7f03d9..854ce9fa54c 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -26,7 +26,7 @@ us.myles viaversion - 3.0.1 + 3.1.0-1.16.2-pre1 provided diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java index d785fabca6a..23caf5d992f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java @@ -33,7 +33,7 @@ import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13; -import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData; +import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData; @AllArgsConstructor public class GeyserSpigotWorldManager extends WorldManager { @@ -60,12 +60,13 @@ public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boo Block block = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z); // Black magic that gets the old block state ID int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF); - // Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 + // Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2 int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId); int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId); int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId); int fifteenBlockId = us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData.blockStateMappings.getNewId(fourteenBlockId); - return MappingData.blockStateMappings.getNewId(fifteenBlockId); + int sixteenBlockId = us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData.blockStateMappings.getNewId(fifteenBlockId); + return MappingData.blockStateMappings.getNewId(sixteenBlockId); } else { return BlockTranslator.AIR; } diff --git a/connector/pom.xml b/connector/pom.xml index b999d842ee7..e2e49df5d2b 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.GeyserMC MCProtocolLib - da45dc9165 + ba0c4e9ecd compile diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 536cde02e47..46538b6036f 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 536cde02e47416a341c6de4635a3e5a400d4b9a3 +Subproject commit 46538b6036f02b3fe855ff75d82646ed74d46156 From af5e8a83ca51dedda0267004e12b431947f00bb0 Mon Sep 17 00:00:00 2001 From: Redned Date: Fri, 31 Jul 2020 14:57:06 -0500 Subject: [PATCH 07/37] Add test server to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e5d7af58a01..0d474d990bf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Docs: https://github.com/GeyserMC/Geyser/wiki - Download: http://ci.geysermc.org - Discord: http://discord.geysermc.org/ -- Donate: https://patreon.com/GeyserMC +- ~~Donate: https://patreon.com/GeyserMC~~ Currently disabled. +- Test Server: test.geysermc.org port 25565 for Java and 19132 for Bedrock ## What's Left to be Added/Fixed - The Following Inventories From 7fc14d8956157a735dcba939418b80ef3d1cb48a Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Fri, 31 Jul 2020 19:47:23 -0400 Subject: [PATCH 08/37] Add customizable MTU support (#1068) * Add customizable MTU support Fixes clients being unable to connect in rare instances. * Make config.yml nicer --- .../geysermc/platform/sponge/GeyserSpongeConfiguration.java | 5 +++++ .../main/java/org/geysermc/connector/GeyserConnector.java | 5 +++++ .../connector/configuration/GeyserConfiguration.java | 2 ++ .../connector/configuration/GeyserJacksonConfiguration.java | 3 +++ connector/src/main/resources/config.yml | 6 +++++- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index 27c5432682a..279aca544a4 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -253,6 +253,11 @@ public String getUniqueId() { } } + @Override + public int getMtu() { + return node.getNode("mtu").getInt(1400); + } + @Override public int getConfigVersion() { return node.getNode("config-version").getInt(0); diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index ee687dbbdd2..6224dfcd5f5 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.nukkitx.network.raknet.RakNetConstants; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; import com.nukkitx.protocol.bedrock.v407.Bedrock_v407; @@ -168,6 +169,10 @@ private GeyserConnector(PlatformType platformType, GeyserBootstrap bootstrap) { if (config.isAboveBedrockNetherBuilding()) DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether + // https://github.com/GeyserMC/Geyser/issues/957 + RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu(); + logger.debug("Setting MTU to " + config.getMtu()); + bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort())); bedrockServer.setHandler(new ConnectorServerEventHandler(this)); bedrockServer.bind().whenComplete((avoid, throwable) -> { diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java index 57b4d7392b1..94322db9bce 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java @@ -118,6 +118,8 @@ interface IMetricsInfo { String getUniqueId(); } + int getMtu(); + int getConfigVersion(); static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) { diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java index c31e9d2f51c..d6eaf934328 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java @@ -138,6 +138,9 @@ public static class MetricsInfo implements IMetricsInfo { private String uniqueId; } + @JsonProperty("mtu") + private int mtu = 1400; + @JsonProperty("config-version") private int configVersion; } diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index c587b21d97d..d8961270ec6 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -110,5 +110,9 @@ metrics: # UUID of server, don't change! uuid: generateduuid -# DO NOT TOUCH! +# ADVANCED OPTIONS - DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING! +# The internet supports a maximum MTU of 1492 but could cause issues with packet fragmentation. +# 1400 is the default. +# mtu: 1400 + config-version: 3 From 07f3d45cc48a2f12bed3978967c79de0ecdf82f8 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 1 Aug 2020 12:57:25 -0400 Subject: [PATCH 09/37] Check for display tag when translating anvil contents (#1073) --- .../network/translators/inventory/AnvilInventoryTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index 0a1d2f27276..ab266faef02 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -107,7 +107,7 @@ public void translateActions(GeyserSession session, Inventory inventory, List Date: Sat, 1 Aug 2020 10:41:59 -0800 Subject: [PATCH 10/37] Remove Y pos workaround in BedrockItemFrameDropItemTranslator (#1037) --- .../bedrock/BedrockItemFrameDropItemTranslator.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java index 168e552b65f..8f563c0e0f5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockItemFrameDropItemTranslator.java @@ -40,15 +40,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator 0) { - y = packet.getBlockPosition().getY() * 2; - } else { - y = (packet.getBlockPosition().getY() * -2) - 1; - } - Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), y, packet.getBlockPosition().getZ()); + Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()); ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, position), InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); session.sendDownstreamPacket(interactPacket); From 11c713dc6f72a422cbdbeb6e20ed1a8c54cd2024 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 3 Aug 2020 17:29:52 -0400 Subject: [PATCH 11/37] JavaEntityMetadataTranslator: replace stack trace with concise warning (#1086) * JavaEntityMetadataTranslator: replace stack trace with concise warning Removes the stack trace given when a ClassCastException occurs and replaces it with a friendlier message. Class cast errors will happen since some servers send incorrect values, and apparently it is default Minecraft behavior to ignore them. * Update languages submodule --- .../java/entity/JavaEntityMetadataTranslator.java | 14 +++++++++++++- connector/src/main/resources/languages | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java index e3de626c27c..97160250d78 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityMetadataTranslator.java @@ -32,6 +32,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket; +import org.geysermc.connector.utils.LanguageUtils; @Translator(packet = ServerEntityMetadataPacket.class) public class JavaEntityMetadataTranslator extends PacketTranslator { @@ -45,7 +46,18 @@ public void translate(ServerEntityMetadataPacket packet, GeyserSession session) if (entity == null) return; for (EntityMetadata metadata : packet.getMetadata()) { - entity.updateBedrockMetadata(metadata, session); + try { + entity.updateBedrockMetadata(metadata, session); + } catch (ClassCastException e) { + // Class cast exceptions are really the only ones we're going to get in normal gameplay + // Because some entity rewriters forget about some values + // Any other errors are actual bugs + session.getConnector().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.network.translator.metadata.failed", metadata, entity.getEntityType())); + session.getConnector().getLogger().debug("Entity Java ID: " + entity.getEntityId() + ", Geyser ID: " + entity.getGeyserId()); + if (session.getConnector().getConfig().isDebugMode()) { + e.printStackTrace(); + } + } } entity.updateBedrockMetadata(session); diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index 65e36478b89..7cc503e2f7c 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 65e36478b894af9cec74bc6df6552cb160a0c47d +Subproject commit 7cc503e2f7c0871a24beb3a114726d764a4836f1 From 61dbcb0c80bb991cb8c8098d540576c3081008f3 Mon Sep 17 00:00:00 2001 From: AJ Ferguson Date: Mon, 3 Aug 2020 13:42:43 -0800 Subject: [PATCH 12/37] Update effects mappings (#949) * Update effects mappings * Use STOP_RECORD as the default record instead of null * Add comments * Update mappings submodule * Update MCProtocolLib and effects * Change level event used for EVAPORATE effect The bedrock client plays an additional sound when using CAULDRON_EXPLODE. The java client does not play any sound. * Update mappings submodule --- connector/pom.xml | 2 +- .../network/translators/effect/Effect.java | 29 +- .../translators/effect/EffectRegistry.java | 60 +++- .../translators/effect/PlaySoundEffect.java | 81 +++++ .../translators/effect/SoundEventEffect.java | 64 ++++ .../translators/effect/SoundLevelEffect.java | 56 +++ .../java/world/JavaPlayEffectTranslator.java | 325 ++++++++++++------ connector/src/main/resources/mappings | 2 +- 8 files changed, 489 insertions(+), 130 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java diff --git a/connector/pom.xml b/connector/pom.xml index f58fb0be83c..17c9711d9ae 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.steveice10 mcprotocollib - 46b46001f6 + f03b176e18 compile diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java index 4c58235af56..b827bb93efe 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java @@ -25,19 +25,18 @@ package org.geysermc.connector.network.translators.effect; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; +import org.geysermc.connector.network.session.GeyserSession; -@Getter -@Setter -@AllArgsConstructor -public class Effect { - - private String javaName; - private String bedrockName; - private String type; - private int data; - private String identifier; - -} \ No newline at end of file +/** + * Represents an effect capable of translating itself into bedrock + */ +public interface Effect { + /** + * Translates the given {@link ServerPlayEffectPacket} into bedrock and sends it upstream. + * + * @param session GeyserSession + * @param packet the effect packet to handle + */ + void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet); +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java index 2aa96d88e84..39c586db758 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.effect; import com.fasterxml.jackson.databind.JsonNode; +import com.github.steveice10.mc.protocol.data.game.world.effect.SoundEffect; import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; @@ -46,7 +47,7 @@ */ public class EffectRegistry { - public static final Map EFFECTS = new HashMap<>(); + public static final Map SOUND_EFFECTS = new HashMap<>(); public static final Int2ObjectMap RECORDS = new Int2ObjectOpenHashMap<>(); private static Map particleTypeMap = new HashMap<>(); @@ -97,19 +98,54 @@ public static void init() { Iterator> effectsIterator = effects.fields(); while (effectsIterator.hasNext()) { Map.Entry entry = effectsIterator.next(); - // Separate records database since they're handled differently between the two versions - if (entry.getValue().has("records")) { - JsonNode records = entry.getValue().get("records"); - Iterator> recordsIterator = records.fields(); - while (recordsIterator.hasNext()) { - Map.Entry recordEntry = recordsIterator.next(); - RECORDS.put(Integer.parseInt(recordEntry.getKey()), SoundEvent.valueOf(recordEntry.getValue().asText())); + JsonNode node = entry.getValue(); + try { + String type = node.get("type").asText(); + SoundEffect javaEffect = null; + Effect effect = null; + switch (type) { + case "soundLevel": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); + int data = node.has("data") ? node.get("data").intValue() : 0; + effect = new SoundLevelEffect(levelEventType, data); + break; + } + case "soundEvent": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + SoundEvent soundEvent = SoundEvent.valueOf(node.get("name").asText()); + String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; + int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; + effect = new SoundEventEffect(soundEvent, identifier, extraData); + break; + } + case "playSound": { + javaEffect = SoundEffect.valueOf(entry.getKey()); + String name = node.get("name").asText(); + float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; + boolean pitchSub = node.has("pitch_sub") ? node.get("pitch_sub").booleanValue() : false; + float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").floatValue() : 1.0f; + float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").floatValue() : 0.0f; + boolean relative = node.has("relative") ? node.get("relative").booleanValue() : true; + effect = new PlaySoundEffect(name, volume, pitchSub, pitchMul, pitchAdd, relative); + break; + } + case "record": { + JsonNode records = entry.getValue().get("records"); + Iterator> recordsIterator = records.fields(); + while (recordsIterator.hasNext()) { + Map.Entry recordEntry = recordsIterator.next(); + RECORDS.put(Integer.parseInt(recordEntry.getKey()), SoundEvent.valueOf(recordEntry.getValue().asText())); + } + break; + } + } + if (javaEffect != null) { + SOUND_EFFECTS.put(javaEffect, effect); } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e.toString()); } - String identifier = (entry.getValue().has("identifier")) ? entry.getValue().get("identifier").asText() : ""; - int data = (entry.getValue().has("data")) ? entry.getValue().get("data").asInt() : -1; - Effect effect = new Effect(entry.getKey(), entry.getValue().get("name").asText(), entry.getValue().get("type").asText(), data, identifier); - EFFECTS.put(entry.getKey(), effect); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java new file mode 100644 index 00000000000..c82bca33260 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + * + */ + +package org.geysermc.connector.network.translators.effect; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; +import lombok.Value; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +@Value +public class PlaySoundEffect implements Effect { + /** + * Bedrock playsound identifier + */ + String name; + + /** + * Volume of the sound + */ + float volume; + + /** + * If true, the initial value used for random pitch is the difference between two random floats. + * If false, it is a single random float + */ + boolean pitchSub; + + /** + * Multiplier for random pitch value + */ + float pitchMul; + + /** + * Constant addition to random pitch value after multiplier + */ + float pitchAdd; + + /** + * True if the sound is meant to be played in 3d space + */ + boolean relative; + + @Override + public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { + Random rand = ThreadLocalRandom.current(); + PlaySoundPacket playSoundPacket = new PlaySoundPacket(); + playSoundPacket.setSound(name); + playSoundPacket.setPosition(!relative ? session.getPlayerEntity().getPosition() : Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); + playSoundPacket.setVolume(volume); + playSoundPacket.setPitch((pitchSub ? (rand.nextFloat() - rand.nextFloat()) : rand.nextFloat()) * pitchMul + pitchAdd); //replicates java client randomness + session.sendUpstreamPacket(playSoundPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java new file mode 100644 index 00000000000..77641e37fff --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + * + */ + +package org.geysermc.connector.network.translators.effect; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; +import lombok.Value; +import org.geysermc.connector.network.session.GeyserSession; + +@Value +public class SoundEventEffect implements Effect { + /** + * Bedrock sound event + */ + SoundEvent soundEvent; + + /** + * Entity identifier. Usually an empty string + */ + String identifier; + + /** + * Extra data. Usually -1 + */ + int extraData; + + @Override + public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { + LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); + levelSoundEvent.setSound(soundEvent); + levelSoundEvent.setIdentifier(identifier); + levelSoundEvent.setExtraData(extraData); + levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); + levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); + levelSoundEvent.setBabySound(false); + session.sendUpstreamPacket(levelSoundEvent); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java new file mode 100644 index 00000000000..67b10bb2c05 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + * + */ + +package org.geysermc.connector.network.translators.effect; + +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import lombok.Value; +import org.geysermc.connector.network.session.GeyserSession; + +@Value +public class SoundLevelEffect implements Effect { + /** + * Bedrock level event type + */ + LevelEventType levelEventType; + + /** + * Event data. Usually 0 + */ + int data; + + @Override + public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { + LevelEventPacket eventPacket = new LevelEventPacket(); + eventPacket.setType(levelEventType); + eventPacket.setData(data); + eventPacket.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); + session.sendUpstreamPacket(eventPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java index 83d6bb69fae..2590a679f2c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayEffectTranslator.java @@ -45,123 +45,246 @@ import java.util.ArrayList; import java.util.List; +import java.util.Locale; @Translator(packet = ServerPlayEffectPacket.class) public class JavaPlayEffectTranslator extends PacketTranslator { - // TODO: Update mappings since they're definitely all going to be wrong now @Override public void translate(ServerPlayEffectPacket packet, GeyserSession session) { - LevelEventPacket effect = new LevelEventPacket(); - // Some things here are particles, others are not - if (packet.getEffect() instanceof ParticleEffect) { - ParticleEffect particleEffect = (ParticleEffect) packet.getEffect(); - Effect geyserEffect = EffectRegistry.EFFECTS.get(particleEffect.name()); + // Separate case since each RecordEffectData in Java is an individual track in Bedrock + if (packet.getEffect() == SoundEffect.RECORD) { + RecordEffectData recordEffectData = (RecordEffectData) packet.getData(); + SoundEvent soundEvent = EffectRegistry.RECORDS.getOrDefault(recordEffectData.getRecordId(), SoundEvent.STOP_RECORD); + Vector3f pos = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f); + + LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); + levelSoundEvent.setIdentifier(""); + levelSoundEvent.setSound(soundEvent); + levelSoundEvent.setPosition(pos); + levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); + levelSoundEvent.setExtraData(-1); + levelSoundEvent.setBabySound(false); + session.sendUpstreamPacket(levelSoundEvent); + + if (soundEvent != SoundEvent.STOP_RECORD) { + // Send text packet as it seems to be handled in Java Edition client-side. + TextPacket textPacket = new TextPacket(); + textPacket.setType(TextPacket.Type.JUKEBOX_POPUP); + textPacket.setNeedsTranslation(true); + textPacket.setXuid(""); + textPacket.setPlatformChatId(""); + textPacket.setSourceName(null); + textPacket.setMessage("record.nowPlaying"); + List params = new ArrayList<>(); + String recordString = "%item." + soundEvent.name().toLowerCase(Locale.ROOT) + ".desc"; + params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); + textPacket.setParameters(params); + session.sendUpstreamPacket(textPacket); + } + return; + } + + if (packet.getEffect() instanceof SoundEffect) { + SoundEffect soundEffect = (SoundEffect) packet.getEffect(); + Effect geyserEffect = EffectRegistry.SOUND_EFFECTS.get(soundEffect); if (geyserEffect != null) { - String name = geyserEffect.getBedrockName(); - effect.setType(LevelEventType.valueOf(name)); - } else { - switch (particleEffect) { - // TODO: BREAK_SPLASH_POTION has additional data - case BONEMEAL_GROW: - effect.setType(LevelEventType.PARTICLE_CROP_GROWTH); - BonemealGrowEffectData growEffectData = (BonemealGrowEffectData) packet.getData(); - effect.setData(growEffectData.getParticleCount()); - break; - //TODO: Block break particles when under fire - case BREAK_BLOCK: - effect.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); // TODO: Check to make sure this is right - BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData(); - effect.setData(BlockTranslator.getBedrockBlockId(breakBlockEffectData.getBlockState())); - break; - case EXPLOSION: - effect.setType(LevelEventType.PARTICLE_EXPLOSION); - break; - case MOB_SPAWN: - effect.setType(LevelEventType.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java - break; - // Done with a dispenser - case SMOKE: - // Might need to be SHOOT - effect.setType(LevelEventType.PARTICLE_SMOKE); - break; - case COMPOSTER: - effect.setType(LevelEventType.PARTICLE_CROP_GROWTH); - - ComposterEffectData composterEffectData = (ComposterEffectData) packet.getData(); - LevelSoundEventPacket soundEvent = new LevelSoundEventPacket(); - soundEvent.setSound(SoundEvent.valueOf("COMPOSTER_" + composterEffectData.name())); - soundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - soundEvent.setIdentifier(":"); - soundEvent.setExtraData(-1); - soundEvent.setBabySound(false); - soundEvent.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEvent); - break; - case BLOCK_LAVA_EXTINGUISH: - effect.setType(LevelEventType.PARTICLE_SHOOT); - effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY() + 1, packet.getPosition().getZ())); - session.sendUpstreamPacket(effect); + geyserEffect.handleEffectPacket(session, packet); + return; + } + GeyserConnector.getInstance().getLogger().debug("Unhandled sound effect: " + soundEffect.name()); + } else if (packet.getEffect() instanceof ParticleEffect) { + ParticleEffect particleEffect = (ParticleEffect) packet.getEffect(); + Vector3f pos = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f); + + LevelEventPacket effectPacket = new LevelEventPacket(); + effectPacket.setPosition(pos); + effectPacket.setData(0); + switch (particleEffect) { + case COMPOSTER: { + effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + + ComposterEffectData composterEffectData = (ComposterEffectData) packet.getData(); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + switch (composterEffectData) { + case FILL: + soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); + break; + case FILL_SUCCESS: + soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); + break; + } + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + case BLOCK_LAVA_EXTINGUISH: { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + case BLOCK_REDSTONE_TORCH_BURNOUT: { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + case BLOCK_END_PORTAL_FRAME_FILL: { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.BLOCK_END_PORTAL_FRAME_FILL); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + case SMOKE: { + effectPacket.setType(LevelEventType.PARTICLE_SHOOT); + + SmokeEffectData smokeEffectData = (SmokeEffectData) packet.getData(); + int data = 0; + switch (smokeEffectData) { + case DOWN: + data = 4; + pos = pos.add(0, -0.9f, 0); + break; + case UP: + data = 4; + pos = pos.add(0, 0.5f, 0); + break; + case NORTH: + data = 1; + pos = pos.add(0, -0.2f, -0.7f); + break; + case SOUTH: + data = 7; + pos = pos.add(0, -0.2f, 0.7f); + break; + case WEST: + data = 3; + pos = pos.add(-0.7f, -0.2f, 0); + break; + case EAST: + data = 5; + pos = pos.add(0.7f, -0.2f, 0); + break; + + } + effectPacket.setPosition(pos); + effectPacket.setData(data); + break; + } + //TODO: Block break particles when under fire + case BREAK_BLOCK: { + effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); + + BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData(); + effectPacket.setData(BlockTranslator.getBedrockBlockId(breakBlockEffectData.getBlockState())); + break; + } + case BREAK_SPLASH_POTION: { + effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); + effectPacket.setPosition(pos.add(0, -0.5f, 0)); + + BreakPotionEffectData splashPotionData = (BreakPotionEffectData) packet.getData(); + effectPacket.setData(splashPotionData.getPotionId()); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.GLASS); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + case BREAK_EYE_OF_ENDER: { + effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); + break; + } + case MOB_SPAWN: { + effectPacket.setType(LevelEventType.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java + break; + } + case BONEMEAL_GROW: { + effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + + BonemealGrowEffectData growEffectData = (BonemealGrowEffectData) packet.getData(); + effectPacket.setData(growEffectData.getParticleCount()); + break; + } + case ENDERDRAGON_FIREBALL_EXPLODE: { + effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO + + DragonFireballEffectData fireballEffectData = (DragonFireballEffectData) packet.getData(); + if (fireballEffectData == DragonFireballEffectData.HAS_SOUND) { LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); - soundEventPacket.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - soundEventPacket.setIdentifier(":"); + soundEventPacket.setSound(SoundEvent.EXPLODE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); soundEventPacket.setExtraData(-1); soundEventPacket.setBabySound(false); soundEventPacket.setRelativeVolumeDisabled(false); session.sendUpstreamPacket(soundEventPacket); - return; - default: - GeyserConnector.getInstance().getLogger().debug("No effect handling for particle effect: " + packet.getEffect()); - } - } - effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - session.sendUpstreamPacket(effect); - } else if (packet.getEffect() instanceof SoundEffect) { - SoundEffect soundEffect = (SoundEffect) packet.getEffect(); - Effect geyserEffect = EffectRegistry.EFFECTS.get(soundEffect.name()); - if (geyserEffect != null) { - // Some events are LevelEventTypes, some are SoundEvents. - if (geyserEffect.getType().equals("soundLevel")) { - effect.setType(LevelEventType.valueOf(geyserEffect.getBedrockName())); - } else if (geyserEffect.getType().equals("soundEvent")) { - LevelSoundEventPacket soundEvent = new LevelSoundEventPacket(); - // Separate case since each RecordEffectData in Java is an individual track in Bedrock - if (geyserEffect.getJavaName().equals("RECORD")) { - RecordEffectData recordEffectData = (RecordEffectData) packet.getData(); - soundEvent.setSound(EffectRegistry.RECORDS.get(recordEffectData.getRecordId())); - if (EffectRegistry.RECORDS.get(recordEffectData.getRecordId()) != SoundEvent.STOP_RECORD) { - // Send text packet as it seems to be handled in Java Edition client-side. - TextPacket textPacket = new TextPacket(); - textPacket.setType(TextPacket.Type.JUKEBOX_POPUP); - textPacket.setNeedsTranslation(true); - textPacket.setXuid(""); - textPacket.setPlatformChatId(""); - textPacket.setSourceName(null); - textPacket.setMessage("record.nowPlaying"); - List params = new ArrayList<>(); - String recordString = "%item." + EffectRegistry.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase() + ".desc"; - params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); - textPacket.setParameters(params); - session.sendUpstreamPacket(textPacket); - } - } else { - soundEvent.setSound(SoundEvent.valueOf(geyserEffect.getBedrockName())); } - soundEvent.setExtraData(geyserEffect.getData()); - soundEvent.setIdentifier(geyserEffect.getIdentifier()); - soundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - session.sendUpstreamPacket(soundEvent); + break; + } + case EXPLOSION: { + effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); + effectPacket.setData(61); + break; + } + case EVAPORATE: { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); + effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); + break; + } + case END_GATEWAY_SPAWN: { + effectPacket.setType(LevelEventType.PARTICLE_EXPLOSION); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXPLODE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + break; + } + default: { + GeyserConnector.getInstance().getLogger().debug("Unhandled particle effect: " + particleEffect.name()); + return; } - } else { - GeyserConnector.getInstance().getLogger().debug("No effect handling for sound effect: " + packet.getEffect()); } + session.sendUpstreamPacket(effectPacket); } - if (effect.getType() != null) { - effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - session.sendUpstreamPacket(effect); - } - } } \ No newline at end of file diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 47179bc5ee1..8d6400da19d 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 47179bc5ee12cab11370b650ab5f3a641aba1390 +Subproject commit 8d6400da19d07085d60c6bbc11b23c1d391c056f From dea9329bb4398ed6696e449786a8d733cdc44680 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Wed, 5 Aug 2020 16:36:58 +0100 Subject: [PATCH 13/37] Update mappings submodule to fix 1.16 slabs and stonecutter (#1089) --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 8d6400da19d..83a3468766b 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 8d6400da19d07085d60c6bbc11b23c1d391c056f +Subproject commit 83a3468766b82ea97bd1ae8a1e92bffcc2745349 From 098a0e7993b81cd28f38b54de76d169666a804e8 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Wed, 5 Aug 2020 18:57:41 -0400 Subject: [PATCH 14/37] Update to 1.16.2-pre2 --- connector/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/pom.xml b/connector/pom.xml index e2e49df5d2b..f78cc875053 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.GeyserMC MCProtocolLib - ba0c4e9ecd + da148409ff compile From 0ca1096f45098e2f997571d4695d9495ea3d09f4 Mon Sep 17 00:00:00 2001 From: bundabrg Date: Sat, 8 Aug 2020 00:33:21 +0800 Subject: [PATCH 15/37] Fix Skin Caching and Fix Skin Restorer (#680) * Fix Skin Caching Changes: * Instead of caching a skin based upon the player we cached it based upon the textureURL. This means multiple players with the same skin will benefit from the cache and more importantly will mean a player changing their skin will not get a false cache hit. * This should fix all issues with SkinRestorer and will now correctly show the skin both to the player themselves and to other players Closes #518 * Remove duplicated code * Minimize playerlist updates Changes: * All async skin stuff will now just update skins and not be involved with sending the session to the player. This eliminates issues where the player list changes whilst an async task is occuring plus it means no invisible players while retrieving skin. * Fix bug when retrieving cached skin * When sending PlayerList packets ensure the skins have appropriate skinIds so the Bedrock client will cache hit/miss as needed * Make sure to add and remove player when setting skin if they do not belong on the playerlist * Make use of AuthData UUID when removing the player * Revert removal of checking if entity is valid when initialized This section is supposed to send all spawned entities in the java world to a player only after they've initialized. By removing this check it would also be sending entities that exist but are not spawned. * Optimizations Changes: * Check for duplicate requests based on textureURL instead of player ID * Don't use the PlayerSkinPacket. It duplicates the data sent in the PlayerListPacket and without it the players still get skin updates. * Support caching of skins to disk based on configuration variable If a skin is downloaded it will be saved to `cache/skins` using a base64 encoded filename of the textureUrl, if allowed by setting a non 0 value for the configuration variable `cache-skins` When reading a skin we try load it from a cache file first before trying to download it. We don't yet expire them but do update their last modification so we know which ones have been accessed. * Update `config.yml` with cache-skins directive, defaulting to disabled * Merge Fixes * Cache all images instead of just skins Changes: * Move the image caching from skins to where images may get downloaded so this also covers capes and anything else that uses the same method of image retrieval * Updated config value from `cache-skins` to `cache-images` * Updated cache location from `cache/skins` to `cache/images` * Images are stored in png format with a uuid. This may make debugging easier as they can be directly opened. * Implement cached image expiry If `cache-images` is set to a value greater than 0 then a scheduled task will occur once a day that will remove images with a modification date older than the value in days. * Force skin changes as trusted * Resolve PR queries * Fix signed int causing issues calculating expiry time for images * Reset Defaults to 0 and implement Google Timed Eviction cache for Images * Add memory cache for Capes Co-authored-by: Brendan Grieve Co-authored-by: bundabrg --- .gitignore | 1 + .../sponge/GeyserSpongeConfiguration.java | 5 + .../configuration/GeyserConfiguration.java | 2 + .../GeyserJacksonConfiguration.java | 3 + .../connector/entity/PlayerEntity.java | 22 +-- .../network/session/GeyserSession.java | 11 -- ...SetLocalPlayerAsInitializedTranslator.java | 4 +- .../player/JavaPlayerListEntryTranslator.java | 22 ++- .../spawn/JavaSpawnPlayerTranslator.java | 4 +- .../connector/utils/SkinProvider.java | 133 +++++++++++++----- .../geysermc/connector/utils/SkinUtils.java | 89 ++++++------ connector/src/main/resources/config.yml | 4 + 12 files changed, 167 insertions(+), 133 deletions(-) diff --git a/.gitignore b/.gitignore index 88b8bc73061..c4c878af454 100644 --- a/.gitignore +++ b/.gitignore @@ -241,3 +241,4 @@ config.yml logs/ public-key.pem locales/ +cache/ \ No newline at end of file diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index 279aca544a4..734fcca67f8 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -149,6 +149,11 @@ public boolean isCacheChunks() { return node.getNode("cache-chunks").getBoolean(false); } + @Override + public int getCacheImages() { + return node.getNode("cache-skins").getInt(0); + } + @Override public boolean isAboveBedrockNetherBuilding() { return node.getNode("above-bedrock-nether-building").getBoolean(false); diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java index 94322db9bce..4d9933ff50f 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java @@ -77,6 +77,8 @@ public interface GeyserConfiguration { boolean isCacheChunks(); + int getCacheImages(); + IMetricsInfo getMetrics(); interface IBedrockConfiguration { diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java index d6eaf934328..3873db3cc41 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java @@ -87,6 +87,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("cache-chunks") private boolean cacheChunks; + @JsonProperty("cache-images") + private int cacheImages = 0; + @JsonProperty("above-bedrock-nether-building") private boolean aboveBedrockNetherBuilding; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index fe4dc905c78..424f51870e8 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -38,7 +38,6 @@ import com.nukkitx.protocol.bedrock.packet.*; import lombok.Getter; import lombok.Setter; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.attribute.Attribute; import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.type.EntityType; @@ -47,7 +46,6 @@ import org.geysermc.connector.scoreboard.Team; import org.geysermc.connector.utils.AttributeUtils; import org.geysermc.connector.utils.MessageUtils; -import org.geysermc.connector.utils.SkinUtils; import java.util.ArrayList; import java.util.List; @@ -61,7 +59,7 @@ public class PlayerEntity extends LivingEntity { private UUID uuid; private String username; private long lastSkinUpdate = -1; - private boolean playerList = true; + private boolean playerList = true; // Player is in the player list private final EntityEffectCache effectCache; private Entity leftParrot; @@ -117,30 +115,12 @@ public void spawnEntity(GeyserSession session) { public void sendPlayer(GeyserSession session) { if(session.getEntityCache().getPlayerEntity(uuid) == null) return; - if (getLastSkinUpdate() == -1) { - if (playerList) { - PlayerListPacket playerList = new PlayerListPacket(); - playerList.setAction(PlayerListPacket.Action.ADD); - playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId)); - session.sendUpstreamPacket(playerList); - } - } if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) { session.getEntityCache().spawnEntity(this); } else { spawnEntity(session); } - - if (!playerList) { - // remove from playerlist if player isn't on playerlist - GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> { - PlayerListPacket playerList = new PlayerListPacket(); - playerList.setAction(PlayerListPacket.Action.REMOVE); - playerList.getEntries().add(new PlayerListPacket.Entry(uuid)); - session.sendUpstreamPacket(playerList); - }); - } } @Override 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 b861f64c437..5378900d090 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 @@ -251,17 +251,6 @@ public void connect(RemoteServer remoteServer) { upstream.sendPacket(attributesPacket); } - public void fetchOurSkin(PlayerListPacket.Entry entry) { - PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket(); - playerSkinPacket.setUuid(authData.getUUID()); - playerSkinPacket.setSkin(entry.getSkin()); - playerSkinPacket.setOldSkinName("OldName"); - playerSkinPacket.setNewSkinName("NewName"); - playerSkinPacket.setTrustedSkin(true); - upstream.sendPacket(playerSkinPacket); - getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID()); - } - public void login() { if (connector.getAuthType() != AuthType.ONLINE) { if (connector.getAuthType() == AuthType.OFFLINE) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index 87da2d00cb3..c1ad7409a92 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -44,8 +44,8 @@ public void translate(SetLocalPlayerAsInitializedPacket packet, GeyserSession se for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) { if (!entity.isValid()) { - // async skin loading - SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session)); + SkinUtils.requestAndHandleSkinAndCape(entity, session, null); + entity.sendPlayer(session); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java index f387daecfdd..10b2ba9add3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerListEntryTranslator.java @@ -82,18 +82,7 @@ public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) playerEntity.setPlayerList(true); playerEntity.setValid(true); - PlayerListPacket.Entry playerListEntry = SkinUtils.buildCachedEntry(entry.getProfile(), playerEntity.getGeyserId()); - if (self) { - // Copy the entry with our identity instead. - PlayerListPacket.Entry copy = new PlayerListPacket.Entry(session.getAuthData().getUUID()); - copy.setName(playerListEntry.getName()); - copy.setEntityId(playerListEntry.getEntityId()); - copy.setSkin(playerListEntry.getSkin()); - copy.setXuid(playerListEntry.getXuid()); - copy.setPlatformChatId(playerListEntry.getPlatformChatId()); - copy.setTeacher(playerListEntry.isTeacher()); - playerListEntry = copy; - } + PlayerListPacket.Entry playerListEntry = SkinUtils.buildCachedEntry(session, entry.getProfile(), playerEntity.getGeyserId()); translate.getEntries().add(playerListEntry); break; @@ -103,15 +92,20 @@ public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) // remove from tablist but player entity is still there entity.setPlayerList(false); } else { - // just remove it from caching if (entity == null) { + // just remove it from caching session.getEntityCache().removePlayerEntity(entry.getProfile().getId()); } else { entity.setPlayerList(false); session.getEntityCache().removeEntity(entity, false); } } - translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId())); + if (entity == session.getPlayerEntity()) { + // If removing ourself we use our AuthData UUID + translate.getEntries().add(new PlayerListPacket.Entry(session.getAuthData().getUUID())); + } else { + translate.getEntries().add(new PlayerListPacket.Entry(entry.getProfile().getId())); + } break; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java index 130a5f653be..47beca8a652 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java @@ -54,9 +54,9 @@ public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) { entity.setRotation(rotation); session.getEntityCache().cacheEntity(entity); - // async skin loading if (session.getUpstream().isInitialized()) { - SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session)); + entity.sendPlayer(session); + SkinUtils.requestAndHandleSkinAndCape(entity, session, null); } } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java index 36507db089b..352a0b0f9cc 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java @@ -27,6 +27,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -40,9 +42,11 @@ import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; import java.util.Arrays; import java.util.Base64; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.*; @@ -54,22 +58,26 @@ public class SkinProvider { public static final Skin EMPTY_SKIN = new Skin(-1, "steve", STEVE_SKIN); public static final byte[] ALEX_SKIN = new ProvidedSkin("bedrock/skin/skin_alex.png").getSkin(); public static final Skin EMPTY_SKIN_ALEX = new Skin(-1, "alex", ALEX_SKIN); - private static Map cachedSkins = new ConcurrentHashMap<>(); - private static Map> requestedSkins = new ConcurrentHashMap<>(); + private static final Cache cachedSkins = CacheBuilder.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .build(); + + private static final Map> requestedSkins = new ConcurrentHashMap<>(); public static final Cape EMPTY_CAPE = new Cape("", "no-cape", new byte[0], -1, true); - private static Map cachedCapes = new ConcurrentHashMap<>(); - private static Map> requestedCapes = new ConcurrentHashMap<>(); + private static final Cache cachedCapes = CacheBuilder.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .build(); + private static final Map> requestedCapes = new ConcurrentHashMap<>(); public static final SkinGeometry EMPTY_GEOMETRY = SkinProvider.SkinGeometry.getLegacy(false); - private static Map cachedGeometry = new ConcurrentHashMap<>(); + private static final Map cachedGeometry = new ConcurrentHashMap<>(); public static final boolean ALLOW_THIRD_PARTY_EARS = GeyserConnector.getInstance().getConfig().isAllowThirdPartyEars(); public static String EARS_GEOMETRY; public static String EARS_GEOMETRY_SLIM; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - private static final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes static { /* Load in the normal ears geometry */ @@ -102,22 +110,44 @@ public class SkinProvider { } EARS_GEOMETRY_SLIM = earsDataBuilder.toString(); - } - public static boolean hasSkinCached(UUID uuid) { - return cachedSkins.containsKey(uuid); + // Schedule Daily Image Expiry if we are caching them + if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) { + GeyserConnector.getInstance().getGeneralThreadPool().scheduleAtFixedRate(() -> { + File cacheFolder = Paths.get("cache", "images").toFile(); + if (!cacheFolder.exists()) { + return; + } + + int count = 0; + final long expireTime = ((long)GeyserConnector.getInstance().getConfig().getCacheImages()) * ((long)1000 * 60 * 60 * 24); + for (File imageFile : Objects.requireNonNull(cacheFolder.listFiles())) { + if (imageFile.lastModified() < System.currentTimeMillis() - expireTime) { + //noinspection ResultOfMethodCallIgnored + imageFile.delete(); + count++; + } + } + + if (count > 0) { + GeyserConnector.getInstance().getLogger().debug(String.format("Removed %d cached image files as they have expired", count)); + } + }, 10, 1440, TimeUnit.MINUTES); + } } public static boolean hasCapeCached(String capeUrl) { - return cachedCapes.containsKey(capeUrl); + return cachedCapes.getIfPresent(capeUrl) != null; } - public static Skin getCachedSkin(UUID uuid) { - return cachedSkins.getOrDefault(uuid, EMPTY_SKIN); + public static Skin getCachedSkin(String skinUrl) { + Skin skin = cachedSkins.getIfPresent(skinUrl); + return skin != null ? skin : EMPTY_SKIN; } public static Cape getCachedCape(String capeUrl) { - return capeUrl != null ? cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE) : EMPTY_CAPE; + Cape cape = capeUrl != null ? cachedCapes.getIfPresent(capeUrl) : EMPTY_CAPE; + return cape != null ? cape : EMPTY_CAPE; } public static CompletableFuture requestSkinAndCape(UUID playerId, String skinUrl, String capeUrl) { @@ -137,28 +167,26 @@ public static CompletableFuture requestSkinAndCape(UUID playerId, S public static CompletableFuture requestSkin(UUID playerId, String textureUrl, boolean newThread) { if (textureUrl == null || textureUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_SKIN); - if (requestedSkins.containsKey(playerId)) return requestedSkins.get(playerId); // already requested + if (requestedSkins.containsKey(textureUrl)) return requestedSkins.get(textureUrl); // already requested - if ((System.currentTimeMillis() - CACHE_INTERVAL) < cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getRequestedOn()) { - // no need to update, still cached - return CompletableFuture.completedFuture(cachedSkins.get(playerId)); + Skin cachedSkin = cachedSkins.getIfPresent(textureUrl); + if (cachedSkin != null) { + return CompletableFuture.completedFuture(cachedSkin); } CompletableFuture future; if (newThread) { future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE) .whenCompleteAsync((skin, throwable) -> { - if (!cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getTextureUrl().equals(textureUrl)) { - skin.updated = true; - cachedSkins.put(playerId, skin); - } - requestedSkins.remove(skin.getSkinOwner()); + skin.updated = true; + cachedSkins.put(textureUrl, skin); + requestedSkins.remove(textureUrl); }); - requestedSkins.put(playerId, future); + requestedSkins.put(textureUrl, future); } else { Skin skin = supplySkin(playerId, textureUrl); future = CompletableFuture.completedFuture(skin); - cachedSkins.put(playerId, skin); + cachedSkins.put(textureUrl, skin); } return future; } @@ -168,11 +196,9 @@ public static CompletableFuture requestCape(String capeUrl, CapeProvider p if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested boolean officialCape = provider == CapeProvider.MINECRAFT; - boolean validCache = (System.currentTimeMillis() - CACHE_INTERVAL) < cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE).getRequestedOn(); - - if ((cachedCapes.containsKey(capeUrl) && officialCape) || validCache) { - // the cape is an official cape (static) or the cape doesn't need a update yet - return CompletableFuture.completedFuture(cachedCapes.get(capeUrl)); + Cape cachedCape = cachedCapes.getIfPresent(capeUrl); + if (cachedCape != null) { + return CompletableFuture.completedFuture(cachedCape); } CompletableFuture future; @@ -245,7 +271,10 @@ public static CompletableFuture requestUnofficialEars(Skin officialSkin, U } public static CompletableFuture requestBedrockCape(UUID playerID, boolean newThread) { - Cape bedrockCape = cachedCapes.getOrDefault(playerID.toString() + ".Bedrock", EMPTY_CAPE); + Cape bedrockCape = cachedCapes.getIfPresent(playerID.toString() + ".Bedrock"); + if (bedrockCape == null) { + bedrockCape = EMPTY_CAPE; + } return CompletableFuture.completedFuture(bedrockCape); } @@ -256,7 +285,7 @@ public static CompletableFuture requestBedrockGeometry(SkinGeometr public static void storeBedrockSkin(UUID playerID, String skinID, byte[] skinData) { Skin skin = new Skin(playerID, skinID, skinData, System.currentTimeMillis(), true, false); - cachedSkins.put(playerID, skin); + cachedSkins.put(skin.getTextureUrl(), skin); } public static void storeBedrockCape(UUID playerID, byte[] capeData) { @@ -276,7 +305,7 @@ public static void storeBedrockGeometry(UUID playerID, byte[] geometryName, byte * @param skin The skin to cache */ public static void storeEarSkin(UUID playerID, Skin skin) { - cachedSkins.put(playerID, skin); + cachedSkins.put(skin.getTextureUrl(), skin); } /** @@ -290,11 +319,12 @@ public static void storeEarGeometry(UUID playerID, boolean isSlim) { } private static Skin supplySkin(UUID uuid, String textureUrl) { - byte[] skin = EMPTY_SKIN.getSkinData(); try { - skin = requestImage(textureUrl, null); + byte[] skin = requestImage(textureUrl, null); + return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); } catch (Exception ignored) {} // just ignore I guess - return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); + + return new Skin(uuid, "empty", EMPTY_SKIN.getSkinData(), System.currentTimeMillis(), false, false); } private static Cape supplyCape(String capeUrl, CapeProvider provider) { @@ -356,11 +386,38 @@ private static Skin supplyEars(Skin existingSkin, String earsUrl, EarsProvider p return existingSkin; } + @SuppressWarnings("ResultOfMethodCallIgnored") private static byte[] requestImage(String imageUrl, CapeProvider provider) throws Exception { - BufferedImage image = downloadImage(imageUrl, provider); - GeyserConnector.getInstance().getLogger().debug("Downloaded " + imageUrl); + BufferedImage image = null; + + // First see if we have a cached file. We also update the modification stamp so we know when the file was last used + File imageFile = Paths.get("cache", "images", UUID.nameUUIDFromBytes(imageUrl.getBytes()).toString() + ".png").toFile(); + if (imageFile.exists()) { + try { + GeyserConnector.getInstance().getLogger().debug("Reading cached image from file " + imageFile.getPath() + " for " + imageUrl); + imageFile.setLastModified(System.currentTimeMillis()); + image = ImageIO.read(imageFile); + } catch (IOException ignored) {} + } + + // If no image we download it + if (image == null) { + image = downloadImage(imageUrl, provider); + GeyserConnector.getInstance().getLogger().debug("Downloaded " + imageUrl); + + // Write to cache if we are allowed + if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) { + imageFile.getParentFile().mkdirs(); + try { + ImageIO.write(image, "png", imageFile); + GeyserConnector.getInstance().getLogger().debug("Writing cached skin to file " + imageFile.getPath() + " for " + imageUrl); + } catch (IOException e) { + GeyserConnector.getInstance().getLogger().error("Failed to write cached skin to file " + imageFile.getPath() + " for " + imageUrl); + } + } + } - // if the requested image is an cape + // if the requested image is a cape if (provider != null) { while(image.getWidth() > 64) { image = scale(image); diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java index 225885769a5..77ab7f9393c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -47,18 +47,21 @@ public class SkinUtils { - public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long geyserId) { + public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, GameProfile profile, long geyserId) { GameProfileData data = GameProfileData.from(profile); SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl()); SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); + SkinProvider.Skin skin = SkinProvider.getCachedSkin(data.getSkinUrl()); + return buildEntryManually( + session, profile.getId(), profile.getName(), geyserId, - profile.getIdAsString(), - SkinProvider.getCachedSkin(profile.getId()).getSkinData(), + skin.getTextureUrl(), + skin.getSkinData(), cape.getCapeId(), cape.getCapeData(), geometry.getGeometryName(), @@ -66,12 +69,13 @@ public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long ); } - public static PlayerListPacket.Entry buildDefaultEntry(GameProfile profile, long geyserId) { + public static PlayerListPacket.Entry buildDefaultEntry(GeyserSession session, GameProfile profile, long geyserId) { return buildEntryManually( + session, profile.getId(), profile.getName(), geyserId, - profile.getIdAsString(), + "default", SkinProvider.STEVE_SKIN, SkinProvider.EMPTY_CAPE.getCapeId(), SkinProvider.EMPTY_CAPE.getCapeData(), @@ -80,16 +84,25 @@ public static PlayerListPacket.Entry buildDefaultEntry(GameProfile profile, long ); } - public static PlayerListPacket.Entry buildEntryManually(UUID uuid, String username, long geyserId, + public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, UUID uuid, String username, long geyserId, String skinId, byte[] skinData, String capeId, byte[] capeData, String geometryName, String geometryData) { SerializedSkin serializedSkin = SerializedSkin.of( skinId, geometryName, ImageData.of(skinData), Collections.emptyList(), - ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, uuid.toString() + ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId ); - PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid); + PlayerListPacket.Entry entry; + + // If we are building a PlayerListEntry for our own session we use our AuthData UUID instead of the Java UUID + // as bedrock expects to get back its own provided uuid + if (session.getPlayerEntity().getUuid().equals(uuid)) { + entry = new PlayerListPacket.Entry(session.getAuthData().getUUID()); + } else { + entry = new PlayerListPacket.Entry(uuid); + } + entry.setName(username); entry.setEntityId(geyserId); entry.setSkin(serializedSkin); @@ -201,48 +214,34 @@ public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSessio } } - if (entity.getLastSkinUpdate() < skin.getRequestedOn()) { - entity.setLastSkinUpdate(skin.getRequestedOn()); - - if (session.getUpstream().isInitialized()) { - PlayerListPacket.Entry updatedEntry = buildEntryManually( - entity.getUuid(), - entity.getUsername(), - entity.getGeyserId(), - entity.getUuid().toString(), - skin.getSkinData(), - cape.getCapeId(), - cape.getCapeData(), - geometry.getGeometryName(), - geometry.getGeometryData() - ); - - // If it is our skin we replace the UUID with the authdata UUID - if (session.getPlayerEntity() == entity) { - // Copy the entry with our identity instead. - PlayerListPacket.Entry copy = new PlayerListPacket.Entry(session.getAuthData().getUUID()); - copy.setName(updatedEntry.getName()); - copy.setEntityId(updatedEntry.getEntityId()); - copy.setSkin(updatedEntry.getSkin()); - copy.setXuid(updatedEntry.getXuid()); - copy.setPlatformChatId(updatedEntry.getPlatformChatId()); - copy.setTeacher(updatedEntry.isTeacher()); - updatedEntry = copy; - } - + entity.setLastSkinUpdate(skin.getRequestedOn()); + + if (session.getUpstream().isInitialized()) { + PlayerListPacket.Entry updatedEntry = buildEntryManually( + session, + entity.getUuid(), + entity.getUsername(), + entity.getGeyserId(), + skin.getTextureUrl(), + skin.getSkinData(), + cape.getCapeId(), + cape.getCapeData(), + geometry.getGeometryName(), + geometry.getGeometryData() + ); + + + PlayerListPacket playerAddPacket = new PlayerListPacket(); + playerAddPacket.setAction(PlayerListPacket.Action.ADD); + playerAddPacket.getEntries().add(updatedEntry); + session.sendUpstreamPacket(playerAddPacket); + + if (!entity.isPlayerList()) { PlayerListPacket playerRemovePacket = new PlayerListPacket(); playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); playerRemovePacket.getEntries().add(updatedEntry); session.sendUpstreamPacket(playerRemovePacket); - PlayerListPacket playerAddPacket = new PlayerListPacket(); - playerAddPacket.setAction(PlayerListPacket.Action.ADD); - playerAddPacket.getEntries().add(updatedEntry); - session.sendUpstreamPacket(playerAddPacket); - - if(entity.getUuid().equals(session.getPlayerEntity().getUuid())) { - session.fetchOurSkin(updatedEntry); - } } } } catch (Exception e) { diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index d8961270ec6..6ccaa306563 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -94,6 +94,10 @@ show-cooldown: true # Geyser has direct access to the server itself. cache-chunks: false +# Specify how many days images will be cached to disk to save downloading them from the internet. +# A value of 0 is disabled. (Default: 0) +cache-images: 0 + # Bedrock prevents building and displaying blocks above Y127 in the Nether - # enabling this config option works around that by changing the Nether dimension ID # to the End ID. The main downside to this is that the sky will resemble that of From d49856cd7fe7ada9b4125f6e23ee2ee4a308b8be Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Fri, 7 Aug 2020 14:10:26 -0400 Subject: [PATCH 16/37] Change scoreboard errors to debug only (#781) Prevents errors from occuring that don't stop operation of Geyser. --- .../java/scoreboard/JavaTeamTranslator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java index f1eb21011ed..7498a64f420 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaTeamTranslator.java @@ -65,21 +65,21 @@ public void translate(ServerTeamPacket packet, GeyserSession session) { .setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode())) .setUpdateType(UpdateType.UPDATE); } else { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); + GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } break; case ADD_PLAYER: - if(team != null){ + if (team != null) { team.addEntities(packet.getPlayers()); } else { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); + GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } break; case REMOVE_PLAYER: - if(team != null){ + if (team != null) { team.removeEntities(packet.getPlayers()); } else { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); + GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } break; case REMOVE: From 7df476183abe005b93593e9ac774b015f2909d20 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 8 Aug 2020 17:50:32 -0400 Subject: [PATCH 17/37] Implement proper mappings for pistons, dropper, dispenser (#1103) This commit gets rid of the hacky workaround implemented for pistons, droppers and dispensers and actually implements the vanilla data values. --- .../connector/network/translators/item/ItemRegistry.java | 7 ------- connector/src/main/resources/mappings | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 6fc5647299b..4828fbf27bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -214,13 +214,6 @@ public static ItemEntry getItem(ItemData data) { return itemEntry; } } - // If item find was unsuccessful first time, we try again while ignoring damage - // Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory - for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId()) { - return itemEntry; - } - } // This will hide the message when the player clicks with an empty hand if (data.getId() != 0 && data.getDamage() != 0) { diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 83a3468766b..a222d85dc0b 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 83a3468766b82ea97bd1ae8a1e92bffcc2745349 +Subproject commit a222d85dc0b8e8c95a150f2d488a6a25390b8c2f From 0fde30fc78f05ad97d9aa278ebc4283187f10e22 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Sat, 8 Aug 2020 17:50:49 -0400 Subject: [PATCH 18/37] GeyserSession: always send naturalRegeneration=false gamerule (#1097) This essentially gives the server full control over the health visual. --- .../geysermc/connector/network/session/GeyserSession.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 5378900d090..340292e254b 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 @@ -249,6 +249,12 @@ public void connect(RemoteServer remoteServer) { attributes.add(new AttributeData("minecraft:movement", 0.0f, 1024f, 0.1f, 0.1f)); attributesPacket.setAttributes(attributes); upstream.sendPacket(attributesPacket); + + // Only allow the server to send health information + // Setting this to false allows natural regeneration to work false but doesn't break it being true + GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket(); + gamerulePacket.getGameRules().add(new GameRuleData<>("naturalregeneration", false)); + upstream.sendPacket(gamerulePacket); } public void login() { From 0a5048232f8d994537190674e1b4f6c09729ff1f Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 8 Aug 2020 23:41:12 +0100 Subject: [PATCH 19/37] Add support for client side settings (#1035) * Port code from #486 Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com> * Fix and clean code and add default gamemode changing * Clean copyright * Remove direct modification of server, clean up code and add player list xuid fetching. * Move to custom settings menu * Move sendAdventureSettings to GeyserSession * Add javadoc comments * Add translation support * Remove updated copyright * Clean up * Clarify some javadoc comments * Remove obsolete code * Update languages submodule * Fix javadoc comments * Fix compile Co-authored-by: Luke <32024335+lukeeey@users.noreply.github.com> Co-authored-by: Redned --- .../world/GeyserSpigotWorldManager.java | 21 ++- connector/pom.xml | 6 + .../connector/bootstrap/GeyserBootstrap.java | 4 +- .../connector/entity/PlayerEntity.java | 12 +- .../network/UpstreamPacketHandler.java | 5 + .../network/session/GeyserSession.java | 109 +++++++++++- .../{ScoreboardCache.java => WorldCache.java} | 23 ++- ...drockServerSettingsRequestTranslator.java} | 20 ++- .../BedrockEntityEventTranslator.java | 2 +- .../player}/BedrockActionTranslator.java | 2 +- .../player}/BedrockEmoteTranslator.java | 2 +- .../player}/BedrockInteractTranslator.java | 2 +- .../player}/BedrockMovePlayerTranslator.java | 2 +- .../BedrockLevelSoundEventTranslator.java | 2 +- .../java/JavaDifficultyTranslator.java | 2 + .../java/JavaJoinGameTranslator.java | 2 +- .../entity/JavaEntityStatusTranslator.java | 28 +++ .../player/JavaPlayerAbilitiesTranslator.java | 21 +-- .../JavaDisplayScoreboardTranslator.java | 2 +- .../JavaScoreboardObjectiveTranslator.java | 4 +- .../java/scoreboard/JavaTeamTranslator.java | 2 +- .../scoreboard/JavaUpdateScoreTranslator.java | 2 +- .../world/JavaNotifyClientTranslator.java | 31 +--- .../java/world/JavaUpdateTimeTranslator.java | 4 +- .../translators/world/GeyserWorldManager.java | 86 +++++++++ .../translators/world/WorldManager.java | 55 ++++++ .../geysermc/connector/utils/GameRule.java | 123 +++++++++++++ .../connector/utils/SettingsUtils.java | 163 ++++++++++++++++++ .../geysermc/connector/utils/SkinUtils.java | 14 +- 29 files changed, 668 insertions(+), 83 deletions(-) rename connector/src/main/java/org/geysermc/connector/network/session/cache/{ScoreboardCache.java => WorldCache.java} (78%) rename connector/src/main/java/org/geysermc/connector/network/translators/{world/CachedChunkManager.java => bedrock/BedrockServerSettingsRequestTranslator.java} (55%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => entity}/BedrockEntityEventTranslator.java (98%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => entity/player}/BedrockActionTranslator.java (99%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => entity/player}/BedrockEmoteTranslator.java (96%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => entity/player}/BedrockInteractTranslator.java (99%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => entity/player}/BedrockMovePlayerTranslator.java (98%) rename connector/src/main/java/org/geysermc/connector/network/translators/bedrock/{ => world}/BedrockLevelSoundEventTranslator.java (97%) create mode 100644 connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java create mode 100644 connector/src/main/java/org/geysermc/connector/utils/GameRule.java create mode 100644 connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java index 7871f00603c..0e7eab3513b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java @@ -25,17 +25,19 @@ package org.geysermc.platform.spigot.world; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import lombok.AllArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.utils.GameRule; import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13; import us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData; @AllArgsConstructor -public class GeyserSpigotWorldManager extends WorldManager { +public class GeyserSpigotWorldManager extends GeyserWorldManager { private final boolean isLegacy; // You need ViaVersion to connect to an older server with Geyser. @@ -69,4 +71,19 @@ public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boo return BlockTranslator.AIR; } } + + @Override + public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { + return Boolean.parseBoolean(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID())); + } + + @Override + public int getGameRuleInt(GeyserSession session, GameRule gameRule) { + return Integer.parseInt(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID())); + } + + @Override + public boolean hasPermission(GeyserSession session, String permission) { + return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission); + } } diff --git a/connector/pom.xml b/connector/pom.xml index 17c9711d9ae..ad8b82211af 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -96,6 +96,12 @@ 8.3.1 compile + + com.nukkitx.fastutil + fastutil-object-object-maps + 8.3.1 + compile + com.google.guava guava diff --git a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java index eb8bf967e43..b6a766a3bec 100644 --- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java +++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java @@ -30,14 +30,14 @@ import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.network.translators.world.CachedChunkManager; +import org.geysermc.connector.network.translators.world.GeyserWorldManager; import org.geysermc.connector.network.translators.world.WorldManager; import java.nio.file.Path; public interface GeyserBootstrap { - CachedChunkManager DEFAULT_CHUNK_MANAGER = new CachedChunkManager(); + GeyserWorldManager DEFAULT_CHUNK_MANAGER = new GeyserWorldManager(); /** * Called when the GeyserBootstrap is enabled diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index 424f51870e8..52b2735137b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -30,6 +30,7 @@ import com.github.steveice10.mc.protocol.data.message.TextMessage; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.AdventureSetting; import com.nukkitx.protocol.bedrock.data.AttributeData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; @@ -47,10 +48,7 @@ import org.geysermc.connector.utils.AttributeUtils; import org.geysermc.connector.utils.MessageUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; @Getter @Setter @@ -95,7 +93,7 @@ public void spawnEntity(GeyserSession session) { addPlayerPacket.setMotion(motion); addPlayerPacket.setHand(hand); addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.NORMAL); - addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.VISITOR); + addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); addPlayerPacket.getMetadata().putAll(metadata); @@ -212,7 +210,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s if (entityMetadata.getId() == 2) { // System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet()); - for (Team team : session.getScoreboardCache().getScoreboard().getTeams().values()) { + for (Team team : session.getWorldCache().getScoreboard().getTeams().values()) { // session.getConnector().getLogger().info("team name " + team.getName()); // session.getConnector().getLogger().info("team entities " + team.getEntities()); } @@ -221,7 +219,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s if (name != null) { username = MessageUtils.getBedrockMessage(name); } - Team team = session.getScoreboardCache().getScoreboard().getTeamFor(username); + Team team = session.getWorldCache().getScoreboard().getTeamFor(username); if (team != null) { // session.getConnector().getLogger().info("team name es " + team.getName() + " with prefix " + team.getPrefix() + " and suffix " + team.getSuffix()); metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix()); diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index dd9f48d6a74..357e870f6a1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -34,6 +34,7 @@ import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.utils.LoginEncryptionUtils; import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.utils.SettingsUtils; public class UpstreamPacketHandler extends LoggingPacketHandler { @@ -91,6 +92,10 @@ public boolean handle(ResourcePackClientResponsePacket packet) { @Override public boolean handle(ModalFormResponsePacket packet) { + if (packet.getFormId() == SettingsUtils.SETTINGS_FORM_ID) { + return SettingsUtils.handleSettingsForm(session, packet.getFormData()); + } + return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData()); } 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 340292e254b..ac186a79905 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 @@ -46,6 +46,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.*; +import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; @@ -54,6 +55,7 @@ import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import lombok.Getter; import lombok.Setter; +import org.geysermc.common.window.CustomFormWindow; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; @@ -79,9 +81,7 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @Getter @@ -102,7 +102,7 @@ public class GeyserSession implements CommandSender { private ChunkCache chunkCache; private EntityCache entityCache; private InventoryCache inventoryCache; - private ScoreboardCache scoreboardCache; + private WorldCache worldCache; private WindowCache windowCache; @Setter private TeleportCache teleportCache; @@ -191,6 +191,41 @@ public class GeyserSession implements CommandSender { private MinecraftProtocol protocol; + private boolean reducedDebugInfo = false; + + @Setter + private CustomFormWindow settingsForm; + + /** + * The op permission level set by the server + */ + @Setter + private int opPermissionLevel = 0; + + /** + * If the current player can fly + */ + @Setter + private boolean canFly = false; + + /** + * If the current player is flying + */ + @Setter + private boolean flying = false; + + /** + * If the current player is in noclip + */ + @Setter + private boolean noClip = false; + + /** + * If the current player can not interact with the world + */ + @Setter + private boolean worldImmutable = false; + public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { this.connector = connector; this.upstream = new UpstreamSession(bedrockServerSession); @@ -198,7 +233,7 @@ public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServ this.chunkCache = new ChunkCache(this); this.entityCache = new EntityCache(this); this.inventoryCache = new InventoryCache(this); - this.scoreboardCache = new ScoreboardCache(this); + this.worldCache = new WorldCache(this); this.windowCache = new WindowCache(this); this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO); @@ -440,7 +475,7 @@ public void disconnect(String reason) { this.chunkCache = null; this.entityCache = null; - this.scoreboardCache = null; + this.worldCache = null; this.inventoryCache = null; this.windowCache = null; @@ -605,4 +640,66 @@ public void sendDownstreamPacket(Packet packet) { connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server"); } } + + /** + * Update the cached value for the reduced debug info gamerule. + * This also toggles the coordinates display + * + * @param value The new value for reducedDebugInfo + */ + public void setReducedDebugInfo(boolean value) { + worldCache.setShowCoordinates(!value); + reducedDebugInfo = value; + } + + /** + * Send a gamerule value to the client + * + * @param gameRule The gamerule to send + * @param value The value of the gamerule + */ + public void sendGameRule(String gameRule, Object value) { + GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); + gameRulesChangedPacket.getGameRules().add(new GameRuleData<>(gameRule, value)); + upstream.sendPacket(gameRulesChangedPacket); + } + + /** + * @see org.geysermc.connector.network.translators.world.WorldManager#hasPermission(GeyserSession, String) + */ + public Boolean hasPermission(String permission) { + return connector.getWorldManager().hasPermission(this, permission); + } + + /** + * Send an AdventureSettingsPacket to the client with the latest flags + */ + public void sendAdventureSettings() { + AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); + adventureSettingsPacket.setUniqueEntityId(playerEntity.getGeyserId()); + adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); + adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); + + Set flags = new HashSet<>(); + if (canFly) { + flags.add(AdventureSetting.MAY_FLY); + } + + if (flying) { + flags.add(AdventureSetting.FLYING); + } + + if (worldImmutable) { + flags.add(AdventureSetting.WORLD_IMMUTABLE); + } + + if (noClip) { + flags.add(AdventureSetting.NO_CLIP); + } + + flags.add(AdventureSetting.AUTO_JUMP); + + adventureSettingsPacket.getSettings().addAll(flags); + sendUpstreamPacket(adventureSettingsPacket); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java similarity index 78% rename from connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java rename to connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java index 9a6924075ef..310e5f9d7f7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java @@ -25,7 +25,9 @@ package org.geysermc.connector.network.session.cache; +import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import lombok.Getter; +import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.scoreboard.Objective; import org.geysermc.connector.scoreboard.Scoreboard; @@ -33,11 +35,18 @@ import java.util.Collection; @Getter -public class ScoreboardCache { +public class WorldCache { + private GeyserSession session; + + @Setter + private Difficulty difficulty = Difficulty.EASY; + + private boolean showCoordinates = true; + private Scoreboard scoreboard; - public ScoreboardCache(GeyserSession session) { + public WorldCache(GeyserSession session) { this.session = session; this.scoreboard = new Scoreboard(session); } @@ -52,4 +61,14 @@ public void removeScoreboard() { } } } + + /** + * Tell the client to hide or show the coordinates + * + * @param value True to show, false to hide + */ + public void setShowCoordinates(boolean value) { + showCoordinates = value; + session.sendGameRule("showcoordinates", value); + } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java similarity index 55% rename from connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java index 0580fcffdac..a8591cd7f90 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java @@ -23,15 +23,25 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.world; +package org.geysermc.connector.network.translators.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.nukkitx.protocol.bedrock.packet.ServerSettingsRequestPacket; +import com.nukkitx.protocol.bedrock.packet.ServerSettingsResponsePacket; 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.utils.SettingsUtils; -public class CachedChunkManager extends WorldManager { +@Translator(packet = ServerSettingsRequestPacket.class) +public class BedrockServerSettingsRequestTranslator extends PacketTranslator { @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - return session.getChunkCache().getBlockAt(new Position(x, y, z)); + public void translate(ServerSettingsRequestPacket packet, GeyserSession session) { + SettingsUtils.buildForm(session); + + ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket(); + serverSettingsResponsePacket.setFormData(session.getSettingsForm().getJSONData()); + serverSettingsResponsePacket.setFormId(SettingsUtils.SETTINGS_FORM_ID); + session.sendUpstreamPacket(serverSettingsResponsePacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java similarity index 98% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java index 620e2b8a51e..18fd6614ee1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.entity; import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; import com.github.steveice10.mc.protocol.data.game.window.WindowType; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java similarity index 99% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java index 2e1a122ec07..f4365f7963e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.entity.player; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java similarity index 96% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java index f07016e701f..e76fece0b59 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.entity.player; import com.nukkitx.protocol.bedrock.packet.EmotePacket; import org.geysermc.connector.GeyserConnector; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java similarity index 99% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java index 856b01eecb9..c5d6f2dda7a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.entity.player; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java similarity index 98% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java index 0abf8150571..be918ba74c4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.entity.player; import com.nukkitx.math.vector.Vector3d; import org.geysermc.connector.common.ChatColor; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java similarity index 97% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java index 08ad10bfbc8..44553e82e28 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.bedrock.world; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDifficultyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDifficultyTranslator.java index 7e4d9ca8622..601b0fc488c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDifficultyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDifficultyTranslator.java @@ -40,5 +40,7 @@ public void translate(ServerDifficultyPacket packet, GeyserSession session) { SetDifficultyPacket setDifficultyPacket = new SetDifficultyPacket(); setDifficultyPacket.setDifficulty(packet.getDifficulty().ordinal()); session.sendUpstreamPacket(setDifficultyPacket); + + session.getWorldCache().setDifficulty(packet.getDifficulty()); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java index 94b5bed38d0..da107f48df5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java @@ -56,7 +56,7 @@ public void translate(ServerJoinGamePacket packet, GeyserSession session) { DimensionUtils.switchDimension(session, fakeDim); DimensionUtils.switchDimension(session, packet.getDimension()); - session.getScoreboardCache().removeScoreboard(); + session.getWorldCache().removeScoreboard(); } AdventureSettingsPacket bedrockPacket = new AdventureSettingsPacket(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java index 109e00e29dc..ac2a80f7a87 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java @@ -31,6 +31,7 @@ import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -51,6 +52,33 @@ public void translate(ServerEntityStatusPacket packet, GeyserSession session) { EntityEventPacket entityEventPacket = new EntityEventPacket(); entityEventPacket.setRuntimeEntityId(entity.getGeyserId()); switch (packet.getStatus()) { + case PLAYER_ENABLE_REDUCED_DEBUG: + session.setReducedDebugInfo(true); + return; + case PLAYER_DISABLE_REDUCED_DEBUG: + session.setReducedDebugInfo(false); + return; + case PLAYER_OP_PERMISSION_LEVEL_0: + session.setOpPermissionLevel(0); + session.sendAdventureSettings(); + return; + case PLAYER_OP_PERMISSION_LEVEL_1: + session.setOpPermissionLevel(1); + session.sendAdventureSettings(); + return; + case PLAYER_OP_PERMISSION_LEVEL_2: + session.setOpPermissionLevel(2); + session.sendAdventureSettings(); + return; + case PLAYER_OP_PERMISSION_LEVEL_3: + session.setOpPermissionLevel(3); + session.sendAdventureSettings(); + return; + case PLAYER_OP_PERMISSION_LEVEL_4: + session.setOpPermissionLevel(4); + session.sendAdventureSettings(); + return; + // EntityEventType.HURT sends extra data depending on the type of damage. However this appears to have no visual changes case LIVING_BURN: case LIVING_DROWN: diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerAbilitiesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerAbilitiesTranslator.java index a569acff802..0f5a12e5add 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerAbilitiesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerAbilitiesTranslator.java @@ -32,6 +32,7 @@ import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -43,24 +44,12 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator playerFlags = new ObjectOpenHashSet<>(); - playerFlags.add(AdventureSetting.AUTO_JUMP); - if (packet.isCanFly()) - playerFlags.add(AdventureSetting.MAY_FLY); - - if (packet.isFlying()) - playerFlags.add(AdventureSetting.FLYING); - - AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); - adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); - // Required or the packet simply is not sent - adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); - adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId()); - adventureSettingsPacket.getSettings().addAll(playerFlags); - session.sendUpstreamPacket(adventureSettingsPacket); + session.setCanFly(packet.isCanFly()); + session.setFlying(packet.isFlying()); + session.sendAdventureSettings(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java index 5a722953ac9..3ee174d7a8e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java @@ -36,7 +36,7 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator { public void translate(ServerTeamPacket packet, GeyserSession session) { GeyserConnector.getInstance().getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers())); - Scoreboard scoreboard = session.getScoreboardCache().getScoreboard(); + Scoreboard scoreboard = session.getWorldCache().getScoreboard(); Team team = scoreboard.getTeam(packet.getTeamName()); switch (packet.getAction()) { case CREATE: diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java index 827e4c7f4b9..8d7d59a892c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java @@ -42,7 +42,7 @@ public class JavaUpdateScoreTranslator extends PacketTranslator playerFlags = new ObjectOpenHashSet<>(); GameMode gameMode = (GameMode) packet.getValue(); - if (gameMode == GameMode.ADVENTURE) - playerFlags.add(AdventureSetting.WORLD_IMMUTABLE); - if (gameMode == GameMode.CREATIVE) - playerFlags.add(AdventureSetting.MAY_FLY); - - if (gameMode == GameMode.SPECTATOR) { - playerFlags.add(AdventureSetting.MAY_FLY); - playerFlags.add(AdventureSetting.NO_CLIP); - playerFlags.add(AdventureSetting.FLYING); - playerFlags.add(AdventureSetting.WORLD_IMMUTABLE); - gameMode = GameMode.CREATIVE; // spectator doesnt exist on bedrock - } - - playerFlags.add(AdventureSetting.AUTO_JUMP); + session.setNoClip(gameMode == GameMode.SPECTATOR); + session.setWorldImmutable(gameMode == GameMode.ADVENTURE || gameMode == GameMode.SPECTATOR); + session.sendAdventureSettings(); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); playerGameTypePacket.setGamemode(gameMode.ordinal()); session.sendUpstreamPacket(playerGameTypePacket); session.setGameMode(gameMode); - // We need to delay this because otherwise it's overridden by the adventure settings from the abilities packet - session.getConnector().getGeneralThreadPool().schedule(() -> { - AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); - adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); - adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); - adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId()); - adventureSettingsPacket.getSettings().addAll(playerFlags); - session.sendUpstreamPacket(adventureSettingsPacket); - }, 50, TimeUnit.MILLISECONDS); - // Update the crafting grid to add/remove barriers for creative inventory PlayerInventoryTranslator.updateCraftingGrid(session, session.getInventory()); break; 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 188e960d6d5..8dc68918550 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 @@ -67,9 +67,7 @@ public void translate(ServerUpdateTimePacket packet, GeyserSession session) { } private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) { - GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); - gameRulesChangedPacket.getGameRules().add(new GameRuleData<>("dodaylightcycle", doCycle)); - session.sendUpstreamPacket(gameRulesChangedPacket); + session.sendGameRule("dodaylightcycle", doCycle); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java new file mode 100644 index 00000000000..83f1a7783f8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.world; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.GameRule; + +public class GeyserWorldManager extends WorldManager { + + private static final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); + + @Override + public int getBlockAt(GeyserSession session, int x, int y, int z) { + return session.getChunkCache().getBlockAt(new Position(x, y, z)); + } + + @Override + public void setGameRule(GeyserSession session, String name, Object value) { + session.sendDownstreamPacket(new ClientChatPacket("/gamerule " + name + " " + value)); + gameruleCache.put(name, String.valueOf(value)); + } + + @Override + public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { + String value = gameruleCache.get(gameRule.getJavaID()); + if (value != null) { + return Boolean.parseBoolean(value); + } + + return gameRule.getDefaultValue() != null ? (Boolean) gameRule.getDefaultValue() : false; + } + + @Override + public int getGameRuleInt(GeyserSession session, GameRule gameRule) { + String value = gameruleCache.get(gameRule.getJavaID()); + if (value != null) { + return Integer.parseInt(value); + } + + return gameRule.getDefaultValue() != null ? (int) gameRule.getDefaultValue() : 0; + } + + @Override + public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { + session.sendDownstreamPacket(new ClientChatPacket("/gamemode " + gameMode.name().toLowerCase())); + } + + @Override + public void setDifficulty(GeyserSession session, Difficulty difficulty) { + session.sendDownstreamPacket(new ClientChatPacket("/difficulty " + difficulty.name().toLowerCase())); + } + + @Override + public boolean hasPermission(GeyserSession session, String permission) { + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java index 325e686091c..3260122778b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java @@ -26,8 +26,11 @@ package org.geysermc.connector.network.translators.world; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.GameRule; /** * Class that manages or retrieves various information @@ -70,4 +73,56 @@ public int getBlockAt(GeyserSession session, Vector3i vector) { * @return the block state at the specified location */ public abstract int getBlockAt(GeyserSession session, int x, int y, int z); + + /** + * Updates a gamerule value on the Java server + * + * @param session The session of the user that requested the change + * @param name The gamerule to change + * @param value The new value for the gamerule + */ + public abstract void setGameRule(GeyserSession session, String name, Object value); + + /** + * Get a gamerule value as a boolean + * + * @param session The session of the user that requested the value + * @param gameRule The gamerule to fetch the value of + * @return The boolean representation of the value + */ + public abstract Boolean getGameRuleBool(GeyserSession session, GameRule gameRule); + + /** + * Get a gamerule value as an integer + * + * @param session The session of the user that requested the value + * @param gameRule The gamerule to fetch the value of + * @return The integer representation of the value + */ + public abstract int getGameRuleInt(GeyserSession session, GameRule gameRule); + + /** + * Change the game mode of the given session + * + * @param session The session of the player to change the game mode of + * @param gameMode The game mode to change the player to + */ + public abstract void setPlayerGameMode(GeyserSession session, GameMode gameMode); + + /** + * Change the difficulty of the Java server + * + * @param session The session of the user that requested the change + * @param difficulty The difficulty to change to + */ + public abstract void setDifficulty(GeyserSession session, Difficulty difficulty); + + /** + * Checks if the given session's player has a permission + * + * @param session The session of the player to check the permission of + * @param permission The permission node to check + * @return True if the player has the requested permission, false if not + */ + public abstract boolean hasPermission(GeyserSession session, String permission); } diff --git a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java new file mode 100644 index 00000000000..350337f3d7e --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.utils; + +import lombok.Getter; + +/** + * This enum stores each gamerule along with the value type and the default. + * It is used to construct the list for the settings menu + */ +public enum GameRule { + ANNOUNCEADVANCEMENTS("announceAdvancements", Boolean.class, true), // JE only + COMMANDBLOCKOUTPUT("commandBlockOutput", Boolean.class, true), + DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", Boolean.class, false), // JE only + DISABLERAIDS("disableRaids", Boolean.class, false), // JE only + DODAYLIGHTCYCLE("doDaylightCycle", Boolean.class, true), + DOENTITYDROPS("doEntityDrops", Boolean.class, true), + DOFIRETICK("doFireTick", Boolean.class, true), + DOIMMEDIATERESPAWN("doImmediateRespawn", Boolean.class, false), + DOINSOMNIA("doInsomnia", Boolean.class, true), + DOLIMITEDCRAFTING("doLimitedCrafting", Boolean.class, false), // JE only + DOMOBLOOT("doMobLoot", Boolean.class, true), + DOMOBSPAWNING("doMobSpawning", Boolean.class, true), + DOPATROLSPAWNING("doPatrolSpawning", Boolean.class, true), // JE only + DOTILEDROPS("doTileDrops", Boolean.class, true), + DOTRADERSPAWNING("doTraderSpawning", Boolean.class, true), // JE only + DOWEATHERCYCLE("doWeatherCycle", Boolean.class, true), + DROWNINGDAMAGE("drowningDamage", Boolean.class, true), + FALLDAMAGE("fallDamage", Boolean.class, true), + FIREDAMAGE("fireDamage", Boolean.class, true), + FORGIVEDEADPLAYERS("forgiveDeadPlayers", Boolean.class, true), // JE only + KEEPINVENTORY("keepInventory", Boolean.class, false), + LOGADMINCOMMANDS("logAdminCommands", Boolean.class, true), // JE only + MAXCOMMANDCHAINLENGTH("maxCommandChainLength", Integer.class, 65536), + MAXENTITYCRAMMING("maxEntityCramming", Integer.class, 24), // JE only + MOBGRIEFING("mobGriefing", Boolean.class, true), + NATURALREGENERATION("naturalRegeneration", Boolean.class, true), + RANDOMTICKSPEED("randomTickSpeed", Integer.class, 3), + REDUCEDDEBUGINFO("reducedDebugInfo", Boolean.class, false), // JE only + SENDCOMMANDFEEDBACK("sendCommandFeedback", Boolean.class, true), + SHOWDEATHMESSAGES("showDeathMessages", Boolean.class, true), + SPAWNRADIUS("spawnRadius", Integer.class, 10), + SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", Boolean.class, true), // JE only + UNIVERSALANGER("universalAnger", Boolean.class, false), // JE only + + UNKNOWN("unknown", Object.class); + + private static final GameRule[] VALUES = values(); + + @Getter + private String javaID; + + @Getter + private Class type; + + @Getter + private Object defaultValue; + + GameRule(String javaID, Class type) { + this(javaID, type, null); + } + + GameRule(String javaID, Class type, Object defaultValue) { + this.javaID = javaID; + this.type = type; + this.defaultValue = defaultValue; + } + + /** + * Convert a string to an object of the correct type for the current gamerule + * + * @param value The string value to convert + * @return The converted and formatted value + */ + public Object convertValue(String value) { + if (type.equals(Boolean.class)) { + return Boolean.parseBoolean(value); + } else if (type.equals(Integer.class)) { + return Integer.parseInt(value); + } + + return null; + } + + /** + * Fetch a game rule by the given Java ID + * + * @param id The ID of the gamerule + * @return A {@link GameRule} object representing the requested ID or {@link GameRule.UNKNOWN} + */ + public static GameRule fromJavaID(String id) { + for (GameRule gamerule : VALUES) { + if (gamerule.javaID.equals(id)) { + return gamerule; + } + } + + return UNKNOWN; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java new file mode 100644 index 00000000000..89e9fe67b7f --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.utils; + +import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import org.geysermc.common.window.CustomFormBuilder; +import org.geysermc.common.window.CustomFormWindow; +import org.geysermc.common.window.button.FormImage; +import org.geysermc.common.window.component.DropdownComponent; +import org.geysermc.common.window.component.InputComponent; +import org.geysermc.common.window.component.LabelComponent; +import org.geysermc.common.window.component.ToggleComponent; +import org.geysermc.common.window.response.CustomFormResponse; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.ArrayList; + +public class SettingsUtils { + + // Used in UpstreamPacketHandler.java + public static final int SETTINGS_FORM_ID = 1338; + + /** + * Build a settings form for the given session and store it for later + * + * @param session The session to build the form for + */ + public static void buildForm(GeyserSession session) { + // Cache the language for cleaner access + String language = session.getClientData().getLanguageCode(); + + CustomFormBuilder builder = new CustomFormBuilder(LanguageUtils.getPlayerLocaleString("geyser.settings.title.main", language)); + builder.setIcon(new FormImage(FormImage.FormImageType.PATH, "textures/ui/settings_glyph_color_2x.png")); + + builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.client", language))); + builder.addComponent(new ToggleComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.option.coordinates", language, session.getWorldCache().isShowCoordinates()))); + + + if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { + builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.server", language))); + + DropdownComponent gamemodeDropdown = new DropdownComponent(); + gamemodeDropdown.setText("%createWorldScreen.gameMode.personal"); + gamemodeDropdown.setOptions(new ArrayList<>()); + for (GameMode gamemode : GameMode.values()) { + gamemodeDropdown.addOption(LocaleUtils.getLocaleString("selectWorld.gameMode." + gamemode.name().toLowerCase(), language), session.getGameMode() == gamemode); + } + builder.addComponent(gamemodeDropdown); + + DropdownComponent difficultyDropdown = new DropdownComponent(); + difficultyDropdown.setText("%options.difficulty"); + difficultyDropdown.setOptions(new ArrayList<>()); + for (Difficulty difficulty : Difficulty.values()) { + difficultyDropdown.addOption("%options.difficulty." + difficulty.name().toLowerCase(), session.getWorldCache().getDifficulty() == difficulty); + } + builder.addComponent(difficultyDropdown); + } + + if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) { + builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.game_rules", language))); + for (GameRule gamerule : GameRule.values()) { + if (gamerule.equals(GameRule.UNKNOWN)) { + continue; + } + + // Add the relevant form item based on the gamerule type + if (Boolean.class.equals(gamerule.getType())) { + builder.addComponent(new ToggleComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), GeyserConnector.getInstance().getWorldManager().getGameRuleBool(session, gamerule))); + } else if (Integer.class.equals(gamerule.getType())) { + builder.addComponent(new InputComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), "", String.valueOf(GeyserConnector.getInstance().getWorldManager().getGameRuleInt(session, gamerule)))); + } + } + } + + session.setSettingsForm(builder.build()); + } + + /** + * Handle the settings form response + * + * @param session The session that sent the response + * @param response The response string to parse + * @return True if the form was parsed correctly, false if not + */ + public static boolean handleSettingsForm(GeyserSession session, String response) { + CustomFormWindow settingsForm = session.getSettingsForm(); + settingsForm.setResponse(response); + + CustomFormResponse settingsResponse = (CustomFormResponse) settingsForm.getResponse(); + int offset = 0; + + offset++; // Client settings title + + session.getWorldCache().setShowCoordinates(settingsResponse.getToggleResponses().get(offset)); + offset++; + + if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { + offset++; // Server settings title + + GameMode gameMode = GameMode.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()]; + if (gameMode != null && gameMode != session.getGameMode()) { + session.getConnector().getWorldManager().setPlayerGameMode(session, gameMode); + } + offset++; + + Difficulty difficulty = Difficulty.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()]; + if (difficulty != null && difficulty != session.getWorldCache().getDifficulty()) { + session.getConnector().getWorldManager().setDifficulty(session, difficulty); + } + offset++; + } + + if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) { + offset++; // Game rule title + + for (GameRule gamerule : GameRule.values()) { + if (gamerule.equals(GameRule.UNKNOWN)) { + continue; + } + + if (Boolean.class.equals(gamerule.getType())) { + Boolean value = settingsResponse.getToggleResponses().get(offset).booleanValue(); + if (value != session.getConnector().getWorldManager().getGameRuleBool(session, gamerule)) { + session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value); + } + } else if (Integer.class.equals(gamerule.getType())) { + int value = Integer.parseInt(settingsResponse.getInputResponses().get(offset)); + if (value != session.getConnector().getWorldManager().getGameRuleInt(session, gamerule)) { + session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value); + } + } + offset++; + } + } + + return true; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java index 77ab7f9393c..1d5e4073de0 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -35,6 +35,7 @@ import lombok.Getter; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.auth.BedrockClientData; @@ -93,6 +94,15 @@ public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, U ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId ); + // This attempts to find the xuid of the player so profile images show up for xbox accounts + String xuid = ""; + for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { + if (player.getPlayerEntity().getUuid().equals(uuid)) { + xuid = player.getAuthData().getXboxUUID(); + break; + } + } + PlayerListPacket.Entry entry; // If we are building a PlayerListEntry for our own session we use our AuthData UUID instead of the Java UUID @@ -102,11 +112,11 @@ public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, U } else { entry = new PlayerListPacket.Entry(uuid); } - + entry.setName(username); entry.setEntityId(geyserId); entry.setSkin(serializedSkin); - entry.setXuid(""); + entry.setXuid(xuid); entry.setPlatformChatId(""); entry.setTeacher(false); entry.setTrustedSkin(true); From 04cf8b2a995fb2c352bcf7a289eaee6435efcacc Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 8 Aug 2020 17:56:15 -0500 Subject: [PATCH 20/37] Fix javadoc errors --- .../main/java/org/geysermc/connector/GeyserLogger.java | 6 ++++++ .../connector/network/session/GeyserSession.java | 5 ++++- .../java/org/geysermc/connector/utils/FileUtils.java | 1 + .../java/org/geysermc/connector/utils/GameRule.java | 2 +- .../org/geysermc/connector/utils/InventoryUtils.java | 3 +++ .../org/geysermc/connector/utils/MessageUtils.java | 10 +++++----- 6 files changed, 20 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/GeyserLogger.java b/connector/src/main/java/org/geysermc/connector/GeyserLogger.java index 2ea45a49533..0ba2a689f94 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserLogger.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserLogger.java @@ -36,6 +36,9 @@ public interface GeyserLogger { /** * Logs a severe message and an exception to console + * + * @param message the message to log + * @param error the error to throw */ void severe(String message, Throwable error); @@ -48,6 +51,9 @@ public interface GeyserLogger { /** * Logs an error message and an exception to console + * + * @param message the message to log + * @param error the error to throw */ void error(String message, Throwable error); 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 ac186a79905..05465c46b6d 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 @@ -665,7 +665,10 @@ public void sendGameRule(String gameRule, Object value) { } /** - * @see org.geysermc.connector.network.translators.world.WorldManager#hasPermission(GeyserSession, String) + * Checks if the given session's player has a permission + * + * @param permission The permission node to check + * @return true if the player has the requested permission, false if not */ public Boolean hasPermission(String permission) { return connector.getWorldManager().hasPermission(this, permission); diff --git a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java index 0b7b5c5cf09..38369d6c823 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java @@ -42,6 +42,7 @@ public class FileUtils { * * @param src File to load * @param valueType Class to load file into + * @param the type * @return The data as the given class * @throws IOException if the config could not be loaded */ diff --git a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java index 350337f3d7e..48feb1c18bf 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java +++ b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java @@ -109,7 +109,7 @@ public Object convertValue(String value) { * Fetch a game rule by the given Java ID * * @param id The ID of the gamerule - * @return A {@link GameRule} object representing the requested ID or {@link GameRule.UNKNOWN} + * @return A {@link GameRule} object representing the requested ID or {@link GameRule#UNKNOWN} */ public static GameRule fromJavaID(String id) { for (GameRule gamerule : VALUES) { 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 6d83da0ad53..cb51e2f3b6d 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -136,6 +136,9 @@ public static boolean canStack(ItemData item1, ItemData item2) { /** * Returns a barrier block with custom name and lore to explain why * part of the inventory is unusable. + * + * @param description the description + * @return the unusable space block */ public static ItemData createUnusableSpaceBlock(String description) { NbtMapBuilder root = NbtMap.builder(); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 0b49589504b..36cdbc422b4 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -95,7 +95,7 @@ public class MessageUtils { * @param messages A {@link List} of {@link Message} to parse * @param locale A locale loaded to get the message for * @param parent A {@link Message} to use as the parent (can be null) - * @return + * @return the translation parameters */ public static List getTranslationParams(List messages, String locale, Message parent) { List strings = new ArrayList<>(); @@ -160,10 +160,10 @@ public static String getTranslatedBedrockMessage(Message message, String locale, * Translate a given {@link TranslationMessage} to the given locale * * @param message The {@link Message} to send - * @param locale - * @param shouldTranslate - * @param parent - * @return + * @param locale the locale + * @param shouldTranslate if the message should be translated + * @param parent the parent message + * @return the given translation message translated from the given locale */ public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate, Message parent) { JsonParser parser = new JsonParser(); From 3ef7e30230bf82a1f3989fb53016ae1bb979e2c0 Mon Sep 17 00:00:00 2001 From: Savagetechguy Date: Sat, 8 Aug 2020 17:59:03 -0500 Subject: [PATCH 21/37] Fix fire not extinguishing on server side when on bedrock Fixes #875 Fixes #906 --- .../entity/player/BedrockActionTranslator.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java index f4365f7963e..536bad98855 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java @@ -119,6 +119,18 @@ public void translate(PlayerActionPacket packet, GeyserSession session) { // Handled in BedrockInventoryTransactionTranslator break; case START_BREAK: + if (session.getConnector().getConfig().isCacheChunks()) { + if (packet.getFace() == BlockFace.UP.ordinal()) { + int blockUp = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().add(0, 1, 0)); + String identifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockUp); + if (identifier.startsWith("minecraft:fire") || identifier.startsWith("minecraft:soul_fire")) { + ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(), + packet.getBlockPosition().getY() + 1, packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]); + session.sendDownstreamPacket(startBreakingPacket); + break; + } + } + } ClientPlayerActionPacket startBreakingPacket = new ClientPlayerActionPacket(PlayerAction.START_DIGGING, new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), BlockFace.values()[packet.getFace()]); session.sendDownstreamPacket(startBreakingPacket); From 6e80f22ee9522e66cdce1d933d235679339d2960 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Sun, 9 Aug 2020 22:43:57 -0400 Subject: [PATCH 22/37] Update to 1.16.2-rc1 --- connector/pom.xml | 2 +- .../java/JavaJoinGameTranslator.java | 7 ++--- .../java/JavaRespawnTranslator.java | 7 ++--- .../connector/utils/DimensionUtils.java | 26 ++++++++++++++++++- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index f78cc875053..7997efadeef 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -105,7 +105,7 @@ com.github.GeyserMC MCProtocolLib - da148409ff + 2ee53b72d1 compile diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java index 94b5bed38d0..06fa2016f60 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java @@ -51,10 +51,11 @@ public void translate(ServerJoinGamePacket packet, GeyserSession session) { entity.setEntityId(packet.getEntityId()); // If the player is already initialized and a join game packet is sent, they // are swapping servers + String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); if (session.isSpawned()) { String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD; DimensionUtils.switchDimension(session, fakeDim); - DimensionUtils.switchDimension(session, packet.getDimension()); + DimensionUtils.switchDimension(session, newDimension); session.getScoreboardCache().removeScoreboard(); } @@ -91,8 +92,8 @@ public void translate(ServerJoinGamePacket packet, GeyserSession session) { ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); session.sendDownstreamPacket(clientSettingsPacket); - if (!packet.getDimension().equals(entity.getDimension())) { - DimensionUtils.switchDimension(session, packet.getDimension()); + if (!newDimension.equals(entity.getDimension())) { + DimensionUtils.switchDimension(session, newDimension); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java index 6d03380821f..2f7dead77d6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java @@ -65,13 +65,14 @@ public void translate(ServerRespawnPacket packet, GeyserSession session) { stopRainPacket.setPosition(Vector3f.ZERO); session.sendUpstreamPacket(stopRainPacket); - if (!entity.getDimension().equals(packet.getDimension())) { - DimensionUtils.switchDimension(session, packet.getDimension()); + String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); + if (!entity.getDimension().equals(newDimension)) { + DimensionUtils.switchDimension(session, newDimension); } else { if (session.isManyDimPackets()) { //reloading world String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD; DimensionUtils.switchDimension(session, fakeDim); - DimensionUtils.switchDimension(session, packet.getDimension()); + DimensionUtils.switchDimension(session, newDimension); } else { // Handled in JavaPlayerPositionRotationTranslator session.setSpawned(false); diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index 74db16bb586..bcbc4ce0dd6 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -26,8 +26,13 @@ package org.geysermc.connector.utils; import com.github.steveice10.mc.protocol.data.game.entity.Effect; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket; +import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; +import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; @@ -99,6 +104,25 @@ public static int javaToBedrock(String javaDimension) { } } + /** + * Determines the new dimension based on the {@link CompoundTag} sent by either the {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket} + * or {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket}. + * @param dimensionTag the packet's dimension tag. + * @return the dimension identifier. + */ + public static String getNewDimension(CompoundTag dimensionTag) { + if (dimensionTag == null || dimensionTag.isEmpty()) { + GeyserConnector.getInstance().getLogger().debug("Dimension tag was null or empty."); + return "minecraft:overworld"; + } + if (dimensionTag.getValue().get("effects") != null) { + System.out.println(((StringTag) dimensionTag.getValue().get("effects")).getValue()); + return ((StringTag) dimensionTag.getValue().get("effects")).getValue(); + } + GeyserConnector.getInstance().getLogger().debug("Effects portion of the tag was null or empty."); + return "minecraft:overworld"; + } + public static void changeBedrockNetherId() { // Change dimension ID to the End to allow for building above Bedrock BEDROCK_NETHER_ID = 2; From 439027d510146caef6ebdece92b9caa3f794cca3 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 10 Aug 2020 15:31:08 +0100 Subject: [PATCH 23/37] Fix Shulker color and open state (#1113) --- .../entity/living/monster/ShulkerEntity.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java index 8728547fc08..a0bd5bc2b1e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java @@ -53,14 +53,21 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s metadata.put(EntityData.SHULKER_ATTACH_POS, Vector3i.from(position.getX(), position.getY(), position.getZ())); } } - //TODO Outdated metadata flag SHULKER_PEAK_HEIGHT -// if (entityMetadata.getId() == 17) { -// int height = (byte) entityMetadata.getValue(); -// metadata.put(EntityData.SHULKER_PEAK_HEIGHT, height); -// } + + if (entityMetadata.getId() == 17) { + int height = (byte) entityMetadata.getValue(); + metadata.put(EntityData.SHULKER_PEEK_ID, height); + } + if (entityMetadata.getId() == 18) { - int color = Math.abs((byte) entityMetadata.getValue() - 15); - metadata.put(EntityData.VARIANT, color); + byte color = (byte) entityMetadata.getValue(); + if (color == 16) { + // 16 is default on both editions + metadata.put(EntityData.VARIANT, 16); + } else { + // Every other shulker color is offset 15 in bedrock edition + metadata.put(EntityData.VARIANT, Math.abs(color - 15)); + } } super.updateBedrockMetadata(entityMetadata, session); } From 9ac13f37b7c4458ccf342b0f9c664588d841f936 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+DoctorMacc@users.noreply.github.com> Date: Mon, 10 Aug 2020 10:31:39 -0400 Subject: [PATCH 24/37] Update submodules (#1109) --- connector/src/main/resources/languages | 2 +- connector/src/main/resources/mappings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index 7cc503e2f7c..bd69044f8f6 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 7cc503e2f7c0871a24beb3a114726d764a4836f1 +Subproject commit bd69044f8f69783bd9a7d8b4922b9122044a2a1e diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index a222d85dc0b..e7c7f5f52d1 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit a222d85dc0b8e8c95a150f2d488a6a25390b8c2f +Subproject commit e7c7f5f52d11537c234e63dd46009f68a9b8d9a1 From c7958af1dbbb4a3f5a81d8530b6566b1c69fa994 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 10 Aug 2020 15:31:49 +0100 Subject: [PATCH 25/37] Fix dust particles type (#1108) --- .../translators/java/world/JavaSpawnParticleTranslator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java index 323f57f07b1..453e08445dd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java @@ -78,7 +78,7 @@ public void translate(ServerSpawnParticlePacket packet, GeyserSession session) { int r = (int) (data.getRed()*255); int g = (int) (data.getGreen()*255); int b = (int) (data.getBlue()*255); - particle.setType(LevelEventType.PARTICLE_FALLING_DUST); + particle.setType(LevelEventType.PARTICLE_REDSTONE); particle.setData(((0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)); particle.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); session.sendUpstreamPacket(particle); From a676e86f6cd9b0d0d4e4ed74943868af05732059 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Mon, 10 Aug 2020 11:22:59 -0400 Subject: [PATCH 26/37] Remove debug line --- .../main/java/org/geysermc/connector/utils/DimensionUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index bcbc4ce0dd6..de09ed8c659 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -116,7 +116,6 @@ public static String getNewDimension(CompoundTag dimensionTag) { return "minecraft:overworld"; } if (dimensionTag.getValue().get("effects") != null) { - System.out.println(((StringTag) dimensionTag.getValue().get("effects")).getValue()); return ((StringTag) dimensionTag.getValue().get("effects")).getValue(); } GeyserConnector.getInstance().getLogger().debug("Effects portion of the tag was null or empty."); From b84986a502df07052612aa8564504db3e657bf1c Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 10 Aug 2020 21:44:20 +0100 Subject: [PATCH 27/37] Fix quotes breaking formatted message strings (#1118) --- .../main/java/org/geysermc/connector/utils/LanguageUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java index 61e23470db7..de6796a262c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java @@ -122,7 +122,7 @@ public static String getPlayerLocaleString(String key, String locale, Object... formatString = key; } - return MessageFormat.format(formatString.replace("&", "\u00a7"), values); + return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values); } /** From afc7dfeb4518442351844807ae3a0c9115e45b82 Mon Sep 17 00:00:00 2001 From: EasyClifton <63668444+EasyClifton@users.noreply.github.com> Date: Tue, 11 Aug 2020 12:57:49 +0300 Subject: [PATCH 28/37] Add Command Block and Structure block to the fix list (#1119) * Add Command Block and Structure block to the fix list * Add Horse Inventory to the fix list Added Horse to the What's left to be added/fixed list. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 0d474d990bf..1f4562258d2 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,9 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - [ ] Beacon - [ ] Cartography Table - [ ] Stonecutter + - [ ] Command Block + - [ ] Structure Block + - [ ] Horse Inventory - Some Entity Flags ## Compiling From 009381d9c77cd2586d10432a70f154937f16243e Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 09:06:28 -0400 Subject: [PATCH 29/37] Update for protocol v409 --- connector/pom.xml | 2 +- .../src/main/java/org/geysermc/connector/GeyserConnector.java | 4 ++-- connector/src/main/resources/languages | 2 +- connector/src/main/resources/mappings | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/connector/pom.xml b/connector/pom.xml index 7997efadeef..ff6101b329a 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -32,7 +32,7 @@ com.nukkitx.protocol - bedrock-v408 + bedrock-v409 2.6.0-SNAPSHOT compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 4de3751006d..693244799b4 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -30,7 +30,7 @@ import com.nukkitx.network.raknet.RakNetConstants; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; -import com.nukkitx.protocol.bedrock.v408.Bedrock_v408; +import com.nukkitx.protocol.bedrock.v409.Bedrock_v409; import lombok.Getter; import lombok.Setter; import org.geysermc.connector.bootstrap.GeyserBootstrap; @@ -75,7 +75,7 @@ public class GeyserConnector { public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); - public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v408.V408_CODEC; + public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v409.V409_CODEC; public static final String NAME = "Geyser"; public static final String VERSION = "DEV"; // A fallback for running in IDEs diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index 7cc503e2f7c..bd69044f8f6 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 7cc503e2f7c0871a24beb3a114726d764a4836f1 +Subproject commit bd69044f8f69783bd9a7d8b4922b9122044a2a1e diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 16eedef89e2..e7c7f5f52d1 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 16eedef89e2a28ca5a1edbfb068008740efa7286 +Subproject commit e7c7f5f52d11537c234e63dd46009f68a9b8d9a1 From 953fe8fec3f3b6b92e8f6c1b155a85d2912ab354 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 09:09:29 -0400 Subject: [PATCH 30/37] Update mappings --- connector/src/main/resources/mappings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index e7c7f5f52d1..94d30c1c6c4 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit e7c7f5f52d11537c234e63dd46009f68a9b8d9a1 +Subproject commit 94d30c1c6c4518932b813826bfcef680575a3c9c From 6ccf629a8ae9f5c573a60379c775f7282ead4951 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 10:00:14 -0400 Subject: [PATCH 31/37] Update to 1.16.2-rc2; add multiversion support --- connector/pom.xml | 2 +- .../geysermc/connector/GeyserConnector.java | 4 -- .../command/defaults/VersionCommand.java | 3 +- .../org/geysermc/connector/dump/DumpInfo.java | 5 +- .../connector/network/BedrockProtocol.java | 66 +++++++++++++++++++ .../network/ConnectorServerEventHandler.java | 3 +- .../connector/network/QueryPacketHandler.java | 2 +- .../network/UpstreamPacketHandler.java | 20 ++++-- 8 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java diff --git a/connector/pom.xml b/connector/pom.xml index 3d5c098ae11..dd1ad1921c5 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -111,7 +111,7 @@ com.github.GeyserMC MCProtocolLib - 2ee53b72d1 + 82dcf31d03 compile diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 693244799b4..103faf79154 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -28,9 +28,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.nukkitx.network.raknet.RakNetConstants; -import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; -import com.nukkitx.protocol.bedrock.v409.Bedrock_v409; import lombok.Getter; import lombok.Setter; import org.geysermc.connector.bootstrap.GeyserBootstrap; @@ -75,8 +73,6 @@ public class GeyserConnector { public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); - public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v409.V409_CODEC; - public static final String NAME = "Geyser"; public static final String VERSION = "DEV"; // A fallback for running in IDEs diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java index 50527968d3b..681474a982b 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java @@ -30,6 +30,7 @@ import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.common.ChatColor; +import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.WebUtils; @@ -50,7 +51,7 @@ public VersionCommand(GeyserConnector connector, String name, String description @Override public void execute(CommandSender sender, String[] args) { - sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.version", GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.version", GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); // Disable update checking in dev mode //noinspection ConstantConditions - changes in production diff --git a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java index 9c4928414ba..9d91cde6b56 100644 --- a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java +++ b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java @@ -32,6 +32,7 @@ import lombok.Getter; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.network.BedrockProtocol; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.FileUtils; @@ -136,8 +137,8 @@ public static class MCInfo { private final int javaProtocol; MCInfo() { - this.bedrockVersion = GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion(); - this.bedrockProtocol = GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion(); + this.bedrockVersion = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion(); + this.bedrockProtocol = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion(); this.javaVersion = MinecraftConstants.GAME_VERSION; this.javaProtocol = MinecraftConstants.PROTOCOL_VERSION; } diff --git a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java new file mode 100644 index 00000000000..734bea436d9 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network; + +import com.nukkitx.protocol.bedrock.BedrockPacketCodec; +import com.nukkitx.protocol.bedrock.v407.Bedrock_v407; +import com.nukkitx.protocol.bedrock.v409.Bedrock_v409; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Contains information about the supported Bedrock protocols in Geyser. + */ +public class BedrockProtocol { + /** + * Default Bedrock codec that should act as a fallback and as the version shown in /geyser version + */ + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v409.V409_CODEC; + /** + * A list of all supported Bedrock versions that can join Geyser + */ + public static final Set SUPPORTED_BEDROCK_CODECS = ConcurrentHashMap.newKeySet(); + + static { + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v407.V407_CODEC); + } + + /** + * Gets the {@link BedrockPacketCodec} of the given protocol version. + * @param protocolVersion The protocol version to attempt to find + * @return The packet codec, or null if the client's protocol is unsupported + */ + public static BedrockPacketCodec getBedrockCodec(int protocolVersion) { + for (BedrockPacketCodec packetCodec : SUPPORTED_BEDROCK_CODECS) { + if (packetCodec.getProtocolVersion() == protocolVersion) { + return packetCodec; + } + } + return null; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java index 6ca9063c222..c850fc4ab5d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java @@ -71,7 +71,7 @@ public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { pong.setEdition("MCPE"); pong.setGameType("Default"); pong.setNintendoLimited(false); - pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()); + pong.setProtocolVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()); pong.setVersion(null); // Server tries to connect either way and it looks better pong.setIpv4Port(config.getBedrock().getPort()); @@ -108,7 +108,6 @@ public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { public void onSessionCreation(BedrockServerSession bedrockServerSession) { bedrockServerSession.setLogging(true); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession))); - bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java index 7854f14c0f7..bd67fd1b55f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -167,7 +167,7 @@ private byte[] getGameData() { gameData.put("hostname", motd); gameData.put("gametype", "SMP"); gameData.put("game_id", "MINECRAFT"); - gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); + gameData.put("version", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); gameData.put("plugins", ""); gameData.put("map", GeyserConnector.NAME); gameData.put("numplayers", currentPlayerCount); diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 357e870f6a1..f65b3ef1abb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -26,6 +26,7 @@ package org.geysermc.connector.network; import com.nukkitx.protocol.bedrock.BedrockPacket; +import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.configuration.GeyserConfiguration; @@ -48,15 +49,20 @@ private boolean translateAndDefault(BedrockPacket packet) { @Override public boolean handle(LoginPacket loginPacket) { - if (loginPacket.getProtocolVersion() > GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) { - // Too early to determine session locale - session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion())); - return true; - } else if (loginPacket.getProtocolVersion() < GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) { - session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion())); - return true; + BedrockPacketCodec packetCodec = BedrockProtocol.getBedrockCodec(loginPacket.getProtocolVersion()); + if (packetCodec == null) { + if (loginPacket.getProtocolVersion() > BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { + // Too early to determine session locale + session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); + return true; + } else if (loginPacket.getProtocolVersion() < BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { + session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); + return true; + } } + session.getUpstream().getSession().setPacketCodec(packetCodec); + LoginEncryptionUtils.encryptPlayerConnection(connector, session, loginPacket); PlayStatusPacket playStatus = new PlayStatusPacket(); From 8b691d22d53fc33c7699406135343fbabc5d2508 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 12:16:18 -0400 Subject: [PATCH 32/37] Add v408 as the default protocol smh mojang --- .../java/org/geysermc/connector/network/BedrockProtocol.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java index 734bea436d9..904f70a0a04 100644 --- a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java +++ b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java @@ -27,6 +27,7 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.v407.Bedrock_v407; +import com.nukkitx.protocol.bedrock.v408.Bedrock_v408; import com.nukkitx.protocol.bedrock.v409.Bedrock_v409; import java.util.Set; @@ -39,7 +40,7 @@ public class BedrockProtocol { /** * Default Bedrock codec that should act as a fallback and as the version shown in /geyser version */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v409.V409_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v408.V408_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -48,6 +49,7 @@ public class BedrockProtocol { static { SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v407.V407_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v409.V409_CODEC); } /** From 31fec1d4bf88fa9b33b85fd028abc082e5f64415 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 12:35:45 -0400 Subject: [PATCH 33/37] Update to 1.16.2 --- bootstrap/spigot/pom.xml | 2 +- connector/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 854ce9fa54c..ca9958d0a4e 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -26,7 +26,7 @@ us.myles viaversion - 3.1.0-1.16.2-pre1 + 3.1.0 provided diff --git a/connector/pom.xml b/connector/pom.xml index dd1ad1921c5..711e74bb17b 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -111,7 +111,7 @@ com.github.GeyserMC MCProtocolLib - 82dcf31d03 + b835436e20 compile From 016a5c04ea57decfcaaaccfd08f7e7cfdbdd9995 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 11 Aug 2020 18:45:14 +0100 Subject: [PATCH 34/37] Fix chat translation parameters not having color sometimes --- .../connector/utils/MessageUtils.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java index 36cdbc422b4..a127fd8db19 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -110,14 +110,6 @@ public static List getTranslationParams(List messages, String l strings.add(builder); } - if (translation.getKey().equals("commands.gamemode.success.other")) { - strings.add(""); - } - - if (translation.getKey().equals("command.context.here")) { - strings.add(" - no permission or invalid command!"); - } - // Collect all params and add format corrections to the end of them List furtherParams = new ArrayList<>(); for (String param : getTranslationParams(translation.getWith(), locale, message)) { @@ -133,9 +125,16 @@ public static List getTranslationParams(List messages, String l } if (locale != null) { - strings.add(insertParams(LocaleUtils.getLocaleString(translation.getKey(), locale), furtherParams)); + String builder = getFormat(message.getStyle().getFormats()) + + getColor(message.getStyle().getColor()); + builder += insertParams(LocaleUtils.getLocaleString(translation.getKey(), locale), furtherParams); + strings.add(builder); } else { - strings.addAll(furtherParams); + String format = getFormat(message.getStyle().getFormats()) + + getColor(message.getStyle().getColor()); + for (String param : furtherParams) { + strings.add(format + param); + } } } else { String builder = getFormat(message.getStyle().getFormats()) + From 41d299fae59399f29d5d05281e6f5b57c41130e4 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Tue, 11 Aug 2020 19:10:48 +0100 Subject: [PATCH 35/37] Change version number to 1.1.0 --- README.md | 2 +- bootstrap/bungeecord/pom.xml | 4 ++-- bootstrap/pom.xml | 2 +- bootstrap/spigot/pom.xml | 4 ++-- bootstrap/sponge/pom.xml | 4 ++-- bootstrap/standalone/pom.xml | 4 ++-- bootstrap/velocity/pom.xml | 4 ++-- common/pom.xml | 2 +- connector/pom.xml | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1f4562258d2..64ff22522d9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here! -### Currently supporting Minecraft Bedrock v1.16.0/1 and Minecraft Java v1.16.1. +### Currently supporting Minecraft Bedrock v1.16.x and Minecraft Java v1.16.2. ## Setting Up Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser. diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 565264f0f49..8497b9684ee 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.0.0 + 1.1.0 ../ bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc connector - 1.0.0 + 1.1.0 compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 85ede3466d9..d9bac67d160 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -10,7 +10,7 @@ ../ bootstrap-parent - 1.0.0 + 1.1.0 pom diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index ca9958d0a4e..422b2769b44 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.0.0 + 1.1.0 ../ bootstrap-spigot @@ -14,7 +14,7 @@ org.geysermc connector - 1.0.0 + 1.1.0 compile diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index cca3fcaae78..f3c898084e9 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.0.0 + 1.1.0 ../ bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc connector - 1.0.0 + 1.1.0 compile diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index 468042b8ffa..07458f7300f 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.0.0 + 1.1.0 ../ bootstrap-standalone @@ -14,7 +14,7 @@ org.geysermc connector - 1.0.0 + 1.1.0 compile diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 7c42ba3362f..b08e5cbc55a 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 1.0.0 + 1.1.0 ../ bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc connector - 1.0.0 + 1.1.0 compile diff --git a/common/pom.xml b/common/pom.xml index 0df8ef4bf6c..85dde12c665 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -10,7 +10,7 @@ ../ common - 1.0.0 + 1.1.0 com.google.code.gson diff --git a/connector/pom.xml b/connector/pom.xml index 711e74bb17b..ff5bc6174a7 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -10,12 +10,12 @@ ../ connector - 1.0.0 + 1.1.0 org.geysermc common - 1.0.0 + 1.1.0 compile From 5db0e7898faee12e729511be50e5e6abd0026f77 Mon Sep 17 00:00:00 2001 From: DoctorMacc Date: Tue, 11 Aug 2020 14:33:37 -0400 Subject: [PATCH 36/37] Bump MCProtocolLib --- connector/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connector/pom.xml b/connector/pom.xml index ff5bc6174a7..6cc46f0039a 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -111,7 +111,7 @@ com.github.GeyserMC MCProtocolLib - b835436e20 + 82c20c954c compile From 3da1427853b60a2ad2eba9f7cad789302e4ef1d3 Mon Sep 17 00:00:00 2001 From: bundabrg Date: Wed, 12 Aug 2020 10:00:39 +0800 Subject: [PATCH 37/37] Fix Skin Selfie --- .../src/main/java/org/geysermc/connector/utils/SkinUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java index 1d5e4073de0..e9e9995efc5 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -264,8 +264,6 @@ public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSessio } public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientData clientData) { - GameProfileData data = GameProfileData.from(playerEntity.getProfile()); - GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.register", playerEntity.getUsername(), playerEntity.getUuid())); try { @@ -276,7 +274,7 @@ public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientDat byte[] geometryBytes = Base64.getDecoder().decode(clientData.getGeometryData().getBytes("UTF-8")); if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) { - SkinProvider.storeBedrockSkin(playerEntity.getUuid(), data.getSkinUrl(), skinBytes); + SkinProvider.storeBedrockSkin(playerEntity.getUuid(), clientData.getSkinId(), skinBytes); SkinProvider.storeBedrockGeometry(playerEntity.getUuid(), geometryNameBytes, geometryBytes); } else { GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.fail", playerEntity.getUsername()));