mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-11 17:30:44 +01:00
Merge remote-tracking branch 'fork/floodgate-2.0' into floodgate-2.0
# Conflicts: # connector/src/main/java/org/geysermc/connector/utils/PluginMessageUtils.java
This commit is contained in:
commit
0e7dca551e
16 changed files with 219 additions and 161 deletions
|
@ -3,7 +3,7 @@
|
||||||
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/)
|
[![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)
|
[![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/)
|
[![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)
|
[![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/)
|
[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate") == null) {
|
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"));
|
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||||
return;
|
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
|
// Floodgate installed means that the user wants Floodgate authentication
|
||||||
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
||||||
geyserConfig.getRemote().setAuthType("floodgate");
|
geyserConfig.getRemote().setAuthType("floodgate");
|
||||||
|
|
|
@ -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"));
|
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||||
this.getPluginLoader().disablePlugin(this);
|
this.getPluginLoader().disablePlugin(this);
|
||||||
return;
|
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
|
// Floodgate installed means that the user wants Floodgate authentication
|
||||||
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
geyserLogger.debug("Auto-setting to Floodgate authentication.");
|
||||||
geyserConfig.getRemote().setAuthType("floodgate");
|
geyserConfig.getRemote().setAuthType("floodgate");
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class FloodgateKeyLoader {
|
||||||
|
|
||||||
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
||||||
if (floodgate != null) {
|
if (floodgate != null) {
|
||||||
Path autoKey = floodgateDataFolder.resolve("public-key.pem");
|
Path autoKey = floodgateDataFolder.resolve("key.pem");
|
||||||
if (Files.exists(autoKey)) {
|
if (Files.exists(autoKey)) {
|
||||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
|
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
|
||||||
floodgateKey = autoKey;
|
floodgateKey = autoKey;
|
||||||
|
|
|
@ -152,8 +152,13 @@ public class GeyserSession implements CommandSender {
|
||||||
@Setter
|
@Setter
|
||||||
private boolean interacting;
|
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). <br>
|
||||||
|
* Initialized as (0, 0, 0) so it is always not-null.
|
||||||
|
*/
|
||||||
@Setter
|
@Setter
|
||||||
private Vector3i lastInteractionPosition;
|
private Vector3i lastInteractionPosition = Vector3i.ZERO;
|
||||||
|
|
||||||
private boolean manyDimPackets = false;
|
private boolean manyDimPackets = false;
|
||||||
private ServerRespawnPacket lastDimPacket = null;
|
private ServerRespawnPacket lastDimPacket = null;
|
||||||
|
@ -189,6 +194,13 @@ public class GeyserSession implements CommandSender {
|
||||||
@Setter
|
@Setter
|
||||||
private long lastHitTime;
|
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;
|
private boolean reducedDebugInfo = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
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.data.inventory.ContainerType;
|
||||||
import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket;
|
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.InventoryTransactionPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.LevelEventPacket;
|
||||||
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
import org.geysermc.connector.entity.CommandBlockMinecartEntity;
|
||||||
|
@ -78,6 +80,17 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
case ITEM_USE:
|
case ITEM_USE:
|
||||||
switch (packet.getActionType()) {
|
switch (packet.getActionType()) {
|
||||||
case 0:
|
case 0:
|
||||||
|
// Check to make sure the client isn't spamming interaction
|
||||||
|
// Based on Nukkit 1.0, with changes to ensure holding down still works
|
||||||
|
boolean hasAlreadyClicked = System.currentTimeMillis() - session.getLastInteractionTime() < 110.0 &&
|
||||||
|
packet.getBlockPosition().distanceSquared(session.getLastInteractionPosition()) < 0.00001;
|
||||||
|
session.setLastInteractionPosition(packet.getBlockPosition());
|
||||||
|
if (hasAlreadyClicked) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Only update the interaction time if it's valid - that way holding down still works.
|
||||||
|
session.setLastInteractionTime(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
// Bedrock sends block interact code for a Java entity so we send entity code back to Java
|
// Bedrock sends block interact code for a Java entity so we send entity code back to Java
|
||||||
if (BlockTranslator.isItemFrame(packet.getBlockRuntimeId()) &&
|
if (BlockTranslator.isItemFrame(packet.getBlockRuntimeId()) &&
|
||||||
|
@ -101,12 +114,24 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
session.sendDownstreamPacket(blockPacket);
|
session.sendDownstreamPacket(blockPacket);
|
||||||
|
|
||||||
// Otherwise boats will not be able to be placed in survival and buckets wont work on mobile
|
// Otherwise boats will not be able to be placed in survival and buckets wont work on mobile
|
||||||
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BOAT.getBedrockId()) {
|
||||||
if (packet.getItemInHand() != null && (packet.getItemInHand().getId() == ItemRegistry.BOAT.getBedrockId() ||
|
|
||||||
packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId()) && !packet.getActions().isEmpty()) {
|
|
||||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
session.sendDownstreamPacket(itemPacket);
|
session.sendDownstreamPacket(itemPacket);
|
||||||
}
|
}
|
||||||
|
// Check actions, otherwise buckets may be activated when block inventories are accessed
|
||||||
|
// But don't check actions if the item damage is 0
|
||||||
|
else if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
||||||
|
(packet.getItemInHand().getDamage() == 0 || !packet.getActions().isEmpty())) {
|
||||||
|
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
|
session.sendDownstreamPacket(itemPacket);
|
||||||
|
|
||||||
|
// Let the server decide if the bucket item should change, not the client, and revert the changes the client made
|
||||||
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
|
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
|
slotPacket.setSlot(packet.getHotbarSlot());
|
||||||
|
slotPacket.setItem(packet.getItemInHand());
|
||||||
|
session.sendUpstreamPacket(slotPacket);
|
||||||
|
}
|
||||||
|
|
||||||
if (packet.getActions().isEmpty()) {
|
if (packet.getActions().isEmpty()) {
|
||||||
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) {
|
||||||
|
@ -153,7 +178,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
session.setLastBlockPlacePosition(blockPos);
|
session.setLastBlockPlacePosition(blockPos);
|
||||||
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
session.setLastBlockPlacedId(handItem.getJavaIdentifier());
|
||||||
}
|
}
|
||||||
session.setLastInteractionPosition(packet.getBlockPosition());
|
|
||||||
session.setInteracting(true);
|
session.setInteracting(true);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -164,14 +188,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handled in ITEM_USE
|
// Handled in ITEM_USE
|
||||||
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId()) {
|
if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId() &&
|
||||||
|
// Normal bucket, water bucket, lava bucket
|
||||||
|
(packet.getItemInHand().getDamage() == 0 || packet.getItemInHand().getDamage() == 8 || packet.getItemInHand().getDamage() == 10)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||||
session.sendDownstreamPacket(useItemPacket);
|
session.sendDownstreamPacket(useItemPacket);
|
||||||
// Used for sleeping in beds
|
|
||||||
session.setLastInteractionPosition(packet.getBlockPosition());
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
int blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ());
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class BedrockRespawnTranslator extends PacketTranslator<RespawnPacket> {
|
||||||
RespawnPacket respawnPacket = new RespawnPacket();
|
RespawnPacket respawnPacket = new RespawnPacket();
|
||||||
respawnPacket.setRuntimeEntityId(0);
|
respawnPacket.setRuntimeEntityId(0);
|
||||||
respawnPacket.setPosition(Vector3f.ZERO);
|
respawnPacket.setPosition(Vector3f.ZERO);
|
||||||
respawnPacket.setState(RespawnPacket.State.SERVER_SEARCHING);
|
respawnPacket.setState(RespawnPacket.State.SERVER_READY);
|
||||||
session.sendUpstreamPacket(respawnPacket);
|
session.sendUpstreamPacket(respawnPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<SetPlayerGameTypePacket> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void translate(SetPlayerGameTypePacket packet, GeyserSession session) {
|
||||||
|
// no
|
||||||
|
SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket();
|
||||||
|
playerGameTypePacket.setGamemode(session.getGameMode().ordinal());
|
||||||
|
session.sendUpstreamPacket(playerGameTypePacket);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.ContainerType;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
|
import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.InventorySource;
|
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.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
|
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 org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -48,7 +45,7 @@ public class CraftingInventoryTranslator extends BlockInventoryTranslator {
|
||||||
@Override
|
@Override
|
||||||
public int bedrockSlotToJava(InventoryActionData action) {
|
public int bedrockSlotToJava(InventoryActionData action) {
|
||||||
if (action.getSlot() == 50) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.entity.player.HandPreference;
|
||||||
import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility;
|
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.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.client.ClientSettingsPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.GameRuleData;
|
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.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.utils.DimensionUtils;
|
import org.geysermc.connector.utils.DimensionUtils;
|
||||||
|
import org.geysermc.connector.utils.PluginMessageUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -92,6 +94,8 @@ public class JavaJoinGameTranslator extends PacketTranslator<ServerJoinGamePacke
|
||||||
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND);
|
ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND);
|
||||||
session.sendDownstreamPacket(clientSettingsPacket);
|
session.sendDownstreamPacket(clientSettingsPacket);
|
||||||
|
|
||||||
|
session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
|
||||||
|
|
||||||
if (!newDimension.equals(entity.getDimension())) {
|
if (!newDimension.equals(entity.getDimension())) {
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.java;
|
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket;
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import org.geysermc.common.form.Form;
|
|
||||||
import org.geysermc.common.form.ModalForm;
|
|
||||||
import org.geysermc.common.form.util.FormAdaptor;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
|
||||||
import org.geysermc.connector.common.AuthType;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
@Translator(packet = ServerPluginMessagePacket.class)
|
|
||||||
public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMessagePacket> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,26 +23,32 @@
|
||||||
* @link https://github.com/GeyserMC/Geyser
|
* @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.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 com.nukkitx.protocol.bedrock.packet.TakeItemEntityPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.entity.ExpOrbEntity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
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)
|
@Translator(packet = ServerEntityCollectItemPacket.class)
|
||||||
public class JavaCollectItemTranslator extends PacketTranslator<ServerEntityCollectItemPacket> {
|
public class JavaEntityCollectItemTranslator extends PacketTranslator<ServerEntityCollectItemPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerEntityCollectItemPacket packet, GeyserSession session) {
|
public void translate(ServerEntityCollectItemPacket packet, GeyserSession session) {
|
||||||
// This is the definition of translating - both packets take the same values
|
// Collected entity is the other entity
|
||||||
TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket();
|
|
||||||
// Collected entity is the item
|
|
||||||
Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId());
|
Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId());
|
||||||
if (collectedEntity == null) return;
|
if (collectedEntity == null) return;
|
||||||
// Collector is the entity picking up the item
|
// Collector is the entity 'picking up' the item
|
||||||
Entity collectorEntity;
|
Entity collectorEntity;
|
||||||
if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) {
|
if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) {
|
||||||
collectorEntity = session.getPlayerEntity();
|
collectorEntity = session.getPlayerEntity();
|
||||||
|
@ -50,8 +56,19 @@ public class JavaCollectItemTranslator extends PacketTranslator<ServerEntityColl
|
||||||
collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId());
|
collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId());
|
||||||
}
|
}
|
||||||
if (collectorEntity == null) return;
|
if (collectorEntity == null) return;
|
||||||
|
if (collectedEntity instanceof ExpOrbEntity) {
|
||||||
|
// Player just picked up an experience orb
|
||||||
|
LevelEventPacket xpPacket = new LevelEventPacket();
|
||||||
|
xpPacket.setType(LevelEventType.SOUND_EXPERIENCE_ORB_PICKUP);
|
||||||
|
xpPacket.setPosition(collectedEntity.getPosition());
|
||||||
|
xpPacket.setData(0);
|
||||||
|
session.sendUpstreamPacket(xpPacket);
|
||||||
|
} else {
|
||||||
|
// Item is being picked up (visual only)
|
||||||
|
TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket();
|
||||||
takeItemEntityPacket.setRuntimeEntityId(collectorEntity.getGeyserId());
|
takeItemEntityPacket.setRuntimeEntityId(collectorEntity.getGeyserId());
|
||||||
takeItemEntityPacket.setItemRuntimeEntityId(collectedEntity.getGeyserId());
|
takeItemEntityPacket.setItemRuntimeEntityId(collectedEntity.getGeyserId());
|
||||||
session.sendUpstreamPacket(takeItemEntityPacket);
|
session.sendUpstreamPacket(takeItemEntityPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -83,7 +83,7 @@ public class Objective {
|
||||||
|
|
||||||
public void setScore(String id, int score) {
|
public void setScore(String id, int score) {
|
||||||
if (scores.containsKey(id)) {
|
if (scores.containsKey(id)) {
|
||||||
scores.get(id).setScore(score).setUpdateType(UpdateType.ADD);
|
scores.get(id).setScore(score);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
registerScore(id, score);
|
registerScore(id, score);
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
package org.geysermc.connector.scoreboard;
|
package org.geysermc.connector.scoreboard;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||||
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
||||||
|
@ -153,6 +152,10 @@ public class Scoreboard {
|
||||||
boolean globalAdd = objective.getUpdateType() == ADD;
|
boolean globalAdd = objective.getUpdateType() == ADD;
|
||||||
boolean globalRemove = objective.getUpdateType() == REMOVE;
|
boolean globalRemove = objective.getUpdateType() == REMOVE;
|
||||||
|
|
||||||
|
// Track if any scores changed
|
||||||
|
// Used to delete and resend scoreboard objectives; otherwise they won't update on Bedrock
|
||||||
|
boolean scoreChanged = false;
|
||||||
|
|
||||||
for (Score score : objective.getScores().values()) {
|
for (Score score : objective.getScores().values()) {
|
||||||
Team team = score.getTeam();
|
Team team = score.getTeam();
|
||||||
|
|
||||||
|
@ -187,6 +190,10 @@ public class Scoreboard {
|
||||||
if (remove) {
|
if (remove) {
|
||||||
removeScores.add(score.getCachedInfo());
|
removeScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (add || remove) {
|
||||||
|
scoreChanged = true;
|
||||||
|
}
|
||||||
// score is pending to be updated, so we use the current score as the old score
|
// score is pending to be updated, so we use the current score as the old score
|
||||||
score.setOldScore(score.getScore());
|
score.setOldScore(score.getScore());
|
||||||
|
|
||||||
|
@ -198,7 +205,7 @@ public class Scoreboard {
|
||||||
score.setUpdateType(NOTHING);
|
score.setUpdateType(NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalRemove || globalUpdate) {
|
if (globalRemove || globalUpdate || scoreChanged) {
|
||||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
session.sendUpstreamPacket(removeObjectivePacket);
|
session.sendUpstreamPacket(removeObjectivePacket);
|
||||||
|
@ -208,7 +215,7 @@ public class Scoreboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalAdd || globalUpdate) {
|
if (globalAdd || globalUpdate || scoreChanged) {
|
||||||
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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 org.geysermc.connector.GeyserConnector;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class PluginMessageUtils {
|
||||||
|
private static final byte[] BRAND_DATA;
|
||||||
|
|
||||||
|
static {
|
||||||
|
byte[] data = GeyserConnector.NAME.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] varInt = writeVarInt(data.length);
|
||||||
|
BRAND_DATA = new byte[varInt.length + data.length];
|
||||||
|
System.arraycopy(varInt, 0, BRAND_DATA, 0, varInt.length);
|
||||||
|
System.arraycopy(data, 0, BRAND_DATA, varInt.length, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the prebuilt brand as a byte array
|
||||||
|
* @return the brand information of the Geyser client
|
||||||
|
*/
|
||||||
|
public static byte[] getGeyserBrandData() {
|
||||||
|
return BRAND_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,9 +34,9 @@ remote:
|
||||||
auth-type: online
|
auth-type: online
|
||||||
|
|
||||||
# Floodgate uses encryption to ensure use from authorised sources.
|
# 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.
|
# 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
|
## the Xbox/MCPE username is the key for the Java server auth-info
|
||||||
## this allows automatic configuration/login to the remote Java server
|
## this allows automatic configuration/login to the remote Java server
|
||||||
|
|
Loading…
Reference in a new issue