diff --git a/README.md b/README.md index ba3e6fc2d..e0404a934 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/Geyser/job/master/) +[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser/job/master/) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) [![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC) [![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/) diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java index 9d8e05ac7..e06640896 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java @@ -97,7 +97,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate") == null) { geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); return; - } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { + } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate") != null) { // Floodgate installed means that the user wants Floodgate authentication geyserLogger.debug("Auto-setting to Floodgate authentication."); geyserConfig.getRemote().setAuthType("floodgate"); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java index a8ae50d69..12794d1c8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java @@ -101,7 +101,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); this.getPluginLoader().disablePlugin(this); return; - } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { + } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate") != null) { // Floodgate installed means that the user wants Floodgate authentication geyserLogger.debug("Auto-setting to Floodgate authentication."); geyserConfig.getRemote().setAuthType("floodgate"); diff --git a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java index ec5dd349a..7bf0ac67f 100644 --- a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java +++ b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java @@ -37,7 +37,7 @@ public class FloodgateKeyLoader { if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) { if (floodgate != null) { - Path autoKey = floodgateDataFolder.resolve("public-key.pem"); + Path autoKey = floodgateDataFolder.resolve("key.pem"); if (Files.exists(autoKey)) { logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); floodgateKey = autoKey; 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 ec8c7f0ee..abb50a560 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 @@ -152,8 +152,13 @@ public class GeyserSession implements CommandSender { @Setter private boolean interacting; + /** + * Stores the last position of the block the player interacted with. This can either be a block that the client + * placed or an existing block the player interacted with (for example, a chest).
+ * Initialized as (0, 0, 0) so it is always not-null. + */ @Setter - private Vector3i lastInteractionPosition; + private Vector3i lastInteractionPosition = Vector3i.ZERO; private boolean manyDimPackets = false; private ServerRespawnPacket lastDimPacket = null; @@ -189,6 +194,13 @@ public class GeyserSession implements CommandSender { @Setter private long lastHitTime; + /** + * 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. + */ + @Setter + private long lastInteractionTime; + private boolean reducedDebugInfo = false; /** diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 95e669572..8e891d925 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -39,8 +39,10 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; +import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.connector.entity.CommandBlockMinecartEntity; @@ -78,6 +80,17 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { RespawnPacket respawnPacket = new RespawnPacket(); respawnPacket.setRuntimeEntityId(0); respawnPacket.setPosition(Vector3f.ZERO); - respawnPacket.setState(RespawnPacket.State.SERVER_SEARCHING); + respawnPacket.setState(RespawnPacket.State.SERVER_READY); session.sendUpstreamPacket(respawnPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java new file mode 100644 index 000000000..d61b37863 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java @@ -0,0 +1,47 @@ +/* + * 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.bedrock.entity.player; + +import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +/** + * In vanilla Bedrock, if you have operator status, this sets the player's gamemode without confirmation from the server. + * Since we have a custom server option to request the gamemode, we just reset the gamemode and ignore this. + */ +@Translator(packet = SetPlayerGameTypePacket.class) +public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator { + + @Override + public void translate(SetPlayerGameTypePacket packet, GeyserSession session) { + // no + SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); + playerGameTypePacket.setGamemode(session.getGameMode().ordinal()); + session.sendUpstreamPacket(playerGameTypePacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index f5ebe62df..b260565b8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -30,12 +30,9 @@ import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.utils.InventoryUtils; import java.util.List; @@ -48,7 +45,7 @@ public class CraftingInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryActionData action) { if (action.getSlot() == 50) { - GeyserConnector.getInstance().getLogger().warning("Slot 50 found, please report: " + action); + // Slot 50 is used for crafting with a controller. return 0; } 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 a8fc122bd..c479b23fe 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 @@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.java; import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; +import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientSettingsPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; import com.nukkitx.protocol.bedrock.data.GameRuleData; @@ -38,6 +39,7 @@ 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.DimensionUtils; +import org.geysermc.connector.utils.PluginMessageUtils; import java.util.Arrays; import java.util.List; @@ -92,6 +94,8 @@ public class JavaJoinGameTranslator extends PacketTranslator { - private static final byte[] brandData; - - static { - byte[] data = GeyserConnector.NAME.getBytes(StandardCharsets.UTF_8); - byte[] varInt = writeVarInt(data.length); - brandData = new byte[varInt.length + data.length]; - System.arraycopy(varInt, 0, brandData, 0, varInt.length); - System.arraycopy(data, 0, brandData, varInt.length, data.length); - } - - private static byte[] writeVarInt(int value) { - byte[] data = new byte[getVarIntLength(value)]; - int index = 0; - do { - byte temp = (byte) (value & 0b01111111); - value >>>= 7; - if (value != 0) { - temp |= 0b10000000; - } - data[index] = temp; - index++; - } while (value != 0); - return data; - } - - private static int getVarIntLength(int number) { - if ((number & 0xFFFFFF80) == 0) { - return 1; - } else if ((number & 0xFFFFC000) == 0) { - return 2; - } else if ((number & 0xFFE00000) == 0) { - return 3; - } else if ((number & 0xF0000000) == 0) { - return 4; - } - return 5; - } - - @Override - public void translate(ServerPluginMessagePacket packet, GeyserSession session) { - String channel = packet.getChannel(); - - if (channel.equals("minecraft:brand")) { - session.sendDownstreamPacket( - new ClientPluginMessagePacket(channel, brandData) - ); - } - - // Floodgate plugin messages - if (session.getConnector().getAuthType() != AuthType.FLOODGATE) { - return; - } - - if (channel.equals("floodgate:form")) { - byte[] data = packet.getData(); - - // receive: first byte is form type, second and third are the id, remaining is the form data - // respond: first and second byte id, remaining is form response data - - Form.Type type = Form.Type.getByOrdinal(data[0]); - if (type == null) { - throw new NullPointerException( - "Got type " + data[0] + " which isn't a valid form type!"); - } - - String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8); - - Form form = new GsonBuilder().registerTypeAdapter(ModalForm.class, new FormAdaptor()).create().fromJson(dataString, type.getTypeClass()); - form.setResponseHandler(response -> { - byte[] raw = response.getBytes(StandardCharsets.UTF_8); - byte[] finalData = new byte[raw.length + 2]; - - finalData[0] = data[1]; - finalData[1] = data[2]; - System.arraycopy(raw, 0, finalData, 2, raw.length); - - session.sendDownstreamPacket(new ClientPluginMessagePacket(channel, finalData)); - }); - session.sendForm(form); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java similarity index 61% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java index a90c7016b..270c33a7a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java @@ -23,26 +23,32 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.java.world; +package org.geysermc.connector.network.translators.java.entity; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityCollectItemPacket; +import com.nukkitx.protocol.bedrock.data.LevelEventType; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.TakeItemEntityPacket; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.ExpOrbEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +/** + * This packet is called whenever a player picks up an item. + * In Java, this is called for item entities, experience orbs and arrows + * Bedrock uses it for arrows and item entities, but not experience orbs. + */ @Translator(packet = ServerEntityCollectItemPacket.class) -public class JavaCollectItemTranslator extends PacketTranslator { +public class JavaEntityCollectItemTranslator extends PacketTranslator { @Override public void translate(ServerEntityCollectItemPacket packet, GeyserSession session) { - // This is the definition of translating - both packets take the same values - TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket(); - // Collected entity is the item + // Collected entity is the other entity Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId()); if (collectedEntity == null) return; - // Collector is the entity picking up the item + // Collector is the entity 'picking up' the item Entity collectorEntity; if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) { collectorEntity = session.getPlayerEntity(); @@ -50,8 +56,19 @@ public class JavaCollectItemTranslator extends PacketTranslator>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + data[index] = temp; + index++; + } while (value != 0); + return data; + } + + private static int getVarIntLength(int number) { + if ((number & 0xFFFFFF80) == 0) { + return 1; + } else if ((number & 0xFFFFC000) == 0) { + return 2; + } else if ((number & 0xFFE00000) == 0) { + return 3; + } else if ((number & 0xF0000000) == 0) { + return 4; + } + return 5; + } +} diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index 0602bb546..b9e6700fc 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -34,9 +34,9 @@ remote: auth-type: online # Floodgate uses encryption to ensure use from authorised sources. -# This should point to the public key generated by Floodgate (Bungee or CraftBukkit) +# This should point to the public key generated by Floodgate (BungeeCord, Spigot or Velocity) # You can ignore this when not using Floodgate. -floodgate-key-file: public-key.pem +floodgate-key-file: key.pem ## the Xbox/MCPE username is the key for the Java server auth-info ## this allows automatic configuration/login to the remote Java server