diff --git a/README.md b/README.md index ab1ff24a..4f6a6d43 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.100 and Minecraft Java v1.16.4. +### Currently supporting Minecraft Bedrock v1.16.100/v1.16.101/v1.16.200 and Minecraft Java v1.16.4. ## Setting Up Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser. @@ -34,16 +34,26 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock ## What's Left to be Added/Fixed -- The Following Inventories - - [ ] Enchantment Table (as a proper GUI) - - [ ] Beacon - - [ ] Cartography Table - - [ ] Stonecutter - - [ ] Structure Block - - [ ] Horse Inventory - - [ ] Loom - - [ ] Smithing Table +- Lecterns +- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) +- Resource pack conversion/CustomModelData - Some Entity Flags +- The Following Inventories + - Enchantment Table (as a proper GUI) + - Beacon + - Cartography Table + - Stonecutter + - Structure Block + - Horse Inventory + - Loom + - Smithing Table + +## What can't be fixed +The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. + +- Custom heads in inventories +- Clickable links in chat +- Glowing effect ## Compiling 1. Clone the repo to your computer diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 86de99ba..2fedca71 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -93,7 +93,16 @@ com.google.code.gson:* - io.netty:* + + io.netty:netty-transport-native-epoll:* + io.netty:netty-transport-native-unix-common:* + io.netty:netty-transport-native-kqueue:* + io.netty:netty-handler:* + io.netty:netty-common:* + io.netty:netty-buffer:* + io.netty:netty-resolver:* + io.netty:netty-transport:* + io.netty:netty-codec:* org.slf4j:* org.ow2.asm:* diff --git a/connector/pom.xml b/connector/pom.xml index 328b209b..24e2983b 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -153,19 +153,25 @@ net.kyori adventure-api - 4.2.0 + 4.3.0 compile net.kyori adventure-text-serializer-gson - 4.2.0 + 4.3.0 compile net.kyori adventure-text-serializer-legacy - 4.2.0 + 4.3.0 + compile + + + net.kyori + adventure-text-serializer-gson-legacy-impl + 4.3.0 compile @@ -230,8 +236,12 @@ - VERSION = ".*" - VERSION = "${project.version} (git-${git.branch}-${git.commit.id.abbrev})" + String VERSION = ".*" + String VERSION = "${project.version} (" + GIT_VERSION + ")" + + + String GIT_VERSION = ".*" + String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}" @@ -249,8 +259,12 @@ - VERSION = ".*" - VERSION = "DEV" + String VERSION = ".*" + String VERSION = "DEV" + + + String GIT_VERSION = ".*" + String GIT_VERSION = "DEV" diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 96c70898..5b447b26 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -44,6 +44,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; +import org.geysermc.connector.network.translators.collision.CollisionTranslator; import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; @@ -54,7 +55,6 @@ import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; -import org.geysermc.connector.network.translators.collision.CollisionTranslator; import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.LanguageUtils; @@ -67,10 +67,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -86,6 +83,7 @@ public class GeyserConnector { .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); public static final String NAME = "Geyser"; + public static final String GIT_VERSION = "DEV"; // A fallback for running in IDEs public static final String VERSION = "DEV"; // A fallback for running in IDEs private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"; @@ -325,6 +323,38 @@ public class GeyserConnector { players.remove(player); } + /** + * Gets a player by their current UUID + * + * @param uuid the uuid + * @return the player or null if there is no player online with this UUID + */ + public GeyserSession getPlayerByUuid(UUID uuid) { + for (GeyserSession session : players) { + if (session.getPlayerEntity().getUuid().equals(uuid)) { + return session; + } + } + + return null; + } + + /** + * Gets a player by their Xbox user identifier + * + * @param xuid the Xbox user identifier + * @return the player or null if there is no player online with this xuid + */ + public GeyserSession getPlayerByXuid(String xuid) { + for (GeyserSession session : players) { + if (session.getAuthData() != null && session.getAuthData().getXboxUUID().equals(xuid)) { + return session; + } + } + + return null; + } + public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) { return new GeyserConnector(platformType, bootstrap); } diff --git a/connector/src/main/java/org/geysermc/connector/command/CommandManager.java b/connector/src/main/java/org/geysermc/connector/command/CommandManager.java index 822b6dea..44e3830b 100644 --- a/connector/src/main/java/org/geysermc/connector/command/CommandManager.java +++ b/connector/src/main/java/org/geysermc/connector/command/CommandManager.java @@ -50,6 +50,7 @@ public abstract class CommandManager { registerCommand(new OffhandCommand(connector, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); registerCommand(new DumpCommand(connector, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version")); + registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java new file mode 100644 index 00000000..8f09c774 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java @@ -0,0 +1,68 @@ +/* + * 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.command.defaults; + +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandSender; +import org.geysermc.connector.command.GeyserCommand; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.SettingsUtils; + +public class SettingsCommand extends GeyserCommand { + + private final GeyserConnector connector; + + public SettingsCommand(GeyserConnector connector, String name, String description, String permission) { + super(name, description, permission); + + this.connector = connector; + } + + @Override + public void execute(CommandSender sender, String[] args) { + // Make sure the sender is a Bedrock edition client + GeyserSession session = null; + if (sender instanceof GeyserSession) { + session = (GeyserSession) sender; + } else { + // Needed for Spigot - sender is not an instance of GeyserSession + for (GeyserSession otherSession : connector.getPlayers()) { + if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) { + session = otherSession; + break; + } + } + } + if (session == null) return; + SettingsUtils.buildForm(session); + session.sendForm(session.getSettingsForm(), SettingsUtils.SETTINGS_FORM_ID); + } + + @Override + public boolean isExecutableOnConsole() { + return 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 963385c9..dfa30ae9 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java @@ -71,6 +71,8 @@ public interface GeyserConfiguration { boolean isShowCooldown(); + boolean isShowCoordinates(); + String getDefaultLocale(); Path getFloodgateKeyPath(); 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 0ff80895..67fa0449 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java @@ -89,6 +89,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("show-cooldown") private boolean showCooldown = true; + @JsonProperty("show-coordinates") + private boolean showCoordinates = true; + @JsonProperty("allow-third-party-ears") private boolean allowThirdPartyEars = false; diff --git a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java index c067416d..5e1fd005 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java @@ -35,6 +35,16 @@ import java.util.concurrent.TimeUnit; public class BoatEntity extends Entity { + /** + * Required when IS_BUOYANT is sent in order for boats to work in the water.
+ * + * Taken from BDS 1.16.200, with the modification of simulate_waves since Java doesn't bob the boat up and down + * like Bedrock. + */ + private static final String BUOYANCY_DATA = "{\"apply_gravity\":true,\"base_buoyancy\":1.0,\"big_wave_probability\":0.02999999932944775," + + "\"big_wave_speed\":10.0,\"drag_down_on_buoyancy_removed\":0.0,\"liquid_blocks\":[\"minecraft:water\"," + + "\"minecraft:flowing_water\"],\"simulate_waves\":false}}"; + private boolean isPaddlingLeft; private float paddleTimeLeft; private boolean isPaddlingRight; @@ -45,6 +55,10 @@ public class BoatEntity extends Entity { public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(90, 0, 90)); + + // Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+ + metadata.put(EntityData.IS_BUOYANT, (byte) 1); + metadata.put(EntityData.BUOYANCY_DATA, BUOYANCY_DATA); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java b/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java index 4b665683..0459ea85 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java @@ -39,6 +39,8 @@ public class EnderCrystalEntity extends Entity { public EnderCrystalEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); + // Bedrock 1.16.100+ - prevents the entity from appearing on fire itself when fire is underneath it + metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java index 41308a0d..4a69c834 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java @@ -36,7 +36,20 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class ItemEntity extends Entity { public ItemEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); + super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation); + } + + @Override + public void setMotion(Vector3f motion) { + if (isOnGround()) + motion = Vector3f.from(motion.getX(), 0, motion.getZ()); + + super.setMotion(motion); + } + + @Override + public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported); } @Override @@ -44,7 +57,7 @@ public class ItemEntity extends Entity { if (entityMetadata.getId() == 7) { AddItemEntityPacket itemPacket = new AddItemEntityPacket(); itemPacket.setRuntimeEntityId(geyserId); - itemPacket.setPosition(position); + itemPacket.setPosition(position.add(0d, this.entityType.getOffset(), 0d)); itemPacket.setMotion(motion); itemPacket.setUniqueEntityId(geyserId); itemPacket.setFromFishing(false); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java index b61aeda9..aadbfc78 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java @@ -53,7 +53,7 @@ public class ArmorStandEntity extends LivingEntity { position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d); } - super.moveAbsolute(session, position, rotation, isOnGround, teleported); + super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()), isOnGround, teleported); } @Override @@ -95,4 +95,10 @@ public class ArmorStandEntity extends LivingEntity { } super.updateBedrockMetadata(entityMetadata, session); } + + @Override + public void spawnEntity(GeyserSession session) { + this.rotation = Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()); + super.spawnEntity(session); + } } 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 a77d3504..3e6b6c72 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 @@ -100,7 +100,7 @@ public enum EntityType { ARMOR_STAND(ArmorStandEntity.class, 61, 1.975f, 0.5f), TRIPOD_CAMERA(Entity.class, 62, 0f), PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f), - ITEM(ItemEntity.class, 64, 0.25f, 0.25f), + ITEM(ItemEntity.class, 64, 0.25f, 0.25f, 0.25f, 0.125f), PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"), FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f), MOVING_BLOCK(Entity.class, 67, 0f), 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 510bba2d..00f94853 100644 --- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -174,7 +174,7 @@ public class QueryPacketHandler { gameData.put("hostname", motd); gameData.put("gametype", "SMP"); gameData.put("game_id", "MINECRAFT"); - gameData.put("version", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); + gameData.put("version", GeyserConnector.NAME + " (" + GeyserConnector.GIT_VERSION + ") " + BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); gameData.put("plugins", ""); gameData.put("map", map); gameData.put("numplayers", currentPlayerCount); 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 1125be84..d30047e0 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 @@ -210,12 +210,6 @@ public class GeyserSession implements CommandSender { @Setter private long lastWindowCloseTime = 0; - /** - * Saves the timestamp of the last keep alive packet - */ - @Setter - private long lastKeepAliveTimestamp = 0; - @Setter private VillagerTrade[] villagerTrades; @Setter @@ -237,6 +231,17 @@ public class GeyserSession implements CommandSender { @Setter private long lastHitTime; + /** + * Saves if the client is steering left on a boat. + */ + @Setter + private boolean steeringLeft; + /** + * Saves if the client is steering right on a boat. + */ + @Setter + private boolean steeringRight; + /** * Store the last time the player interacted. Used to fix a right-click spam bug. * See https://github.com/GeyserMC/Geyser/issues/503 for context. @@ -406,6 +411,8 @@ public class GeyserSession implements CommandSender { // Don't let the client modify the inventory on death // Setting this to true allows keep inventory to work if enabled but doesn't break functionality being false gamerulePacket.getGameRules().add(new GameRuleData<>("keepinventory", true)); + // Ensure client doesn't try and do anything funky; the server handles this for us + gamerulePacket.getGameRules().add(new GameRuleData<>("spawnradius", 0)); upstream.sendPacket(gamerulePacket); } @@ -687,7 +694,7 @@ public class GeyserSession implements CommandSender { startGamePacket.setLightningLevel(0); startGamePacket.setMultiplayerGame(true); startGamePacket.setBroadcastingToLan(true); - startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", true)); + startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", connector.getConfig().isShowCoordinates())); startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC); startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC); startGamePacket.setCommandsEnabled(!connector.getConfig().isXboxAchievementsEnabled()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java index 012582da..0bedaa71 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java @@ -25,23 +25,19 @@ package org.geysermc.connector.network.translators.bedrock; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerSwingArmPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket; import com.nukkitx.protocol.bedrock.packet.AnimatePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; import java.util.concurrent.TimeUnit; @Translator(packet = AnimatePacket.class) public class BedrockAnimateTranslator extends PacketTranslator { - private boolean isSteeringLeft; - private boolean isSteeringRight; - @Override public void translate(AnimatePacket packet, GeyserSession session) { // Stop the player sending animations before they have fully spawned into the server @@ -61,13 +57,13 @@ public class BedrockAnimateTranslator extends PacketTranslator { // These two might need to be flipped, but my recommendation is getting moving working first case ROW_LEFT: // Packet value is a float of how long one has been rowing, so we convert that into a boolean - isSteeringLeft = packet.getRowingTime() > 0.0; - ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); + session.setSteeringLeft(packet.getRowingTime() > 0.0); + ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); session.sendDownstreamPacket(steerLeftPacket); break; case ROW_RIGHT: - isSteeringRight = packet.getRowingTime() > 0.0; - ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); + session.setSteeringRight(packet.getRowingTime() > 0.0); + ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); session.sendDownstreamPacket(steerRightPacket); break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java index fd5e71e9..e1d87f19 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -27,6 +27,8 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket; import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import org.geysermc.connector.entity.BoatEntity; +import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -39,8 +41,14 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator { @Override public void translate(TextPacket packet, GeyserSession session) { - String message = packet.getMessage().replaceAll("^\\.", "/").trim(); + String message = packet.getMessage(); if (MessageTranslator.isTooLong(message, session)) { return; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java index 79ce856a..32a9d6e0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java @@ -25,26 +25,32 @@ package org.geysermc.connector.network.translators.chat; +import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.gson.legacyimpl.NBTLegacyHoverEventSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; -import java.util.*; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; public class MessageTranslator { // These are used for handling the translations of the messages private static final TranslatableComponentRenderer RENDERER = TranslatableComponentRenderer.usingTranslationSource(new MinecraftTranslationRegistry()); - // Construct our own {@link GsonComponentSerializer} encase we need to change anything + // Construct our own {@link GsonComponentSerializer} since we need to change a setting private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.builder() + // Specify that we may be expecting legacy hover events + .legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()) .build(); // Store team colors for player names @@ -61,6 +67,9 @@ public class MessageTranslator { TEAM_FORMATS.put(TeamColor.BOLD, TextDecoration.BOLD); TEAM_FORMATS.put(TeamColor.STRIKETHROUGH, TextDecoration.STRIKETHROUGH); TEAM_FORMATS.put(TeamColor.ITALIC, TextDecoration.ITALIC); + + // Tell MCProtocolLib to use our serializer + DefaultComponentSerializer.set(GSON_SERIALIZER); } /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 14b93436..5e5bc354 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -45,8 +45,39 @@ import java.util.stream.Collectors; @ItemRemapper public class BannerTranslator extends ItemTranslator { + /** + * Holds what a Java ominous banner pattern looks like. + * + * Translating the patterns over to Bedrock does not work effectively, but Bedrock has a dedicated type for + * ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply + * the correct ominous banner pattern if Bedrock pulls the item from creative. + */ + public static final ListTag OMINOUS_BANNER_PATTERN; + private final List appliedItems; + static { + OMINOUS_BANNER_PATTERN = new ListTag("Patterns"); + // Construct what an ominous banner is supposed to look like + OMINOUS_BANNER_PATTERN.add(getPatternTag("mr", 9)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("bs", 8)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("cs", 7)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 8)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("ms", 15)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("hh", 8)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("mc", 8)); + OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 15)); + } + + private static CompoundTag getPatternTag(String pattern, int color) { + StringTag patternType = new StringTag("Pattern", pattern); + IntTag colorTag = new IntTag("Color", color); + CompoundTag tag = new CompoundTag(""); + tag.put(patternType); + tag.put(colorTag); + return tag; + } + public BannerTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values() .stream() @@ -62,7 +93,7 @@ public class BannerTranslator extends ItemTranslator { */ public static NbtList convertBannerPattern(ListTag patterns) { List tagsList = new ArrayList<>(); - for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { + for (Tag patternTag : patterns.getValue()) { NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); if (newPatternTag != null) { tagsList.add(newPatternTag); @@ -134,7 +165,13 @@ public class BannerTranslator extends ItemTranslator { ListTag patterns = blockEntityTag.get("Patterns"); NbtMapBuilder builder = itemData.getTag().toBuilder(); - builder.put("Patterns", convertBannerPattern(patterns)); + if (patterns.equals(OMINOUS_BANNER_PATTERN)) { + // Remove the current patterns and set the ominous banner type + builder.remove("Patterns"); + builder.putInt("Type", 1); + } else { + builder.put("Patterns", convertBannerPattern(patterns)); + } itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build()); } @@ -151,7 +188,14 @@ public class BannerTranslator extends ItemTranslator { ItemStack itemStack = super.translateToJava(itemData, itemEntry); NbtMap nbtTag = itemData.getTag(); - if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) { + if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) { + // Ominous banner pattern + itemStack.getNbt().remove("Type"); + CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); + blockEntityTag.put(OMINOUS_BANNER_PATTERN); + + itemStack.getNbt().put(blockEntityTag); + } else if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) { List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java index 8f524336..2247b55b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java @@ -52,9 +52,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator commandData = new ArrayList<>(); Int2ObjectMap commands = new Int2ObjectOpenHashMap<>(); Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>(); @@ -83,14 +88,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator flags = new ArrayList<>(); + List flags = Collections.emptyList(); // Loop through all the found commands for (int commandID : commands.keySet()) { String commandName = commands.get(commandID); // Create a basic alias - CommandEnumData aliases = new CommandEnumData( commandName + "Aliases", new String[] { commandName.toLowerCase() }, false); + CommandEnumData aliases = new CommandEnumData(commandName + "Aliases", new String[] { commandName.toLowerCase() }, false); // Get and parse all params CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes()); @@ -102,9 +107,7 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator 1)); } else { 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 4620fc11..61651b0b 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 class JavaSpawnParticleTranslator extends PacketTranslator