mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-29 15:49:09 +01:00
commit
2b7c75968b
240 changed files with 6516 additions and 4876 deletions
|
@ -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 joined us here!
|
||||
|
||||
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.220 and Minecraft Java v1.16.4 - v1.16.5.
|
||||
### Currently supporting Minecraft Bedrock 1.17 and Minecraft Java 1.17.
|
||||
|
||||
## Setting Up
|
||||
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
|
||||
|
@ -39,6 +39,8 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
|||
- Some Entity Flags
|
||||
- Structure block UI
|
||||
|
||||
Extended height features can be "supported", but require additional work.
|
||||
|
||||
## What can't be fixed
|
||||
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://github.com/GeyserMC/Geyser/wiki/Current-Limitations) page.
|
||||
|
||||
|
@ -53,6 +55,7 @@ Any contributions are appreciated. Please feel free to reach out to us on [Disco
|
|||
you're interested in helping out with Geyser.
|
||||
|
||||
## Libraries Used:
|
||||
- [Adventure Text Library](https://github.com/KyoriPowered/adventure)
|
||||
- [NukkitX Bedrock Protocol Library](https://github.com/NukkitX/Protocol)
|
||||
- [Steveice10's Java Protocol Library](https://github.com/Steveice10/MCProtocolLib)
|
||||
- [TerminalConsoleAppender](https://github.com/Minecrell/TerminalConsoleAppender)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-bungeecord</artifactId>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -41,7 +41,7 @@ public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration
|
|||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserBungeePlugin plugin) {
|
||||
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee");
|
||||
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
|
|
|
@ -94,10 +94,16 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
|||
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate-bungee") == null) {
|
||||
// Remove this in like a year
|
||||
if (getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) {
|
||||
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
|
|
@ -6,15 +6,22 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-spigot</artifactId>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>viaversion-repo</id>
|
||||
<url>https://repo.viaversion.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -24,9 +31,9 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<groupId>com.viaversion</groupId>
|
||||
<artifactId>viaversion</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>4.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -42,15 +42,10 @@ public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration
|
|||
private Path floodgateKeyPath;
|
||||
|
||||
public void loadFloodgate(GeyserSpigotPlugin plugin) {
|
||||
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit");
|
||||
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate");
|
||||
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||
|
||||
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheChunks() {
|
||||
return true; // We override this as with Bukkit, we have direct access to the server implementation
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
package org.geysermc.platform.spigot;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.geysermc.common.PlatformType;
|
||||
|
@ -46,16 +50,9 @@ import org.geysermc.platform.spigot.command.SpigotCommandSender;
|
|||
import org.geysermc.platform.spigot.world.GeyserSpigot1_11CraftingListener;
|
||||
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||
import org.geysermc.platform.spigot.world.manager.*;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
@ -81,12 +78,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
try {
|
||||
if (!getDataFolder().exists()) {
|
||||
getDataFolder().mkdir();
|
||||
File bukkitConfig = new File("plugins/Geyser-Bukkit/config.yml");
|
||||
if (bukkitConfig.exists()) { // Copy over old configs
|
||||
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copy_bukkit_config"));
|
||||
Files.copy(bukkitConfig.toPath(), new File(getDataFolder().toString() + "/config.yml").toPath());
|
||||
getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copied_bukkit_config"));
|
||||
}
|
||||
}
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||
|
@ -129,11 +120,18 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") == null) {
|
||||
// Remove this in like a year
|
||||
if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) {
|
||||
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
||||
this.getPluginLoader().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate") == null) {
|
||||
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");
|
||||
|
@ -154,12 +152,18 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
|
||||
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
|
||||
|
||||
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
|
||||
boolean isViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null;
|
||||
if (isViaVersion) {
|
||||
if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) {
|
||||
try {
|
||||
// Ensure that we have the latest 4.0.0 changes and not an older ViaVersion version
|
||||
Class.forName("com.viaversion.viaversion.api.ViaManager");
|
||||
} catch (ClassNotFoundException e) {
|
||||
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old",
|
||||
"https://ci.viaversion.com/job/ViaVersion/"));
|
||||
isViaVersion = false;
|
||||
if (this.geyserConfig.isDebugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Used to determine if Block.getBlockData() is present.
|
||||
|
@ -167,11 +171,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
if (isLegacy)
|
||||
geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected; falling back to ViaVersion for block state retrieval.");
|
||||
|
||||
boolean use3dBiomes = isCompatible(Bukkit.getServer().getVersion(), "1.16.0");
|
||||
if (!use3dBiomes) {
|
||||
geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes.");
|
||||
}
|
||||
|
||||
boolean isPre1_12 = !isCompatible(Bukkit.getServer().getVersion(), "1.12.0");
|
||||
// Set if we need to use a different method for getting a player's locale
|
||||
SpigotCommandSender.setUseLegacyLocaleMethod(isPre1_12);
|
||||
|
@ -187,11 +186,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(this);
|
||||
} else {
|
||||
// Post-1.13
|
||||
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes);
|
||||
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this);
|
||||
}
|
||||
} else {
|
||||
// No ViaVersion
|
||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, use3dBiomes);
|
||||
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this);
|
||||
}
|
||||
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
|
||||
} catch (Exception e) {
|
||||
|
@ -213,7 +212,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(this);
|
||||
} else {
|
||||
// Post-1.13
|
||||
this.geyserWorldManager = new GeyserSpigotWorldManager(this, use3dBiomes);
|
||||
this.geyserWorldManager = new GeyserSpigotWorldManager(this);
|
||||
}
|
||||
geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass());
|
||||
}
|
||||
|
@ -323,14 +322,14 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
*/
|
||||
private boolean isViaVersionNeeded() {
|
||||
ProtocolVersion serverVersion = getServerProtocolVersion();
|
||||
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
List<ProtocolPathEntry> protocolList = Via.getManager().getProtocolManager().getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
serverVersion.getVersion());
|
||||
if (protocolList == null) {
|
||||
// No translation needed!
|
||||
return false;
|
||||
}
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,12 @@ import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeDa
|
|||
import com.nukkitx.protocol.bedrock.data.inventory.CraftingData;
|
||||
import com.nukkitx.protocol.bedrock.data.inventory.ItemData;
|
||||
import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
@ -45,12 +51,6 @@ import org.geysermc.connector.GeyserConnector;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemTranslator;
|
||||
import org.geysermc.connector.network.translators.item.RecipeRegistry;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -68,12 +68,12 @@ public class GeyserSpigot1_11CraftingListener implements Listener {
|
|||
/**
|
||||
* The list of all protocols from the client's version to 1.13.
|
||||
*/
|
||||
private final List<Pair<Integer, Protocol>> protocolList;
|
||||
private final List<ProtocolPathEntry> protocolList;
|
||||
|
||||
public GeyserSpigot1_11CraftingListener(GeyserConnector connector) {
|
||||
this.connector = connector;
|
||||
this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
||||
this.protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
this.mappingData1_12to1_13 = Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
||||
this.protocolList = Via.getManager().getProtocolManager().getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
ProtocolVersion.v1_13.getVersion());
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class GeyserSpigot1_11CraftingListener implements Listener {
|
|||
}
|
||||
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
itemId = mappingData.getNewItemId(itemId);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.platform.spigot.world.manager;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
@ -32,8 +34,6 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
||||
import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
|
||||
/**
|
||||
* Used with ViaVersion and pre-1.13.
|
||||
|
@ -54,7 +54,7 @@ public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldMan
|
|||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||
BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class);
|
||||
int blockId = adapter.getBlockAt(player.getWorld(), x, y, z);
|
||||
return getLegacyBlock(storage, blockId, x, y, z);
|
||||
}
|
||||
|
|
|
@ -25,23 +25,19 @@
|
|||
|
||||
package org.geysermc.platform.spigot.world.manager;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.minecraft.Position;
|
||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -60,12 +56,12 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
/**
|
||||
* The list of all protocols from the client's version to 1.13.
|
||||
*/
|
||||
private final List<Pair<Integer, Protocol>> protocolList;
|
||||
private final List<ProtocolPathEntry> protocolList;
|
||||
|
||||
public GeyserSpigot1_12WorldManager(Plugin plugin) {
|
||||
super(plugin, false);
|
||||
this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
||||
this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||
super(plugin);
|
||||
this.mappingData1_12to1_13 = Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getMappingData();
|
||||
this.protocolList = Via.getManager().getProtocolManager().getProtocolPath(CLIENT_PROTOCOL_VERSION,
|
||||
ProtocolVersion.v1_13.getVersion());
|
||||
}
|
||||
|
||||
|
@ -81,7 +77,7 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||
BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class);
|
||||
Block block = player.getWorld().getBlockAt(x, y, z);
|
||||
// Black magic that gets the old block state ID
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
|
@ -109,7 +105,7 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
}
|
||||
}
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
blockId = mappingData.getNewBlockStateId(blockId);
|
||||
}
|
||||
|
@ -117,28 +113,6 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
return blockId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
World world = player.getWorld();
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
|
||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
||||
// Black magic that gets the old block state ID
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return true;
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
package org.geysermc.platform.spigot.world.manager;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
|
@ -37,8 +36,7 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
|||
*/
|
||||
public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
|
||||
public GeyserSpigotFallbackWorldManager(Plugin plugin) {
|
||||
// Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes.
|
||||
super(plugin, false);
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,11 +44,6 @@ public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
|
|||
return BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||
// Do nothing, since we can't do anything with the chunk
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnChunkCache() {
|
||||
return false;
|
||||
|
|
|
@ -26,16 +26,15 @@
|
|||
package org.geysermc.platform.spigot.world.manager;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.data.MappingData;
|
||||
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.platform.spigot.GeyserSpigotPlugin;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.data.MappingData;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -46,18 +45,18 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
|
|||
|
||||
private final Int2IntMap oldToNewBlockId;
|
||||
|
||||
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) {
|
||||
super(plugin, use3dBiomes);
|
||||
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin) {
|
||||
super(plugin);
|
||||
IntList allBlockStates = adapter.getAllBlockStates();
|
||||
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
|
||||
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
|
||||
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
List<ProtocolPathEntry> protocolList = Via.getManager().getProtocolManager().getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
|
||||
serverVersion.getVersion());
|
||||
for (int oldBlockId : allBlockStates) {
|
||||
int newBlockId = oldBlockId;
|
||||
// protocolList should *not* be null; we checked for that before initializing this class
|
||||
for (int i = protocolList.size() - 1; i >= 0; i--) {
|
||||
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
|
||||
MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
|
||||
if (mappingData != null) {
|
||||
newBlockId = mappingData.getNewBlockStateId(newBlockId);
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
|
|||
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
|
||||
protected final SpigotWorldAdapter adapter;
|
||||
|
||||
public GeyserSpigotNativeWorldManager(Plugin plugin, boolean use3dBiomes) {
|
||||
super(plugin, use3dBiomes);
|
||||
public GeyserSpigotNativeWorldManager(Plugin plugin) {
|
||||
super(plugin);
|
||||
adapter = SpigotAdapters.getWorldAdapter();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,18 +25,13 @@
|
|||
|
||||
package org.geysermc.platform.spigot.world.manager;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.nbt.NbtMap;
|
||||
import com.nukkitx.nbt.NbtMapBuilder;
|
||||
import com.nukkitx.nbt.NbtType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Lectern;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
@ -44,17 +39,13 @@ import org.bukkit.entity.Player;
|
|||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.inventory.translators.LecternInventoryTranslator;
|
||||
import org.geysermc.connector.network.translators.world.GeyserWorldManager;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||
import org.geysermc.connector.utils.BlockEntityUtils;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.utils.GameRule;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -67,48 +58,10 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
*/
|
||||
protected static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION;
|
||||
|
||||
/**
|
||||
* Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed.
|
||||
*/
|
||||
private final boolean use3dBiomes;
|
||||
/**
|
||||
* Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs.
|
||||
*
|
||||
* Working with the Biome enum in Spigot poses two problems:
|
||||
* 1: The Biome enum values change in both order and names over the years.
|
||||
* 2: There is no way to get the Minecraft biome ID from the name itself with Spigot.
|
||||
* To solve both of these problems, we store a JSON file of every Biome enum that has existed,
|
||||
* along with its 1.16 biome number.
|
||||
*
|
||||
* The key is the Spigot Biome ordinal; the value is the Minecraft Java biome numerical ID
|
||||
*/
|
||||
private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length);
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public GeyserSpigotWorldManager(Plugin plugin, boolean use3dBiomes) {
|
||||
this.use3dBiomes = use3dBiomes;
|
||||
public GeyserSpigotWorldManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Load the values into the biome-to-ID map
|
||||
InputStream biomeStream = FileUtils.getResource("biomes.json");
|
||||
JsonNode biomes;
|
||||
try {
|
||||
biomes = GeyserConnector.JSON_MAPPER.readTree(biomeStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||
}
|
||||
// Only load in the biomes that are present in this version of Minecraft
|
||||
for (Biome enumBiome : Biome.values()) {
|
||||
JsonNode biome = biomes.get(enumBiome.toString());
|
||||
if (biome != null) {
|
||||
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
|
||||
} else {
|
||||
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
|
||||
", defaulting to 0");
|
||||
biomeToIdMap.put(enumBiome.ordinal(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -121,64 +74,11 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
|
||||
Player bukkitPlayer;
|
||||
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|
||||
return;
|
||||
}
|
||||
World world = bukkitPlayer.getWorld();
|
||||
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
|
||||
for (int blockZ = 0; blockZ < 16; blockZ++) {
|
||||
for (int blockX = 0; blockX < 16; blockX++) {
|
||||
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
|
||||
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
|
||||
chunk.set(blockX, blockY, blockZ, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasOwnChunkCache() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public int[] getBiomeDataAt(GeyserSession session, int x, int z) {
|
||||
int[] biomeData = new int[1024];
|
||||
World world = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld();
|
||||
int chunkX = x << 4;
|
||||
int chunkZ = z << 4;
|
||||
int chunkXmax = chunkX + 16;
|
||||
int chunkZmax = chunkZ + 16;
|
||||
// 3D biomes didn't exist until 1.15
|
||||
if (use3dBiomes) {
|
||||
for (int localX = chunkX; localX < chunkXmax; localX += 4) {
|
||||
for (int localY = 0; localY < 255; localY += + 4) {
|
||||
for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) {
|
||||
// Index is based on wiki.vg's index requirements
|
||||
final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3);
|
||||
biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localY, localZ).ordinal(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Looks like the same code, but we're not checking the Y coordinate here
|
||||
for (int localX = chunkX; localX < chunkXmax; localX += 4) {
|
||||
for (int localY = 0; localY < 255; localY += + 4) {
|
||||
for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) {
|
||||
// Index is based on wiki.vg's index requirements
|
||||
final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3);
|
||||
biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localZ).ordinal(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return biomeData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) {
|
||||
// Run as a task to prevent async issues
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
{
|
||||
"MUTATED_ICE_FLATS" : 140,
|
||||
"MUTATED_TAIGA" : 133,
|
||||
"SAVANNA_PLATEAU_MOUNTAINS" : 164,
|
||||
"DEEP_WARM_OCEAN" : 47,
|
||||
"REDWOOD_TAIGA_HILLS" : 33,
|
||||
"THE_VOID" : 127,
|
||||
"COLD_TAIGA_MOUNTAINS" : 158,
|
||||
"BAMBOO_JUNGLE_HILLS" : 169,
|
||||
"MOUNTAINS" : 3,
|
||||
"MESA_PLATEAU" : 39,
|
||||
"SNOWY_TAIGA_HILLS" : 31,
|
||||
"DEEP_FROZEN_OCEAN" : 50,
|
||||
"EXTREME_HILLS" : 3,
|
||||
"BIRCH_FOREST_MOUNTAINS" : 155,
|
||||
"FOREST" : 4,
|
||||
"BIRCH_FOREST" : 27,
|
||||
"SNOWY_TUNDRA" : 12,
|
||||
"ICE_SPIKES" : 140,
|
||||
"FROZEN_OCEAN" : 10,
|
||||
"WARPED_FOREST" : 172,
|
||||
"WOODED_BADLANDS_PLATEAU" : 38,
|
||||
"BADLANDS_PLATEAU" : 39,
|
||||
"ICE_PLAINS_SPIKES" : 140,
|
||||
"MEGA_TAIGA" : 32,
|
||||
"MUTATED_SAVANNA_ROCK" : 164,
|
||||
"SAVANNA_PLATEAU" : 36,
|
||||
"DARK_FOREST_HILLS" : 157,
|
||||
"END_MIDLANDS" : 41,
|
||||
"SHATTERED_SAVANNA_PLATEAU" : 164,
|
||||
"SAVANNA" : 35,
|
||||
"MUSHROOM_ISLAND_SHORE" : 15,
|
||||
"SWAMP" : 6,
|
||||
"ICE_MOUNTAINS" : 13,
|
||||
"BEACH" : 16,
|
||||
"MUTATED_MESA_CLEAR_ROCK" : 167,
|
||||
"END_HIGHLANDS" : 42,
|
||||
"COLD_BEACH" : 26,
|
||||
"JUNGLE" : 21,
|
||||
"MUTATED_TAIGA_COLD" : 158,
|
||||
"TALL_BIRCH_HILLS" : 156,
|
||||
"DARK_FOREST" : 29,
|
||||
"WOODED_HILLS" : 18,
|
||||
"HELL" : 8,
|
||||
"MUTATED_REDWOOD_TAIGA" : 160,
|
||||
"MESA_PLATEAU_FOREST" : 38,
|
||||
"MUSHROOM_ISLAND" : 14,
|
||||
"BADLANDS" : 37,
|
||||
"END_BARRENS" : 43,
|
||||
"MUTATED_EXTREME_HILLS_WITH_TREES" : 162,
|
||||
"MUTATED_JUNGLE_EDGE" : 151,
|
||||
"MODIFIED_BADLANDS_PLATEAU" : 167,
|
||||
"ROOFED_FOREST_MOUNTAINS" : 157,
|
||||
"SOUL_SAND_VALLEY" : 170,
|
||||
"DESERT" : 2,
|
||||
"MUTATED_PLAINS" : 129,
|
||||
"MUTATED_BIRCH_FOREST" : 155,
|
||||
"WOODED_MOUNTAINS" : 34,
|
||||
"TAIGA_HILLS" : 19,
|
||||
"BAMBOO_JUNGLE" : 168,
|
||||
"SWAMPLAND_MOUNTAINS" : 134,
|
||||
"DESERT_MOUNTAINS" : 130,
|
||||
"REDWOOD_TAIGA" : 32,
|
||||
"MUSHROOM_FIELDS" : 14,
|
||||
"GIANT_TREE_TAIGA_HILLS" : 33,
|
||||
"PLAINS" : 1,
|
||||
"JUNGLE_EDGE" : 23,
|
||||
"SAVANNA_MOUNTAINS" : 163,
|
||||
"DEEP_COLD_OCEAN" : 49,
|
||||
"DESERT_LAKES" : 130,
|
||||
"MOUNTAIN_EDGE" : 20,
|
||||
"SNOWY_MOUNTAINS" : 13,
|
||||
"MESA_PLATEAU_MOUNTAINS" : 167,
|
||||
"JUNGLE_MOUNTAINS" : 149,
|
||||
"SMALLER_EXTREME_HILLS" : 20,
|
||||
"MESA_PLATEAU_FOREST_MOUNTAINS" : 166,
|
||||
"NETHER_WASTES" : 8,
|
||||
"BIRCH_FOREST_HILLS_MOUNTAINS" : 156,
|
||||
"MUTATED_JUNGLE" : 149,
|
||||
"WARM_OCEAN" : 44,
|
||||
"DEEP_OCEAN" : 24,
|
||||
"STONE_BEACH" : 25,
|
||||
"MODIFIED_JUNGLE" : 149,
|
||||
"MUTATED_SAVANNA" : 163,
|
||||
"TAIGA_COLD_HILLS" : 31,
|
||||
"OCEAN" : 0,
|
||||
"SMALL_END_ISLANDS" : 40,
|
||||
"MUSHROOM_FIELD_SHORE" : 15,
|
||||
"GRAVELLY_MOUNTAINS" : 131,
|
||||
"FROZEN_RIVER" : 11,
|
||||
"TAIGA_COLD" : 30,
|
||||
"BASALT_DELTAS" : 173,
|
||||
"EXTREME_HILLS_WITH_TREES" : 34,
|
||||
"MEGA_TAIGA_HILLS" : 33,
|
||||
"MUTATED_FOREST" : 132,
|
||||
"MUTATED_BIRCH_FOREST_HILLS" : 156,
|
||||
"SKY" : 9,
|
||||
"LUKEWARM_OCEAN" : 45,
|
||||
"EXTREME_HILLS_MOUNTAINS" : 131,
|
||||
"COLD_TAIGA_HILLS" : 31,
|
||||
"THE_END" : 9,
|
||||
"SUNFLOWER_PLAINS" : 129,
|
||||
"SAVANNA_ROCK" : 36,
|
||||
"ERODED_BADLANDS" : 165,
|
||||
"STONE_SHORE" : 25,
|
||||
"EXTREME_HILLS_PLUS_MOUNTAINS" : 162,
|
||||
"CRIMSON_FOREST" : 171,
|
||||
"VOID" : 127,
|
||||
"SNOWY_TAIGA" : 30,
|
||||
"SNOWY_TAIGA_MOUNTAINS" : 158,
|
||||
"FLOWER_FOREST" : 132,
|
||||
"COLD_OCEAN" : 46,
|
||||
"BEACHES" : 16,
|
||||
"MESA" : 37,
|
||||
"MUSHROOM_SHORE" : 15,
|
||||
"MESA_CLEAR_ROCK" : 39,
|
||||
"NETHER" : 8,
|
||||
"ICE_PLAINS" : 12,
|
||||
"SHATTERED_SAVANNA" : 163,
|
||||
"ROOFED_FOREST" : 29,
|
||||
"GIANT_SPRUCE_TAIGA_HILLS" : 161,
|
||||
"SNOWY_BEACH" : 26,
|
||||
"MESA_BRYCE" : 165,
|
||||
"JUNGLE_EDGE_MOUNTAINS" : 151,
|
||||
"MUTATED_DESERT" : 130,
|
||||
"MODIFIED_GRAVELLY_MOUNTAINS" : 158,
|
||||
"MEGA_SPRUCE_TAIGA" : 160,
|
||||
"TAIGA_MOUNTAINS" : 133,
|
||||
"SMALL_MOUNTAINS" : 20,
|
||||
"EXTREME_HILLS_PLUS" : 34,
|
||||
"GIANT_SPRUCE_TAIGA" : 160,
|
||||
"FOREST_HILLS" : 18,
|
||||
"DESERT_HILLS" : 17,
|
||||
"MUTATED_REDWOOD_TAIGA_HILLS" : 161,
|
||||
"MEGA_SPRUCE_TAIGA_HILLS" : 161,
|
||||
"RIVER" : 7,
|
||||
"GIANT_TREE_TAIGA" : 32,
|
||||
"SWAMPLAND" : 6,
|
||||
"JUNGLE_HILLS" : 22,
|
||||
"TALL_BIRCH_FOREST" : 155,
|
||||
"DEEP_LUKEWARM_OCEAN" : 48,
|
||||
"MESA_ROCK" : 38,
|
||||
"SWAMP_HILLS" : 134,
|
||||
"MODIFIED_WOODED_BADLANDS_PLATEAU" : 166,
|
||||
"MODIFIED_JUNGLE_EDGE" : 151,
|
||||
"BIRCH_FOREST_HILLS" : 28,
|
||||
"COLD_TAIGA" : 30,
|
||||
"TAIGA" : 5,
|
||||
"MUTATED_MESA_ROCK" : 166,
|
||||
"MUTATED_SWAMPLAND" : 134,
|
||||
"ICE_FLATS" : 12,
|
||||
"MUTATED_ROOFED_FOREST" : 157,
|
||||
"MUTATED_MESA" : 165,
|
||||
"MUTATED_EXTREME_HILLS" : 131
|
||||
}
|
|
@ -3,7 +3,7 @@ name: ${outputName}-Spigot
|
|||
author: ${project.organization.name}
|
||||
website: ${project.organization.url}
|
||||
version: ${project.version}
|
||||
softdepend: ["ViaVersion"]
|
||||
softdepend: ["ViaVersion", "floodgate"]
|
||||
api-version: 1.13
|
||||
commands:
|
||||
geyser:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-sponge</artifactId>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-standalone</artifactId>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>bootstrap-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>bootstrap-velocity</artifactId>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -107,6 +107,15 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
|||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
// Remove this in like a year
|
||||
try {
|
||||
// Should only exist on 1.0
|
||||
Class.forName("org.geysermc.floodgate.FloodgateAPI");
|
||||
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.outdated", "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"));
|
||||
return;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
|
||||
if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) {
|
||||
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||
return;
|
||||
|
|
|
@ -6,22 +6,20 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<scope>compile</scope>
|
||||
<groupId>org.geysermc.cumulus</groupId>
|
||||
<artifactId>cumulus</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.9.8</version>
|
||||
<scope>compile</scope>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -31,7 +31,6 @@ import lombok.Getter;
|
|||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PlatformType {
|
||||
|
||||
ANDROID("Android"),
|
||||
BUNGEECORD("BungeeCord"),
|
||||
FABRIC("Fabric"),
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.window.CustomFormWindow;
|
||||
import org.geysermc.common.window.button.FormImage;
|
||||
import org.geysermc.common.window.component.FormComponent;
|
||||
import org.geysermc.common.window.response.CustomFormResponse;
|
||||
|
||||
public class CustomFormBuilder {
|
||||
|
||||
@Getter
|
||||
private CustomFormWindow form;
|
||||
|
||||
public CustomFormBuilder(String title) {
|
||||
form = new CustomFormWindow(title);
|
||||
}
|
||||
|
||||
public CustomFormBuilder setTitle(String title) {
|
||||
form.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomFormBuilder setIcon(FormImage icon) {
|
||||
form.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomFormBuilder setResponse(String data) {
|
||||
form.setResponse(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomFormBuilder setResponse(CustomFormResponse response) {
|
||||
form.setResponse(response);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomFormBuilder addComponent(FormComponent component) {
|
||||
form.addComponent(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CustomFormWindow build() {
|
||||
return form;
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.button.FormImage;
|
||||
import org.geysermc.common.window.component.*;
|
||||
import org.geysermc.common.window.response.CustomFormResponse;
|
||||
import org.geysermc.common.window.response.FormResponseData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomFormWindow extends FormWindow {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String title;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private FormImage icon;
|
||||
|
||||
@Getter
|
||||
private List<FormComponent> content;
|
||||
|
||||
public CustomFormWindow(String title) {
|
||||
this(title, new ArrayList<>());
|
||||
}
|
||||
|
||||
public CustomFormWindow(String title, List<FormComponent> content) {
|
||||
this(title, content, (FormImage) null);
|
||||
}
|
||||
|
||||
public CustomFormWindow(String title, List<FormComponent> content, String icon) {
|
||||
this(title, content, new FormImage(FormImage.FormImageType.URL, icon));
|
||||
}
|
||||
|
||||
public CustomFormWindow(String title, List<FormComponent> content, FormImage icon) {
|
||||
super("custom_form");
|
||||
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public void addComponent(FormComponent component) {
|
||||
content.add(component);
|
||||
}
|
||||
|
||||
public String getJSONData() {
|
||||
String toModify = "";
|
||||
try {
|
||||
toModify = new ObjectMapper().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) { }
|
||||
|
||||
//We need to replace this due to Java not supporting declaring class field 'default'
|
||||
return toModify.replace("defaultOptionIndex", "default")
|
||||
.replace("defaultText", "default")
|
||||
.replace("defaultValue", "default")
|
||||
.replace("defaultStepIndex", "default");
|
||||
}
|
||||
|
||||
public void setResponse(String data) {
|
||||
if (data == null || data.trim().equalsIgnoreCase("null") || data.isEmpty()) {
|
||||
closed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
Map<Integer, FormResponseData> dropdownResponses = new HashMap<Integer, FormResponseData>();
|
||||
Map<Integer, String> inputResponses = new HashMap<Integer, String>();
|
||||
Map<Integer, Float> sliderResponses = new HashMap<Integer, Float>();
|
||||
Map<Integer, FormResponseData> stepSliderResponses = new HashMap<Integer, FormResponseData>();
|
||||
Map<Integer, Boolean> toggleResponses = new HashMap<Integer, Boolean>();
|
||||
Map<Integer, Object> responses = new HashMap<Integer, Object>();
|
||||
Map<Integer, String> labelResponses = new HashMap<Integer, String>();
|
||||
|
||||
List<String> componentResponses = new ArrayList<>();
|
||||
try {
|
||||
componentResponses = new ObjectMapper().readValue(data.trim(), new TypeReference<List<String>>(){});
|
||||
} catch (IOException e) { }
|
||||
|
||||
for (String response : componentResponses) {
|
||||
if (i >= content.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
FormComponent component = content.get(i);
|
||||
if (component == null)
|
||||
return;
|
||||
|
||||
if (component instanceof LabelComponent) {
|
||||
LabelComponent labelComponent = (LabelComponent) component;
|
||||
labelResponses.put(i, labelComponent.getText());
|
||||
}
|
||||
|
||||
if (component instanceof DropdownComponent) {
|
||||
DropdownComponent dropdownComponent = (DropdownComponent) component;
|
||||
String option = dropdownComponent.getOptions().get(Integer.parseInt(response));
|
||||
|
||||
dropdownResponses.put(i, new FormResponseData(Integer.parseInt(response), option));
|
||||
responses.put(i, option);
|
||||
}
|
||||
|
||||
if (component instanceof InputComponent) {
|
||||
inputResponses.put(i, response);
|
||||
responses.put(i, response);
|
||||
}
|
||||
|
||||
if (component instanceof SliderComponent) {
|
||||
float value = Float.parseFloat(response);
|
||||
sliderResponses.put(i, value);
|
||||
responses.put(i, value);
|
||||
}
|
||||
|
||||
if (component instanceof StepSliderComponent) {
|
||||
StepSliderComponent stepSliderComponent = (StepSliderComponent) component;
|
||||
String step = stepSliderComponent.getSteps().get(Integer.parseInt(response));
|
||||
stepSliderResponses.put(i, new FormResponseData(Integer.parseInt(response), step));
|
||||
responses.put(i, step);
|
||||
}
|
||||
|
||||
if (component instanceof ToggleComponent) {
|
||||
boolean answer = Boolean.parseBoolean(response);
|
||||
toggleResponses.put(i, answer);
|
||||
responses.put(i, answer);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
this.response = new CustomFormResponse(responses, dropdownResponses, inputResponses,
|
||||
sliderResponses, stepSliderResponses, toggleResponses, labelResponses);
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.response.ModalFormResponse;
|
||||
|
||||
public class ModalFormWindow extends FormWindow {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String title;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String content;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String button1;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String button2;
|
||||
|
||||
public ModalFormWindow(String title, String content, String button1, String button2) {
|
||||
super("modal");
|
||||
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.button1 = button1;
|
||||
this.button2 = button2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJSONData() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void setResponse(String data) {
|
||||
if (data == null || data.equalsIgnoreCase("null")) {
|
||||
closed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Boolean.parseBoolean(data)) {
|
||||
response = new ModalFormResponse(0, button1);
|
||||
} else {
|
||||
response = new ModalFormResponse(1, button2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.button.FormButton;
|
||||
import org.geysermc.common.window.response.SimpleFormResponse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class SimpleFormWindow extends FormWindow {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String title;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String content;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private List<FormButton> buttons;
|
||||
|
||||
public SimpleFormWindow(String title, String content) {
|
||||
this(title, content, new ArrayList<FormButton>());
|
||||
}
|
||||
|
||||
public SimpleFormWindow(String title, String content, List<FormButton> buttons) {
|
||||
super("form");
|
||||
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.buttons = buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJSONData() {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void setResponse(String data) {
|
||||
if (data == null || data.trim().equalsIgnoreCase("null")) {
|
||||
closed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int buttonID;
|
||||
try {
|
||||
buttonID = Integer.parseInt(data.trim());
|
||||
} catch (Exception ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttonID >= buttons.size()) {
|
||||
response = new SimpleFormResponse(buttonID, null);
|
||||
return;
|
||||
}
|
||||
|
||||
response = new SimpleFormResponse(buttonID, buttons.get(buttonID));
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.component;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DropdownComponent extends FormComponent {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private List<String> options;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private int defaultOptionIndex;
|
||||
|
||||
public DropdownComponent() {
|
||||
super("dropdown");
|
||||
}
|
||||
|
||||
public void addOption(String option, boolean isDefault) {
|
||||
options.add(option);
|
||||
if (isDefault)
|
||||
defaultOptionIndex = options.size() - 1;
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.component;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class InputComponent extends FormComponent {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String placeholder;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String defaultText;
|
||||
|
||||
public InputComponent(String text, String placeholder, String defaultText) {
|
||||
super("input");
|
||||
|
||||
this.text = text;
|
||||
this.placeholder = placeholder;
|
||||
this.defaultText = defaultText;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.component;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class SliderComponent extends FormComponent {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private float min;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private float max;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private int step;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private float defaultValue;
|
||||
|
||||
public SliderComponent(String text, float min, float max, int step, float defaultValue) {
|
||||
super("slider");
|
||||
|
||||
this.text = text;
|
||||
this.min = Math.max(min, 0f);
|
||||
this.max = max > this.min ? max : this.min;
|
||||
if (step != -1f && step > 0)
|
||||
this.step = step;
|
||||
|
||||
if (defaultValue != -1f)
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.component;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ToggleComponent extends FormComponent {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean defaultValue;
|
||||
|
||||
public ToggleComponent(String text) {
|
||||
this(text, false);
|
||||
}
|
||||
|
||||
public ToggleComponent(String text, boolean defaultValue) {
|
||||
super("toggle");
|
||||
|
||||
this.text = text;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.window.response.FormResponse;
|
||||
import org.geysermc.common.window.response.FormResponseData;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class CustomFormResponse implements FormResponse {
|
||||
|
||||
private Map<Integer, Object> responses;
|
||||
private Map<Integer, FormResponseData> dropdownResponses;
|
||||
private Map<Integer, String> inputResponses;
|
||||
private Map<Integer, Float> sliderResponses;
|
||||
private Map<Integer, FormResponseData> stepSliderResponses;
|
||||
private Map<Integer, Boolean> toggleResponses;
|
||||
private Map<Integer, String> labelResponses;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.common.window.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.window.button.FormButton;
|
||||
import org.geysermc.common.window.response.FormResponse;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class SimpleFormResponse implements FormResponse {
|
||||
|
||||
private int clickedButtonId;
|
||||
private FormButton clickedButton;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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/Floodgate
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.Key;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class AesCipher implements FloodgateCipher {
|
||||
public static final int IV_LENGTH = 12;
|
||||
private static final int TAG_BIT_LENGTH = 128;
|
||||
private static final String CIPHER_NAME = "AES/GCM/NoPadding";
|
||||
|
||||
private final SecureRandom secureRandom = new SecureRandom();
|
||||
private final Topping topping;
|
||||
private SecretKey secretKey;
|
||||
|
||||
public void init(Key key) {
|
||||
if (!"AES".equals(key.getAlgorithm())) {
|
||||
throw new RuntimeException(
|
||||
"Algorithm was expected to be AES, but got " + key.getAlgorithm()
|
||||
);
|
||||
}
|
||||
secretKey = (SecretKey) key;
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] data) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
|
||||
|
||||
byte[] iv = new byte[IV_LENGTH];
|
||||
secureRandom.nextBytes(iv);
|
||||
|
||||
GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
|
||||
byte[] cipherText = cipher.doFinal(data);
|
||||
|
||||
if (topping != null) {
|
||||
iv = topping.encode(iv);
|
||||
cipherText = topping.encode(cipherText);
|
||||
}
|
||||
|
||||
return ByteBuffer.allocate(iv.length + cipherText.length + HEADER_LENGTH + 1)
|
||||
.put(IDENTIFIER) // header
|
||||
.put(iv)
|
||||
.put((byte) 0x21)
|
||||
.put(cipherText)
|
||||
.array();
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] cipherTextWithIv) throws Exception {
|
||||
checkHeader(cipherTextWithIv);
|
||||
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
|
||||
|
||||
int bufferLength = cipherTextWithIv.length - HEADER_LENGTH;
|
||||
ByteBuffer buffer = ByteBuffer.wrap(cipherTextWithIv, HEADER_LENGTH, bufferLength);
|
||||
|
||||
int ivLength = IV_LENGTH;
|
||||
|
||||
if (topping != null) {
|
||||
int mark = buffer.position();
|
||||
|
||||
// we need the first index, the second is for the optional RawSkin
|
||||
boolean found = false;
|
||||
while (buffer.hasRemaining() && !found) {
|
||||
if (buffer.get() == 0x21) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
ivLength = buffer.position() - mark - 1; // don't include the splitter itself
|
||||
// don't remove this cast, it'll cause problems if you remove it
|
||||
((Buffer) buffer).position(mark); // reset to the pre-while index
|
||||
}
|
||||
|
||||
byte[] iv = new byte[ivLength];
|
||||
buffer.get(iv);
|
||||
|
||||
// don't remove this cast, it'll cause problems if you remove it
|
||||
((Buffer) buffer).position(buffer.position() + 1); // skip splitter
|
||||
|
||||
byte[] cipherText = new byte[buffer.remaining()];
|
||||
buffer.get(cipherText);
|
||||
|
||||
if (topping != null) {
|
||||
iv = topping.decode(iv);
|
||||
cipherText = topping.decode(cipherText);
|
||||
}
|
||||
|
||||
GCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_LENGTH, iv);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
|
||||
return cipher.doFinal(cipherText);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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/Floodgate
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public final class AesKeyProducer implements KeyProducer {
|
||||
public static int KEY_SIZE = 128;
|
||||
|
||||
@Override
|
||||
public SecretKey produce() {
|
||||
try {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
keyGenerator.init(KEY_SIZE, getSecureRandom());
|
||||
return keyGenerator.generateKey();
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretKey produceFrom(byte[] keyFileData) {
|
||||
try {
|
||||
return new SecretKeySpec(keyFileData, "AES");
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private SecureRandom getSecureRandom() throws NoSuchAlgorithmException {
|
||||
// use Windows-PRNG for windows (default impl is SHA1PRNG)
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
return SecureRandom.getInstance("Windows-PRNG");
|
||||
} else {
|
||||
try {
|
||||
// NativePRNG (which should be the default on unix-systems) can still block your
|
||||
// system. Even though it isn't as bad as NativePRNGBlocking, we still try to
|
||||
// prevent that if possible
|
||||
return SecureRandom.getInstance("NativePRNGNonBlocking");
|
||||
} catch (NoSuchAlgorithmException ignored) {
|
||||
// at this point we just have to go with the default impl even if it blocks
|
||||
return new SecureRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,16 +23,18 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.response;
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.window.response.FormResponse;
|
||||
import java.util.Base64;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ModalFormResponse implements FormResponse {
|
||||
public final class Base64Topping implements Topping {
|
||||
@Override
|
||||
public byte[] encode(byte[] data) {
|
||||
return Base64.getEncoder().encode(data);
|
||||
}
|
||||
|
||||
private int clickedButtonId;
|
||||
private String clickedButtonText;
|
||||
@Override
|
||||
public byte[] decode(byte[] data) {
|
||||
return Base64.getDecoder().decode(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Floodgate
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.geysermc.floodgate.util.InvalidFormatException;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
|
||||
/**
|
||||
* Responsible for both encrypting and decrypting data
|
||||
*/
|
||||
public interface FloodgateCipher {
|
||||
// use invalid username characters at the beginning and the end of the identifier,
|
||||
// to make sure that it doesn't get messed up with usernames
|
||||
byte[] IDENTIFIER = "^Floodgate^".getBytes(StandardCharsets.UTF_8);
|
||||
int HEADER_LENGTH = IDENTIFIER.length;
|
||||
|
||||
static boolean hasHeader(String data) {
|
||||
if (data.length() < IDENTIFIER.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < IDENTIFIER.length; i++) {
|
||||
if (IDENTIFIER[i] != data.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the instance by giving it the key it needs to encrypt or decrypt data
|
||||
*
|
||||
* @param key the key used to encrypt and decrypt data
|
||||
*/
|
||||
void init(Key key);
|
||||
|
||||
/**
|
||||
* Encrypts the given data using the Key provided in {@link #init(Key)}
|
||||
*
|
||||
* @param data the data to encrypt
|
||||
* @return the encrypted data
|
||||
* @throws Exception when the encryption failed
|
||||
*/
|
||||
byte[] encrypt(byte[] data) throws Exception;
|
||||
|
||||
/**
|
||||
* Encrypts data from a String.<br> This method internally calls {@link #encrypt(byte[])}
|
||||
*
|
||||
* @param data the data to encrypt
|
||||
* @return the encrypted data
|
||||
* @throws Exception when the encryption failed
|
||||
*/
|
||||
default byte[] encryptFromString(String data) throws Exception {
|
||||
return encrypt(data.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the given data using the Key provided in {@link #init(Key)}
|
||||
*
|
||||
* @param data the data to decrypt
|
||||
* @return the decrypted data
|
||||
* @throws Exception when the decrypting failed
|
||||
*/
|
||||
byte[] decrypt(byte[] data) throws Exception;
|
||||
|
||||
/**
|
||||
* Decrypts a byte[] and turn it into a String.<br> This method internally calls {@link
|
||||
* #decrypt(byte[])} and converts the returned byte[] into a String.
|
||||
*
|
||||
* @param data the data to encrypt
|
||||
* @return the decrypted data in a UTF-8 String
|
||||
* @throws Exception when the decrypting failed
|
||||
*/
|
||||
default String decryptToString(byte[] data) throws Exception {
|
||||
byte[] decrypted = decrypt(data);
|
||||
if (decrypted == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(decrypted, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a String.<br> This method internally calls {@link #decrypt(byte[])} by converting
|
||||
* the UTF-8 String into a byte[]
|
||||
*
|
||||
* @param data the data to decrypt
|
||||
* @return the decrypted data in a byte[]
|
||||
* @throws Exception when the decrypting failed
|
||||
*/
|
||||
default byte[] decryptFromString(String data) throws Exception {
|
||||
return decrypt(data.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the header is valid. This method will throw an InvalidFormatException when the
|
||||
* header is invalid.
|
||||
*
|
||||
* @param data the data to check
|
||||
* @throws InvalidFormatException when the header is invalid
|
||||
*/
|
||||
default void checkHeader(byte[] data) throws InvalidFormatException {
|
||||
final int identifierLength = IDENTIFIER.length;
|
||||
|
||||
if (data.length <= HEADER_LENGTH) {
|
||||
throw new InvalidFormatException("Data length is smaller then header." +
|
||||
"Needed " + HEADER_LENGTH + ", got " + data.length,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < identifierLength; i++) {
|
||||
if (IDENTIFIER[i] != data[i]) {
|
||||
StringBuilder receivedIdentifier = new StringBuilder();
|
||||
for (byte b : IDENTIFIER) {
|
||||
receivedIdentifier.append(b);
|
||||
}
|
||||
|
||||
throw new InvalidFormatException(
|
||||
String.format("Expected identifier %s, got %s",
|
||||
new String(IDENTIFIER, StandardCharsets.UTF_8),
|
||||
receivedIdentifier.toString()
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
class HeaderResult {
|
||||
private int version;
|
||||
private int startIndex;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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/Floodgate
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Key;
|
||||
|
||||
public interface KeyProducer {
|
||||
Key produce();
|
||||
Key produceFrom(byte[] keyFileData);
|
||||
|
||||
default Key produceFrom(Path keyFileLocation) throws IOException {
|
||||
return produceFrom(Files.readAllBytes(keyFileLocation));
|
||||
}
|
||||
}
|
|
@ -23,15 +23,9 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.response;
|
||||
package org.geysermc.floodgate.crypto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class FormResponseData {
|
||||
|
||||
private int elementID;
|
||||
private String elementContent;
|
||||
public interface Topping {
|
||||
byte[] encode(byte[] data);
|
||||
byte[] decode(byte[] data);
|
||||
}
|
143
common/src/main/java/org/geysermc/floodgate/news/NewsItem.java
Normal file
143
common/src/main/java/org/geysermc/floodgate/news/NewsItem.java
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.news;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.geysermc.floodgate.news.data.ItemData;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class NewsItem {
|
||||
private final int id;
|
||||
private final String project;
|
||||
private final boolean active;
|
||||
private final NewsType type;
|
||||
private final ItemData data;
|
||||
private final boolean priority;
|
||||
private final String message;
|
||||
private final Set<NewsItemAction> actions;
|
||||
private final String url;
|
||||
|
||||
private NewsItem(int id, String project, boolean active, NewsType type, ItemData data,
|
||||
boolean priority, String message, Set<NewsItemAction> actions, String url) {
|
||||
this.id = id;
|
||||
this.project = project;
|
||||
this.active = active;
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
this.priority = priority;
|
||||
this.message = message;
|
||||
this.actions = Collections.unmodifiableSet(actions);
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public static NewsItem readItem(JsonObject newsItem) {
|
||||
NewsType newsType = NewsType.getByName(newsItem.get("type").getAsString());
|
||||
if (newsType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonObject messageObject = newsItem.getAsJsonObject("message");
|
||||
NewsItemMessage itemMessage = NewsItemMessage.getById(messageObject.get("id").getAsInt());
|
||||
|
||||
String message = "Received an unknown news message type. Please update";
|
||||
if (itemMessage != null) {
|
||||
message = itemMessage.getFormattedMessage(messageObject.getAsJsonArray("args"));
|
||||
}
|
||||
|
||||
Set<NewsItemAction> actions = new HashSet<>();
|
||||
for (JsonElement actionElement : newsItem.getAsJsonArray("actions")) {
|
||||
NewsItemAction action = NewsItemAction.getByName(actionElement.getAsString());
|
||||
if (action != null) {
|
||||
actions.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
return new NewsItem(
|
||||
newsItem.get("id").getAsInt(),
|
||||
newsItem.get("project").getAsString(),
|
||||
newsItem.get("active").getAsBoolean(),
|
||||
newsType,
|
||||
newsType.read(newsItem.getAsJsonObject("data")),
|
||||
newsItem.get("priority").getAsBoolean(),
|
||||
message,
|
||||
actions,
|
||||
newsItem.get("url").getAsString()
|
||||
);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return "all".equals(getProject());
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public NewsType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ItemData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ItemData> T getDataAs(Class<T> type) {
|
||||
return (T) data;
|
||||
}
|
||||
|
||||
public boolean isPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public String getRawMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message + " See " + getUrl() + " for more information.";
|
||||
}
|
||||
|
||||
public Set<NewsItemAction> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.news;
|
||||
|
||||
public enum NewsItemAction {
|
||||
ON_SERVER_STARTED,
|
||||
ON_OPERATOR_JOIN,
|
||||
BROADCAST_TO_CONSOLE,
|
||||
BROADCAST_TO_OPERATORS;
|
||||
|
||||
private static final NewsItemAction[] VALUES = values();
|
||||
|
||||
public static NewsItemAction getByName(String actionName) {
|
||||
for (NewsItemAction type : VALUES) {
|
||||
if (type.name().equalsIgnoreCase(actionName)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.news;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
// {} is used for things that have to be filled in by the server,
|
||||
// {@} is for things that have to be filled in by us
|
||||
public enum NewsItemMessage {
|
||||
UPDATE_AVAILABLE("There is an update available for {}. The newest version is: {}"),
|
||||
UPDATE_RECOMMENDED(UPDATE_AVAILABLE + ". Your version is quite old, updating is recommend."),
|
||||
UPDATE_HIGHLY_RECOMMENDED(UPDATE_AVAILABLE + ". We highly recommend updating because some important changes have been made."),
|
||||
UPDATE_ANCIENT_VERSION(UPDATE_AVAILABLE + ". You are running an ancient version, updating is recommended."),
|
||||
|
||||
DOWNTIME_GENERIC("The {} is temporarily going down for maintenance soon."),
|
||||
DOWNTIME_WITH_START("The {} is temporarily going down for maintenance on {}."),
|
||||
DOWNTIME_TIMEFRAME(DOWNTIME_WITH_START + " The maintenance is expected to last till {}.");
|
||||
|
||||
private static final NewsItemMessage[] VALUES = values();
|
||||
|
||||
private final String messageFormat;
|
||||
private final String[] messageSplitted;
|
||||
|
||||
NewsItemMessage(String messageFormat) {
|
||||
this.messageFormat = messageFormat;
|
||||
this.messageSplitted = messageFormat.split(" ");
|
||||
}
|
||||
|
||||
public static NewsItemMessage getById(int id) {
|
||||
return VALUES.length > id ? VALUES[id] : null;
|
||||
}
|
||||
|
||||
public String getMessageFormat() {
|
||||
return messageFormat;
|
||||
}
|
||||
|
||||
public String getFormattedMessage(JsonArray serverArguments) {
|
||||
int serverArgumentsIndex = 0;
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
for (String split : messageSplitted) {
|
||||
if (message.length() > 0) {
|
||||
message.append(' ');
|
||||
}
|
||||
|
||||
String result = split;
|
||||
|
||||
if (serverArgumentsIndex < serverArguments.size()) {
|
||||
String argument = serverArguments.get(serverArgumentsIndex).getAsString();
|
||||
result = result.replace("{}", argument);
|
||||
if (!result.equals(split)) {
|
||||
serverArgumentsIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
message.append(result);
|
||||
}
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getMessageFormat();
|
||||
}
|
||||
}
|
|
@ -23,47 +23,37 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.component;
|
||||
package org.geysermc.floodgate.news;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.geysermc.floodgate.news.data.BuildSpecificData;
|
||||
import org.geysermc.floodgate.news.data.CheckAfterData;
|
||||
import org.geysermc.floodgate.news.data.ItemData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class StepSliderComponent extends FormComponent {
|
||||
public enum NewsType {
|
||||
BUILD_SPECIFIC(BuildSpecificData::read),
|
||||
CHECK_AFTER(CheckAfterData::read);
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
private static final NewsType[] VALUES = values();
|
||||
|
||||
@Getter
|
||||
private List<String> steps;
|
||||
private final Function<JsonObject, ? extends ItemData> readFunction;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private int defaultStepIndex;
|
||||
|
||||
public StepSliderComponent(String text) {
|
||||
this(text, new ArrayList<String>());
|
||||
NewsType(Function<JsonObject, ? extends ItemData> readFunction) {
|
||||
this.readFunction = readFunction;
|
||||
}
|
||||
|
||||
public StepSliderComponent(String text, List<String> steps) {
|
||||
this(text, steps, 0);
|
||||
public static NewsType getByName(String newsType) {
|
||||
for (NewsType type : VALUES) {
|
||||
if (type.name().equalsIgnoreCase(newsType)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public StepSliderComponent(String text, List<String> steps, int defaultStepIndex) {
|
||||
super("step_slider");
|
||||
|
||||
this.text = text;
|
||||
this.steps = steps;
|
||||
this.defaultStepIndex = defaultStepIndex;
|
||||
}
|
||||
|
||||
public void addStep(String step, boolean isDefault) {
|
||||
steps.add(step);
|
||||
|
||||
if (isDefault)
|
||||
defaultStepIndex = steps.size() - 1;
|
||||
public ItemData read(JsonObject data) {
|
||||
return readFunction.apply(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.news.data;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public final class BuildSpecificData implements ItemData {
|
||||
private String branch;
|
||||
|
||||
private boolean allAffected;
|
||||
private int affectedGreaterThan;
|
||||
private int affectedLessThan;
|
||||
|
||||
public static BuildSpecificData read(JsonObject data) {
|
||||
BuildSpecificData updateData = new BuildSpecificData();
|
||||
updateData.branch = data.get("branch").getAsString();
|
||||
|
||||
JsonObject affectedBuilds = data.getAsJsonObject("affected_builds");
|
||||
if (affectedBuilds.has("all")) {
|
||||
updateData.allAffected = affectedBuilds.get("all").getAsBoolean();
|
||||
}
|
||||
if (!updateData.allAffected) {
|
||||
updateData.affectedGreaterThan = affectedBuilds.get("gt").getAsInt();
|
||||
updateData.affectedLessThan = affectedBuilds.get("lt").getAsInt();
|
||||
}
|
||||
return updateData;
|
||||
}
|
||||
|
||||
public boolean isAffected(String branch, int buildId) {
|
||||
return this.branch.equals(branch) &&
|
||||
(allAffected || buildId > affectedGreaterThan && buildId < affectedLessThan);
|
||||
}
|
||||
|
||||
public String getBranch() {
|
||||
return branch;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.news.data;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class CheckAfterData implements ItemData {
|
||||
private long checkAfter;
|
||||
|
||||
public static CheckAfterData read(JsonObject data) {
|
||||
CheckAfterData checkAfterData = new CheckAfterData();
|
||||
checkAfterData.checkAfter = data.get("check_after").getAsLong();
|
||||
return checkAfterData;
|
||||
}
|
||||
|
||||
public long getCheckAfter() {
|
||||
return checkAfter;
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.response;
|
||||
package org.geysermc.floodgate.news.data;
|
||||
|
||||
public interface FormResponse {
|
||||
public interface ItemData {
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.time;
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/*
|
||||
* Thanks:
|
||||
* https://datatracker.ietf.org/doc/html/rfc1769
|
||||
* https://github.com/jonsagara/SimpleNtpClient
|
||||
* https://stackoverflow.com/a/29138806
|
||||
*/
|
||||
public final class SntpClientUtils {
|
||||
private static final int NTP_PORT = 123;
|
||||
|
||||
private static final int NTP_PACKET_SIZE = 48;
|
||||
private static final int NTP_MODE = 3; // client
|
||||
private static final int NTP_VERSION = 3;
|
||||
private static final int RECEIVE_TIME_POSITION = 32;
|
||||
|
||||
private static final long NTP_TIME_OFFSET = ((365L * 70L) + 17L) * 24L * 60L * 60L;
|
||||
|
||||
public static long requestTimeOffset(String host, int timeout) {
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
socket.setSoTimeout(timeout);
|
||||
|
||||
InetAddress address = InetAddress.getByName(host);
|
||||
|
||||
ByteBuffer buff = ByteBuffer.allocate(NTP_PACKET_SIZE);
|
||||
|
||||
DatagramPacket request = new DatagramPacket(
|
||||
buff.array(), NTP_PACKET_SIZE, address, NTP_PORT
|
||||
);
|
||||
|
||||
// mode is in the least signification 3 bits
|
||||
// version is in bits 3-5
|
||||
buff.put((byte) (NTP_MODE | (NTP_VERSION << 3)));
|
||||
|
||||
long originateTime = System.currentTimeMillis();
|
||||
socket.send(request);
|
||||
|
||||
DatagramPacket response = new DatagramPacket(buff.array(), NTP_PACKET_SIZE);
|
||||
socket.receive(response);
|
||||
|
||||
long responseTime = System.currentTimeMillis();
|
||||
|
||||
// everything before isn't important for us
|
||||
buff.position(RECEIVE_TIME_POSITION);
|
||||
|
||||
long receiveTime = readTimestamp(buff);
|
||||
long transmitTime = readTimestamp(buff);
|
||||
|
||||
return ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
private static long readTimestamp(ByteBuffer buffer) {
|
||||
//todo look into the ntp 2036 problem
|
||||
long seconds = buffer.getInt() & 0xffffffffL;
|
||||
long fraction = buffer.getInt() & 0xffffffffL;
|
||||
return ((seconds - NTP_TIME_OFFSET) * 1000) + ((fraction * 1000) / 0x100000000L);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.time;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class TimeSyncer {
|
||||
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
||||
private long timeOffset = Long.MIN_VALUE; // value when it failed to get the offset
|
||||
|
||||
public TimeSyncer(String timeServer) {
|
||||
executorService.scheduleWithFixedDelay(() -> {
|
||||
// 5 tries to get the time offset, since UDP doesn't guaranty a response
|
||||
for (int i = 0; i < 5; i++) {
|
||||
long offset = SntpClientUtils.requestTimeOffset(timeServer, 3000);
|
||||
if (offset != Long.MIN_VALUE) {
|
||||
timeOffset = offset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, 0, 30, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
executorService.shutdown();
|
||||
}
|
||||
|
||||
public long getTimeOffset() {
|
||||
return timeOffset;
|
||||
}
|
||||
|
||||
public long getRealMillis() {
|
||||
if (hasUsefulOffset()) {
|
||||
return System.currentTimeMillis() + getTimeOffset();
|
||||
}
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean hasUsefulOffset() {
|
||||
return timeOffset != Long.MIN_VALUE;
|
||||
}
|
||||
}
|
|
@ -23,16 +23,13 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.component;
|
||||
package org.geysermc.floodgate.util;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public abstract class FormComponent {
|
||||
|
||||
@Getter
|
||||
private final String type;
|
||||
|
||||
public FormComponent(String type) {
|
||||
this.type = type;
|
||||
public final class Base64Utils {
|
||||
public static int getEncodedLength(int length) {
|
||||
if (length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return 4 * ((length + 2) / 3);
|
||||
}
|
||||
}
|
|
@ -25,47 +25,91 @@
|
|||
|
||||
package org.geysermc.floodgate.util;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.geysermc.floodgate.time.TimeSyncer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@AllArgsConstructor
|
||||
/**
|
||||
* This class contains the raw data send by Geyser to Floodgate or from Floodgate to Floodgate. This
|
||||
* class is only used internally, and you should look at FloodgatePlayer instead (FloodgatePlayer is
|
||||
* present in the API module of the Floodgate repo)
|
||||
*/
|
||||
@Getter
|
||||
public class BedrockData {
|
||||
public static final int EXPECTED_LENGTH = 7;
|
||||
public static final String FLOODGATE_IDENTIFIER = "Geyser-Floodgate";
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class BedrockData implements Cloneable {
|
||||
public static final int EXPECTED_LENGTH = 13;
|
||||
|
||||
private String version;
|
||||
private String username;
|
||||
private String xuid;
|
||||
private int deviceId;
|
||||
private String languageCode;
|
||||
private int inputMode;
|
||||
private String ip;
|
||||
private int dataLength;
|
||||
private final String version;
|
||||
private final String username;
|
||||
private final String xuid;
|
||||
private final int deviceOs;
|
||||
private final String languageCode;
|
||||
private final int uiProfile;
|
||||
private final int inputMode;
|
||||
private final String ip;
|
||||
private final LinkedPlayer linkedPlayer;
|
||||
private final boolean fromProxy;
|
||||
|
||||
public BedrockData(String version, String username, String xuid, int deviceId, String languageCode, int inputMode, String ip) {
|
||||
this(version, username, xuid, deviceId, languageCode, inputMode, ip, EXPECTED_LENGTH);
|
||||
private final int subscribeId;
|
||||
private final String verifyCode;
|
||||
|
||||
private final long timestamp;
|
||||
private final int dataLength;
|
||||
|
||||
public static BedrockData of(
|
||||
String version, String username, String xuid, int deviceOs,
|
||||
String languageCode, int uiProfile, int inputMode, String ip,
|
||||
LinkedPlayer linkedPlayer, boolean fromProxy, int subscribeId,
|
||||
String verifyCode, TimeSyncer timeSyncer) {
|
||||
return new BedrockData(version, username, xuid, deviceOs, languageCode, inputMode,
|
||||
uiProfile, ip, linkedPlayer, fromProxy, subscribeId, verifyCode,
|
||||
timeSyncer.getRealMillis(), EXPECTED_LENGTH);
|
||||
}
|
||||
|
||||
public static BedrockData of(
|
||||
String version, String username, String xuid, int deviceOs,
|
||||
String languageCode, int uiProfile, int inputMode, String ip,
|
||||
int subscribeId, String verifyCode, TimeSyncer timeSyncer) {
|
||||
return of(version, username, xuid, deviceOs, languageCode, uiProfile, inputMode, ip, null,
|
||||
false, subscribeId, verifyCode, timeSyncer);
|
||||
}
|
||||
|
||||
public static BedrockData fromString(String data) {
|
||||
String[] split = data.split("\0");
|
||||
if (split.length != EXPECTED_LENGTH) return null;
|
||||
if (split.length != EXPECTED_LENGTH) {
|
||||
return emptyData(split.length);
|
||||
}
|
||||
|
||||
LinkedPlayer linkedPlayer = LinkedPlayer.fromString(split[8]);
|
||||
// The format is the same as the order of the fields in this class
|
||||
return new BedrockData(
|
||||
split[0], split[1], split[2], Integer.parseInt(split[3]),
|
||||
split[4], Integer.parseInt(split[5]), split[6], split.length
|
||||
split[0], split[1], split[2], Integer.parseInt(split[3]), split[4],
|
||||
Integer.parseInt(split[5]), Integer.parseInt(split[6]), split[7], linkedPlayer,
|
||||
"1".equals(split[9]), Integer.parseInt(split[10]), split[11], Long.parseLong(split[12]), split.length
|
||||
);
|
||||
}
|
||||
|
||||
public static BedrockData fromRawData(byte[] data) {
|
||||
return fromString(new String(data));
|
||||
private static BedrockData emptyData(int dataLength) {
|
||||
return new BedrockData(null, null, null, -1, null, -1, -1, null, null, false, -1, null, -1,
|
||||
dataLength);
|
||||
}
|
||||
|
||||
public boolean hasPlayerLink() {
|
||||
return linkedPlayer != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return version +'\0'+ username +'\0'+ xuid +'\0'+ deviceId +'\0'+ languageCode +'\0'+
|
||||
inputMode +'\0'+ ip;
|
||||
// The format is the same as the order of the fields in this class
|
||||
return version + '\0' + username + '\0' + xuid + '\0' + deviceOs + '\0' +
|
||||
languageCode + '\0' + uiProfile + '\0' + inputMode + '\0' + ip + '\0' +
|
||||
(linkedPlayer != null ? linkedPlayer.toString() : "null") + '\0' +
|
||||
(fromProxy ? 1 : 0) + '\0' + subscribeId + '\0' + verifyCode + '\0' + timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BedrockData clone() throws CloneNotSupportedException {
|
||||
return (BedrockData) super.clone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,36 +25,41 @@
|
|||
|
||||
package org.geysermc.floodgate.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
public enum DeviceOS {
|
||||
|
||||
@JsonEnumDefaultValue
|
||||
/**
|
||||
* The Operation Systems where Bedrock players can connect with
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum DeviceOs {
|
||||
UNKNOWN("Unknown"),
|
||||
ANDROID("Android"),
|
||||
GOOGLE("Android"),
|
||||
IOS("iOS"),
|
||||
OSX("macOS"),
|
||||
FIREOS("FireOS"),
|
||||
AMAZON("Amazon"),
|
||||
GEARVR("Gear VR"),
|
||||
HOLOLENS("Hololens"),
|
||||
WIN10("Windows 10"),
|
||||
WIN32("Windows"),
|
||||
UWP("Windows 10"),
|
||||
WIN32("Windows x86"),
|
||||
DEDICATED("Dedicated"),
|
||||
ORBIS("PS4"),
|
||||
TVOS("Apple TV"),
|
||||
PS4("PS4"),
|
||||
NX("Switch"),
|
||||
SWITCH("Switch"),
|
||||
XBOX_ONE("Xbox One"),
|
||||
WIN_PHONE("Windows Phone");
|
||||
XBOX("Xbox One"),
|
||||
WINDOWS_PHONE("Windows Phone");
|
||||
|
||||
private static final DeviceOS[] VALUES = values();
|
||||
private static final DeviceOs[] VALUES = values();
|
||||
|
||||
private final String displayName;
|
||||
|
||||
DeviceOS(final String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public static DeviceOS getById(int id) {
|
||||
/**
|
||||
* Get the DeviceOs instance from the identifier.
|
||||
*
|
||||
* @param id the DeviceOs identifier
|
||||
* @return The DeviceOs or {@link #UNKNOWN} if the DeviceOs wasn't found
|
||||
*/
|
||||
public static DeviceOs getById(int id) {
|
||||
return id < VALUES.length ? VALUES[id] : VALUES[0];
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.util;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.*;
|
||||
import java.security.spec.EncodedKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
public class EncryptionUtil {
|
||||
public static String encrypt(Key key, String data) throws IllegalBlockSizeException,
|
||||
InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
KeyGenerator generator = KeyGenerator.getInstance("AES");
|
||||
generator.init(128);
|
||||
SecretKey secretKey = generator.generateKey();
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
byte[] encryptedText = cipher.doFinal(data.getBytes());
|
||||
|
||||
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(key instanceof PublicKey ? Cipher.PUBLIC_KEY : Cipher.PRIVATE_KEY, key);
|
||||
return Base64.getEncoder().encodeToString(cipher.doFinal(secretKey.getEncoded())) + '\0' +
|
||||
Base64.getEncoder().encodeToString(encryptedText);
|
||||
}
|
||||
|
||||
public static String encryptBedrockData(Key key, BedrockData data) throws IllegalBlockSizeException,
|
||||
InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
return encrypt(key, data.toString());
|
||||
}
|
||||
|
||||
public static byte[] decrypt(Key key, String encryptedData) throws IllegalBlockSizeException,
|
||||
InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
String[] split = encryptedData.split("\0");
|
||||
if (split.length != 2) {
|
||||
throw new IllegalArgumentException("Expected two arguments, got " + split.length);
|
||||
}
|
||||
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||
cipher.init(key instanceof PublicKey ? Cipher.PUBLIC_KEY : Cipher.PRIVATE_KEY, key);
|
||||
byte[] decryptedKey = cipher.doFinal(Base64.getDecoder().decode(split[0]));
|
||||
|
||||
SecretKey secretKey = new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");
|
||||
cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
return cipher.doFinal(Base64.getDecoder().decode(split[1]));
|
||||
}
|
||||
|
||||
public static BedrockData decryptBedrockData(Key key, String encryptedData) throws IllegalBlockSizeException,
|
||||
InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||
return BedrockData.fromRawData(decrypt(key, encryptedData));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends Key> T getKeyFromFile(Path fileLocation, Class<T> keyType) throws
|
||||
IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
||||
boolean isPublicKey = keyType == PublicKey.class;
|
||||
if (!isPublicKey && keyType != PrivateKey.class) {
|
||||
throw new RuntimeException("I can only read public and private keys!");
|
||||
}
|
||||
|
||||
byte[] key = Files.readAllBytes(fileLocation);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
EncodedKeySpec keySpec = isPublicKey ? new X509EncodedKeySpec(key) : new PKCS8EncodedKeySpec(key);
|
||||
return (T) (isPublicKey ?
|
||||
keyFactory.generatePublic(keySpec) :
|
||||
keyFactory.generatePrivate(keySpec)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -23,20 +23,18 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window.component;
|
||||
package org.geysermc.floodgate.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class LabelComponent extends FormComponent {
|
||||
import java.util.Properties;
|
||||
|
||||
public final class FloodgateInfoHolder {
|
||||
@Getter
|
||||
@Setter
|
||||
private String text;
|
||||
|
||||
public LabelComponent(String text) {
|
||||
super("label");
|
||||
|
||||
this.text = text;
|
||||
}
|
||||
private static Object config;
|
||||
@Getter
|
||||
@Setter
|
||||
private static Properties gitProperties;
|
||||
}
|
|
@ -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.floodgate.util;
|
||||
|
||||
public enum InputMode {
|
||||
UNKNOWN,
|
||||
KEYBOARD_MOUSE,
|
||||
TOUCH,
|
||||
CONTROLLER,
|
||||
VR;
|
||||
|
||||
private static final InputMode[] VALUES = values();
|
||||
|
||||
/**
|
||||
* Get the InputMode instance from the identifier.
|
||||
*
|
||||
* @param id the InputMode identifier
|
||||
* @return The InputMode or {@link #UNKNOWN} if the DeviceOs wasn't found
|
||||
*/
|
||||
public static InputMode getById(int id) {
|
||||
return VALUES.length > id ? VALUES[id] : VALUES[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.floodgate.util;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class InvalidFormatException extends Exception {
|
||||
private boolean header = false;
|
||||
|
||||
public InvalidFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidFormatException(String message, boolean header) {
|
||||
super(message);
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public InvalidFormatException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.floodgate.util;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class LinkedPlayer implements Cloneable {
|
||||
/**
|
||||
* The Java username of the linked player
|
||||
*/
|
||||
private final String javaUsername;
|
||||
/**
|
||||
* The Java UUID of the linked player
|
||||
*/
|
||||
private final UUID javaUniqueId;
|
||||
/**
|
||||
* The UUID of the Bedrock player
|
||||
*/
|
||||
private final UUID bedrockId;
|
||||
/**
|
||||
* If the LinkedPlayer is sent from a different platform. For example the LinkedPlayer is from
|
||||
* Bungee but the data has been sent to the Bukkit server.
|
||||
*/
|
||||
private boolean fromDifferentPlatform = false;
|
||||
|
||||
public static LinkedPlayer of(String javaUsername, UUID javaUniqueId, UUID bedrockId) {
|
||||
return new LinkedPlayer(javaUsername, javaUniqueId, bedrockId);
|
||||
}
|
||||
|
||||
public static LinkedPlayer fromString(String data) {
|
||||
String[] split = data.split(";");
|
||||
if (split.length != 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LinkedPlayer player = new LinkedPlayer(
|
||||
split[0], UUID.fromString(split[1]), UUID.fromString(split[2])
|
||||
);
|
||||
player.fromDifferentPlatform = true;
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return javaUsername + ';' + javaUniqueId.toString() + ';' + bedrockId.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedPlayer clone() throws CloneNotSupportedException {
|
||||
return (LinkedPlayer) super.clone();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.floodgate.util;
|
||||
|
||||
public enum UiProfile {
|
||||
CLASSIC,
|
||||
POCKET;
|
||||
|
||||
private static final UiProfile[] VALUES = values();
|
||||
|
||||
/**
|
||||
* Get the UiProfile instance from the identifier.
|
||||
*
|
||||
* @param id the UiProfile identifier
|
||||
* @return The UiProfile or {@link #CLASSIC} if the UiProfile wasn't found
|
||||
*/
|
||||
public static UiProfile getById(int id) {
|
||||
return VALUES.length > id ? VALUES[id] : VALUES[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.floodgate.util;
|
||||
|
||||
public enum WebsocketEventType {
|
||||
/**
|
||||
* Sent once we successfully connected to the server
|
||||
*/
|
||||
SUBSCRIBER_CREATED(0),
|
||||
/**
|
||||
* Sent every time a subscriber got added or disconnected
|
||||
*/
|
||||
SUBSCRIBER_COUNT(1),
|
||||
/**
|
||||
* Sent once the creator disconnected. After this packet the server will automatically close the
|
||||
* connection once the queue size (sent in {@link #ADDED_TO_QUEUE} and {@link #SKIN_UPLOADED}
|
||||
* reaches 0.
|
||||
*/
|
||||
CREATOR_DISCONNECTED(4),
|
||||
|
||||
/**
|
||||
* Sent every time a skin got added to the upload queue
|
||||
*/
|
||||
ADDED_TO_QUEUE(2),
|
||||
/**
|
||||
* Sent every time a skin got successfully uploaded
|
||||
*/
|
||||
SKIN_UPLOADED(3),
|
||||
|
||||
/**
|
||||
* Sent every time a news item was added
|
||||
*/
|
||||
NEWS_ADDED(6),
|
||||
|
||||
/**
|
||||
* Sent when the server wants you to know something. Currently used for violations that aren't
|
||||
* bad enough to close the connection
|
||||
*/
|
||||
LOG_MESSAGE(5);
|
||||
|
||||
private static final WebsocketEventType[] VALUES;
|
||||
|
||||
static {
|
||||
WebsocketEventType[] values = values();
|
||||
VALUES = new WebsocketEventType[values.length];
|
||||
for (WebsocketEventType value : values) {
|
||||
VALUES[value.id] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The ID is based of the time it got added. However, to keep the enum organized as time goes on,
|
||||
* it looks nicer to sort the events based of categories.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
WebsocketEventType(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static WebsocketEventType getById(int id) {
|
||||
return VALUES.length > id ? VALUES[id] : null;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -6,33 +6,59 @@
|
|||
<parent>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>geyser-parent</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>connector</artifactId>
|
||||
|
||||
<properties>
|
||||
<netty.version>4.1.59.Final</netty.version>
|
||||
<adventure.version>4.8.0</adventure.version>
|
||||
<fastutil.version>8.5.2</fastutil.version>
|
||||
<adventure.version>4.7.0</adventure.version>
|
||||
<jackson.version>2.10.2</jackson.version>
|
||||
<netty.version>4.1.59.Final</netty.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.geysermc</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>1.2.1-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Jackson JSON and YAML serialization -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.10.2</version>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.CloudburstMC.Protocol</groupId>
|
||||
<artifactId>bedrock-v431</artifactId>
|
||||
<version>530a0e3</version>
|
||||
<artifactId>bedrock-v440</artifactId>
|
||||
<version>1656151</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -120,9 +146,15 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.steveice10</groupId>
|
||||
<artifactId>mcprotocollib</artifactId>
|
||||
<version>8c204eb</version>
|
||||
<groupId>com.github.GeyserMC</groupId>
|
||||
<artifactId>MCAuthLib</artifactId>
|
||||
<version>0e48a094f2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.GeyserMC</groupId>
|
||||
<artifactId>MCProtocolLib</artifactId>
|
||||
<version>e316986</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -203,12 +235,15 @@
|
|||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
<version>0.9.11</version> <!-- This isn't the latest version to get round https://github.com/ronmamo/reflections/issues/273 -->
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.3</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<!-- Adventure text serialization -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
|
@ -239,11 +274,6 @@
|
|||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.GeyserMC</groupId>
|
||||
<artifactId>MCAuthLib</artifactId>
|
||||
<version>0e48a094f2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -305,6 +335,7 @@
|
|||
</replacement>
|
||||
<replacement>
|
||||
<token>String GIT_VERSION = ".*"</token>
|
||||
<!--suppress UnresolvedMavenProperty -->
|
||||
<value>String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}"</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
|
|
|
@ -33,11 +33,20 @@ import java.nio.file.Path;
|
|||
|
||||
public class FloodgateKeyLoader {
|
||||
public static Path getKeyPath(GeyserJacksonConfiguration config, Object floodgate, Path floodgateDataFolder, Path geyserDataFolder, GeyserLogger logger) {
|
||||
if (!config.getRemote().getAuthType().equals("floodgate")) {
|
||||
return geyserDataFolder.resolve(config.getFloodgateKeyFile());
|
||||
}
|
||||
|
||||
Path floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile());
|
||||
|
||||
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
||||
if (config.getFloodgateKeyFile().equals("public-key.pem")) {
|
||||
logger.info("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead");
|
||||
floodgateKey = geyserDataFolder.resolve("key.pem");
|
||||
}
|
||||
|
||||
if (!Files.exists(floodgateKey)) {
|
||||
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;
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector;
|
|||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.nukkitx.network.raknet.RakNetConstants;
|
||||
import com.nukkitx.network.util.EventLoops;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
|
@ -58,7 +59,14 @@ 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.world.block.entity.SkullBlockEntityTranslator;
|
||||
import org.geysermc.connector.skin.FloodgateSkinUploader;
|
||||
import org.geysermc.connector.utils.*;
|
||||
import org.geysermc.floodgate.crypto.AesCipher;
|
||||
import org.geysermc.floodgate.crypto.AesKeyProducer;
|
||||
import org.geysermc.floodgate.crypto.Base64Topping;
|
||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||
import org.geysermc.floodgate.news.NewsItemAction;
|
||||
import org.geysermc.floodgate.time.TimeSyncer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import javax.naming.directory.Attribute;
|
||||
|
@ -66,16 +74,18 @@ import javax.naming.directory.InitialDirContext;
|
|||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.Key;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
public class GeyserConnector {
|
||||
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper()
|
||||
.enable(JsonParser.Feature.IGNORE_UNDEFINED)
|
||||
.enable(JsonParser.Feature.ALLOW_COMMENTS)
|
||||
|
@ -86,7 +96,7 @@ public class GeyserConnector {
|
|||
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
|
||||
public static final String MINECRAFT_VERSION = "1.16.4 - 1.16.5";
|
||||
public static final String MINECRAFT_VERSION = MinecraftConstants.GAME_VERSION; // Change if multiple version strings are supported
|
||||
|
||||
/**
|
||||
* Oauth client ID for Microsoft authentication
|
||||
|
@ -108,11 +118,16 @@ public class GeyserConnector {
|
|||
@Setter
|
||||
private AuthType defaultAuthType;
|
||||
|
||||
private final TimeSyncer timeSyncer;
|
||||
private FloodgateCipher cipher;
|
||||
private FloodgateSkinUploader skinUploader;
|
||||
private final NewsHandler newsHandler;
|
||||
|
||||
private boolean shuttingDown = false;
|
||||
|
||||
private final ScheduledExecutorService generalThreadPool;
|
||||
|
||||
private BedrockServer bedrockServer;
|
||||
private final BedrockServer bedrockServer;
|
||||
private final PlatformType platformType;
|
||||
private final GeyserBootstrap bootstrap;
|
||||
|
||||
|
@ -196,6 +211,36 @@ public class GeyserConnector {
|
|||
|
||||
defaultAuthType = AuthType.getByName(config.getRemote().getAuthType());
|
||||
|
||||
TimeSyncer timeSyncer = null;
|
||||
if (defaultAuthType == AuthType.FLOODGATE) {
|
||||
timeSyncer = new TimeSyncer(Constants.NTP_SERVER);
|
||||
try {
|
||||
Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath());
|
||||
cipher = new AesCipher(new Base64Topping());
|
||||
cipher.init(key);
|
||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.loaded_key"));
|
||||
skinUploader = new FloodgateSkinUploader(this).start();
|
||||
} catch (Exception exception) {
|
||||
logger.severe(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception);
|
||||
}
|
||||
}
|
||||
this.timeSyncer = timeSyncer;
|
||||
|
||||
String branch = "unknown";
|
||||
int buildNumber = -1;
|
||||
try {
|
||||
Properties gitProperties = new Properties();
|
||||
gitProperties.load(FileUtils.getResource("git.properties"));
|
||||
branch = gitProperties.getProperty("git.branch");
|
||||
String build = gitProperties.getProperty("git.build.number");
|
||||
if (build != null) {
|
||||
buildNumber = Integer.parseInt(build);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("Failed to read git.properties", e);
|
||||
}
|
||||
newsHandler = new NewsHandler(branch, buildNumber);
|
||||
|
||||
CooldownUtils.setDefaultShowCooldown(config.getShowCooldown());
|
||||
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||
SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS = config.isAllowCustomSkulls();
|
||||
|
@ -250,7 +295,7 @@ public class GeyserConnector {
|
|||
for (GeyserSession session : players) {
|
||||
if (session == null) continue;
|
||||
if (session.getClientData() == null) continue;
|
||||
String os = session.getClientData().getDeviceOS().toString();
|
||||
String os = session.getClientData().getDeviceOs().toString();
|
||||
if (!valueMap.containsKey(os)) {
|
||||
valueMap.put(os, 1);
|
||||
} else {
|
||||
|
@ -287,6 +332,40 @@ public class GeyserConnector {
|
|||
return versionMap;
|
||||
}));
|
||||
}
|
||||
|
||||
// The following code can be attributed to the PaperMC project
|
||||
// https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0005-Paper-Metrics.patch#L614
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("javaVersion", () -> {
|
||||
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
Map<String, Integer> entry = new HashMap<>();
|
||||
entry.put(javaVersion, 1);
|
||||
|
||||
// http://openjdk.java.net/jeps/223
|
||||
// Java decided to change their versioning scheme and in doing so modified the
|
||||
// java.version system property to return $major[.$minor][.$security][-ea], as opposed to
|
||||
// 1.$major.0_$identifier we can handle pre-9 by checking if the "major" is equal to "1",
|
||||
// otherwise, 9+
|
||||
String majorVersion = javaVersion.split("\\.")[0];
|
||||
String release;
|
||||
|
||||
int indexOf = javaVersion.lastIndexOf('.');
|
||||
|
||||
if (majorVersion.equals("1")) {
|
||||
release = "Java " + javaVersion.substring(0, indexOf);
|
||||
} else {
|
||||
// of course, it really wouldn't be all that simple if they didn't add a quirk, now
|
||||
// would it valid strings for the major may potentially include values such as -ea to
|
||||
// denote a pre release
|
||||
Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
|
||||
if (versionMatcher.find()) {
|
||||
majorVersion = versionMatcher.group(0);
|
||||
}
|
||||
release = "Java " + majorVersion;
|
||||
}
|
||||
map.put(release, entry);
|
||||
return map;
|
||||
}));
|
||||
}
|
||||
|
||||
boolean isGui = false;
|
||||
|
@ -312,6 +391,8 @@ public class GeyserConnector {
|
|||
if (platformType == PlatformType.STANDALONE) {
|
||||
logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn"));
|
||||
}
|
||||
|
||||
newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
@ -356,6 +437,10 @@ public class GeyserConnector {
|
|||
|
||||
generalThreadPool.shutdown();
|
||||
bedrockServer.close();
|
||||
if (timeSyncer != null) {
|
||||
timeSyncer.shutdown();
|
||||
}
|
||||
newsHandler.shutdown();
|
||||
players.clear();
|
||||
defaultAuthType = null;
|
||||
this.getCommandManager().getCommands().clear();
|
||||
|
@ -434,6 +519,10 @@ public class GeyserConnector {
|
|||
return bootstrap.getWorldManager();
|
||||
}
|
||||
|
||||
public TimeSyncer getTimeSyncer() {
|
||||
return timeSyncer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to use XML reflections in the jar or manually find the reflections.
|
||||
* Will return true if the version number is not 'DEV' and the platform is not Fabric.
|
||||
|
|
|
@ -53,7 +53,7 @@ public abstract class CommandManager {
|
|||
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"));
|
||||
registerCommand(new AdvancementsCommand(connector, "advancements", "geyser.commands.advancements.desc", "geyser.command.advancements"));
|
||||
registerCommand(new AdvancementsCommand("advancements", "geyser.commands.advancements.desc", "geyser.command.advancements"));
|
||||
}
|
||||
|
||||
public void registerCommand(GeyserCommand command) {
|
||||
|
|
|
@ -25,25 +25,20 @@
|
|||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import org.geysermc.common.window.SimpleFormWindow;
|
||||
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.network.session.cache.AdvancementsCache;
|
||||
|
||||
public class AdvancementsCommand extends GeyserCommand {
|
||||
|
||||
public AdvancementsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
public AdvancementsCommand(String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session == null) return;
|
||||
|
||||
SimpleFormWindow window = session.getAdvancementsCache().buildMenuForm();
|
||||
session.sendForm(window, AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID);
|
||||
if (session != null) {
|
||||
session.getAdvancementsCache().buildAndShowMenuForm();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.geysermc.connector.command.GeyserCommand;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.LanguageUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ReloadCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
|
@ -51,8 +53,8 @@ public class ReloadCommand extends GeyserCommand {
|
|||
|
||||
sender.sendMessage(message);
|
||||
|
||||
for (GeyserSession otherSession : connector.getPlayers()) {
|
||||
otherSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getLocale()));
|
||||
for (GeyserSession otherSession : new ArrayList<>(connector.getPlayers())) {
|
||||
otherSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", otherSession.getLocale()));
|
||||
}
|
||||
connector.reload();
|
||||
}
|
||||
|
|
|
@ -32,17 +32,15 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
import org.geysermc.connector.utils.SettingsUtils;
|
||||
|
||||
public class SettingsCommand extends GeyserCommand {
|
||||
|
||||
public SettingsCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GeyserSession session, CommandSender sender, String[] args) {
|
||||
if (session == null) return;
|
||||
|
||||
SettingsUtils.buildForm(session);
|
||||
session.sendForm(session.getSettingsForm(), SettingsUtils.SETTINGS_FORM_ID);
|
||||
if (session != null) {
|
||||
session.sendForm(SettingsUtils.buildForm(session));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -87,8 +87,6 @@ public interface GeyserConfiguration {
|
|||
|
||||
boolean isAboveBedrockNetherBuilding();
|
||||
|
||||
boolean isCacheChunks();
|
||||
|
||||
boolean isForceResourcePacks();
|
||||
|
||||
boolean isXboxAchievementsEnabled();
|
||||
|
|
|
@ -111,9 +111,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||
@JsonProperty("default-locale")
|
||||
private String defaultLocale = null; // is null by default so system language takes priority
|
||||
|
||||
@JsonProperty("cache-chunks")
|
||||
private boolean cacheChunks = false;
|
||||
|
||||
@JsonProperty("cache-images")
|
||||
private int cacheImages = 0;
|
||||
|
||||
|
|
|
@ -34,8 +34,7 @@ import java.util.List;
|
|||
|
||||
@Getter
|
||||
public class BootstrapDumpInfo {
|
||||
|
||||
private PlatformType platform;
|
||||
private final PlatformType platform;
|
||||
|
||||
public BootstrapDumpInfo() {
|
||||
this.platform = GeyserConnector.getInstance().getPlatformType();
|
||||
|
@ -44,7 +43,6 @@ public class BootstrapDumpInfo {
|
|||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class PluginInfo {
|
||||
|
||||
public boolean enabled;
|
||||
public String name;
|
||||
public String version;
|
||||
|
@ -55,7 +53,6 @@ public class BootstrapDumpInfo {
|
|||
@Getter
|
||||
@AllArgsConstructor
|
||||
public static class ListenerInfo {
|
||||
|
||||
public String ip;
|
||||
public int port;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,8 @@ import org.geysermc.connector.network.BedrockProtocol;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.DockerCheck;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.floodgate.util.DeviceOS;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
import org.geysermc.floodgate.util.FloodgateInfoHolder;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -53,27 +54,29 @@ import java.util.Properties;
|
|||
|
||||
@Getter
|
||||
public class DumpInfo {
|
||||
|
||||
@JsonIgnore
|
||||
private static final long MEGABYTE = 1024L * 1024L;
|
||||
|
||||
private final DumpInfo.VersionInfo versionInfo;
|
||||
private Properties gitInfo;
|
||||
private final GeyserConfiguration config;
|
||||
private final Floodgate floodgate;
|
||||
private final Object2IntMap<DeviceOs> userPlatforms;
|
||||
private final HashInfo hashInfo;
|
||||
private final Object2IntMap<DeviceOS> userPlatforms;
|
||||
private final RamInfo ramInfo;
|
||||
private final BootstrapDumpInfo bootstrapInfo;
|
||||
|
||||
public DumpInfo() {
|
||||
this.versionInfo = new DumpInfo.VersionInfo();
|
||||
this.versionInfo = new VersionInfo();
|
||||
|
||||
try {
|
||||
this.gitInfo = new Properties();
|
||||
this.gitInfo.load(FileUtils.getResource("git.properties"));
|
||||
} catch (IOException ignored) { }
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
this.config = GeyserConnector.getInstance().getConfig();
|
||||
this.floodgate = new Floodgate();
|
||||
|
||||
String md5Hash = "unknown";
|
||||
String sha256Hash = "unknown";
|
||||
|
@ -92,14 +95,13 @@ public class DumpInfo {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
this.hashInfo = new HashInfo(md5Hash, sha256Hash);
|
||||
|
||||
this.ramInfo = new DumpInfo.RamInfo();
|
||||
|
||||
this.userPlatforms = new Object2IntOpenHashMap<>();
|
||||
for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) {
|
||||
DeviceOS device = session.getClientData().getDeviceOS();
|
||||
DeviceOs device = session.getClientData().getDeviceOs();
|
||||
userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1);
|
||||
}
|
||||
|
||||
|
@ -108,7 +110,6 @@ public class DumpInfo {
|
|||
|
||||
@Getter
|
||||
public static class VersionInfo {
|
||||
|
||||
private final String name;
|
||||
private final String version;
|
||||
private final String javaVersion;
|
||||
|
@ -123,7 +124,8 @@ public class DumpInfo {
|
|||
this.name = GeyserConnector.NAME;
|
||||
this.version = GeyserConnector.VERSION;
|
||||
this.javaVersion = System.getProperty("java.version");
|
||||
this.architecture = System.getProperty("os.arch"); // Usually gives Java architecture but still may be helpful.
|
||||
// Usually gives Java architecture but still may be helpful.
|
||||
this.architecture = System.getProperty("os.arch");
|
||||
this.operatingSystem = System.getProperty("os.name");
|
||||
this.operatingSystemVersion = System.getProperty("os.version");
|
||||
|
||||
|
@ -132,18 +134,10 @@ public class DumpInfo {
|
|||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class HashInfo {
|
||||
private final String md5Hash;
|
||||
private final String sha256Hash;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class NetworkInfo {
|
||||
|
||||
private String internalIP;
|
||||
private final boolean dockerCheck;
|
||||
private String internalIP;
|
||||
|
||||
NetworkInfo() {
|
||||
if (AsteriskSerializer.showSensitive) {
|
||||
|
@ -156,7 +150,8 @@ public class DumpInfo {
|
|||
try {
|
||||
// Fallback to the normal way of getting the local IP
|
||||
this.internalIP = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException ignored) { }
|
||||
} catch (UnknownHostException ignored) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sometimes the internal IP is the external IP...
|
||||
|
@ -169,7 +164,6 @@ public class DumpInfo {
|
|||
|
||||
@Getter
|
||||
public static class MCInfo {
|
||||
|
||||
private final String bedrockVersion;
|
||||
private final int bedrockProtocol;
|
||||
private final String javaVersion;
|
||||
|
@ -184,8 +178,25 @@ public class DumpInfo {
|
|||
}
|
||||
|
||||
@Getter
|
||||
public static class RamInfo {
|
||||
public static class Floodgate {
|
||||
private final Properties gitInfo;
|
||||
private final Object config;
|
||||
|
||||
Floodgate() {
|
||||
this.gitInfo = FloodgateInfoHolder.getGitProperties();
|
||||
this.config = FloodgateInfoHolder.getConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public static class HashInfo {
|
||||
private final String md5Hash;
|
||||
private final String sha256Hash;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class RamInfo {
|
||||
private final long free;
|
||||
private final long total;
|
||||
private final long max;
|
||||
|
|
|
@ -44,7 +44,7 @@ public class AbstractArrowEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
byte data = (byte) entityMetadata.getValue();
|
||||
|
||||
metadata.getFlags().setFlag(EntityFlag.CRITICAL, (data & 0x01) == 0x01);
|
||||
|
|
|
@ -52,12 +52,12 @@ public class AreaEffectCloudEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, entityMetadata.getValue());
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 8) {
|
||||
} else if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.EFFECT_COLOR, entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 10) {
|
||||
} else if (entityMetadata.getId() == 11) {
|
||||
Particle particle = (Particle) entityMetadata.getValue();
|
||||
int particleId = EffectRegistry.getParticleId(session, particle.getType());
|
||||
if (particleId != -1) {
|
||||
|
|
|
@ -99,24 +99,24 @@ public class BoatEntity extends Entity {
|
|||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
// Time since last hit
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HURT_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Rocking direction
|
||||
if (entityMetadata.getId() == 8) {
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// 'Health' in Bedrock, damage taken in Java
|
||||
if (entityMetadata.getId() == 9) {
|
||||
if (entityMetadata.getId() == 10) {
|
||||
// Not exactly health but it makes motion in Bedrock
|
||||
metadata.put(EntityData.HEALTH, 40 - ((int) (float) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
if (entityMetadata.getId() == 10) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.put(EntityData.VARIANT, entityMetadata.getValue());
|
||||
} else if (entityMetadata.getId() == 11) {
|
||||
} else if (entityMetadata.getId() == 12) {
|
||||
isPaddlingLeft = (boolean) entityMetadata.getValue();
|
||||
if (isPaddlingLeft) {
|
||||
// Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
|
||||
|
@ -136,7 +136,7 @@ public class BoatEntity extends Entity {
|
|||
metadata.put(EntityData.ROW_TIME_LEFT, 0.0f);
|
||||
}
|
||||
}
|
||||
else if (entityMetadata.getId() == 12) {
|
||||
else if (entityMetadata.getId() == 13) {
|
||||
isPaddlingRight = (boolean) entityMetadata.getValue();
|
||||
if (isPaddlingRight) {
|
||||
paddleTimeRight = 0f;
|
||||
|
@ -151,7 +151,7 @@ public class BoatEntity extends Entity {
|
|||
} else {
|
||||
metadata.put(EntityData.ROW_TIME_RIGHT, 0.0f);
|
||||
}
|
||||
} else if (entityMetadata.getId() == 13) {
|
||||
} else if (entityMetadata.getId() == 14) {
|
||||
// Possibly - I don't think this does anything?
|
||||
metadata.put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue());
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 13) {
|
||||
if (entityMetadata.getId() == 14) {
|
||||
metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue());
|
||||
}
|
||||
if (entityMetadata.getId() == 14) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage((Component) entityMetadata.getValue()));
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -56,7 +56,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
customBlock = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
|
@ -65,7 +65,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
|||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
if (entityMetadata.getId() == 12) {
|
||||
customBlockOffset = (int) entityMetadata.getValue();
|
||||
|
||||
if (showCustomBlock) {
|
||||
|
@ -74,7 +74,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity {
|
|||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
if (entityMetadata.getId() == 13) {
|
||||
if ((boolean) entityMetadata.getValue()) {
|
||||
showCustomBlock = true;
|
||||
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId(customBlock));
|
||||
|
|
|
@ -47,7 +47,7 @@ public class EnderCrystalEntity extends Entity {
|
|||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
// Show beam
|
||||
// Usually performed client-side on Bedrock except for Ender Dragon respawn event
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
if (entityMetadata.getValue() instanceof Position) {
|
||||
Position pos = (Position) entityMetadata.getValue();
|
||||
metadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ()));
|
||||
|
@ -56,7 +56,7 @@ public class EnderCrystalEntity extends Entity {
|
|||
}
|
||||
}
|
||||
// There is a base located on the ender crystal
|
||||
if (entityMetadata.getId() == 8) {
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.getFlags().setFlag(EntityFlag.SHOW_BOTTOM, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -303,31 +303,13 @@ public class Entity {
|
|||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
|
||||
// Triggered when crawling
|
||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
|
||||
float width = entityType.getWidth();
|
||||
float height = entityType.getHeight();
|
||||
switch (pose) {
|
||||
case SLEEPING:
|
||||
if (this instanceof LivingEntity) {
|
||||
width = 0.2f;
|
||||
height = 0.2f;
|
||||
}
|
||||
break;
|
||||
case SNEAKING:
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
height = 1.5f;
|
||||
}
|
||||
break;
|
||||
case FALL_FLYING:
|
||||
case SPIN_ATTACK:
|
||||
case SWIMMING:
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
// Seems like this is only cared about for players; nothing else
|
||||
height = 0.6f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, width);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, height);
|
||||
setDimensions(pose);
|
||||
break;
|
||||
case 7: // Freezing ticks
|
||||
// The value that Java edition gives us is in ticks, but Bedrock uses a float percentage of the strength 0.0 -> 1.0
|
||||
// The Java client caps its freezing tick percentage at 140
|
||||
int freezingTicks = Math.min((int) entityMetadata.getValue(), 140);
|
||||
metadata.put(EntityData.FREEZING_EFFECT_STRENGTH, (freezingTicks / 140f));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -345,6 +327,15 @@ public class Entity {
|
|||
session.sendUpstreamPacket(entityDataPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height and width of the entity's bounding box
|
||||
*/
|
||||
protected void setDimensions(Pose pose) {
|
||||
// No flexibility options for basic entities
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth());
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* x = Pitch, y = HeadYaw, z = Yaw
|
||||
*
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.geysermc.connector.network.session.GeyserSession;
|
|||
|
||||
public class ExpOrbEntity extends Entity {
|
||||
|
||||
private int amount;
|
||||
private final int amount;
|
||||
|
||||
public ExpOrbEntity(int amount, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.geysermc.connector.entity.type.EntityType;
|
|||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.utils.FireworkColor;
|
||||
import org.geysermc.connector.utils.MathUtils;
|
||||
import org.geysermc.floodgate.util.DeviceOS;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -55,7 +55,7 @@ public class FireworkEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
ItemStack item = (ItemStack) entityMetadata.getValue();
|
||||
if (item == null) {
|
||||
return;
|
||||
|
@ -68,7 +68,8 @@ public class FireworkEntity extends Entity {
|
|||
|
||||
// TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices.
|
||||
// https://bugs.mojang.com/browse/MCPE-89115
|
||||
if (session.getClientData().getDeviceOS() == DeviceOS.XBOX_ONE || session.getClientData().getDeviceOS() == DeviceOS.ORBIS) {
|
||||
if (session.getClientData().getDeviceOs() == DeviceOs.XBOX
|
||||
|| session.getClientData().getDeviceOs() == DeviceOs.PS4) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -134,7 +135,7 @@ public class FireworkEntity extends Entity {
|
|||
NbtMapBuilder builder = NbtMap.builder();
|
||||
builder.put("Fireworks", fireworksBuilder.build());
|
||||
metadata.put(EntityData.DISPLAY_ITEM, builder.build());
|
||||
} else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||
} else if (entityMetadata.getId() == 9 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) {
|
||||
//Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too.
|
||||
PlayerEntity entity = session.getPlayerEntity();
|
||||
float yaw = entity.getRotation().getX();
|
||||
|
|
|
@ -67,7 +67,7 @@ public class FishingHookEntity extends ThrowableEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) { // Hooked entity
|
||||
if (entityMetadata.getId() == 8) { // Hooked entity
|
||||
int hookedEntityId = (int) entityMetadata.getValue() - 1;
|
||||
Entity entity = session.getEntityCache().getEntityByJavaId(hookedEntityId);
|
||||
if (entity == null && session.getPlayerEntity().getEntityId() == hookedEntityId) {
|
||||
|
@ -174,11 +174,8 @@ public class FishingHookEntity extends ThrowableEntity {
|
|||
* @return true if this entity is currently in air.
|
||||
*/
|
||||
protected boolean isInAir(GeyserSession session) {
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
return false;
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return block == BlockTranslator.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,7 +42,7 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 13 && !showCustomBlock) {
|
||||
if (entityMetadata.getId() == 14 && !showCustomBlock) {
|
||||
hasFuel = (boolean) entityMetadata.getValue();
|
||||
updateDefaultBlockMetadata(session);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class ItemEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
AddItemEntityPacket itemPacket = new AddItemEntityPacket();
|
||||
itemPacket.setRuntimeEntityId(geyserId);
|
||||
itemPacket.setPosition(position.add(0d, this.entityType.getOffset(), 0d));
|
||||
|
|
|
@ -84,7 +84,7 @@ public class ItemFrameEntity extends Entity {
|
|||
@Override
|
||||
public void spawnEntity(GeyserSession session) {
|
||||
NbtMapBuilder blockBuilder = NbtMap.builder()
|
||||
.putString("name", "minecraft:frame")
|
||||
.putString("name", this.entityType == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame")
|
||||
.putInt("version", session.getBlockTranslator().getBlockStateVersion());
|
||||
blockBuilder.put("states", NbtMap.builder()
|
||||
.putInt("facing_direction", direction.ordinal())
|
||||
|
@ -105,7 +105,7 @@ public class ItemFrameEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
|
||||
if (entityMetadata.getId() == 8 && entityMetadata.getValue() != null) {
|
||||
this.heldItem = (ItemStack) entityMetadata.getValue();
|
||||
ItemData itemData = ItemTranslator.translateToBedrock(session, heldItem);
|
||||
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||
|
@ -124,11 +124,11 @@ public class ItemFrameEntity extends Entity {
|
|||
cachedTag = tag.build();
|
||||
updateBlock(session);
|
||||
}
|
||||
else if (entityMetadata.getId() == 7 && entityMetadata.getValue() == null && cachedTag != null) {
|
||||
else if (entityMetadata.getId() == 8 && entityMetadata.getValue() == null && cachedTag != null) {
|
||||
cachedTag = getDefaultTag();
|
||||
updateBlock(session);
|
||||
}
|
||||
else if (entityMetadata.getId() == 8) {
|
||||
else if (entityMetadata.getId() == 9) {
|
||||
rotation = ((int) entityMetadata.getValue()) * 45;
|
||||
if (cachedTag == null) {
|
||||
updateBlock(session);
|
||||
|
@ -167,7 +167,7 @@ public class ItemFrameEntity extends Entity {
|
|||
builder.putInt("y", bedrockPosition.getY());
|
||||
builder.putInt("z", bedrockPosition.getZ());
|
||||
builder.putByte("isMovable", (byte) 1);
|
||||
builder.putString("id", "ItemFrame");
|
||||
builder.putString("id", this.entityType == EntityType.GLOW_ITEM_FRAME ? "GlowItemFrame" : "ItemFrame");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.connector.entity;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
|
@ -68,7 +69,7 @@ public class LivingEntity extends Entity {
|
|||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
switch (entityMetadata.getId()) {
|
||||
case 7: // blocking
|
||||
case 8: // blocking
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
||||
//blocking gets triggered when using a bow, but if we set USING_ITEM for all items, it may look like
|
||||
|
@ -81,24 +82,22 @@ public class LivingEntity extends Entity {
|
|||
// Riptide spin attack
|
||||
metadata.getFlags().setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04);
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
metadata.put(EntityData.EFFECT_COLOR, entityMetadata.getValue());
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
metadata.put(EntityData.EFFECT_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
break;
|
||||
case 13: // Bed Position
|
||||
case 14: // Bed Position
|
||||
Position bedPosition = (Position) entityMetadata.getValue();
|
||||
if (bedPosition != null) {
|
||||
metadata.put(EntityData.BED_POSITION, Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()));
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
}
|
||||
int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition);
|
||||
// Bed has to be updated, or else player is floating in the air
|
||||
ChunkUtils.updateBlock(session, bed, bedPosition);
|
||||
// Indicate that the player should enter the sleep cycle
|
||||
// Has to be a byte or it does not work
|
||||
// (Bed position is what actually triggers sleep - "pose" is only optional)
|
||||
|
@ -113,6 +112,16 @@ public class LivingEntity extends Entity {
|
|||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDimensions(Pose pose) {
|
||||
if (pose == Pose.SLEEPING) {
|
||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
||||
} else {
|
||||
super.setDimensions(pose);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAllEquipment(GeyserSession session) {
|
||||
if (!valid) return;
|
||||
|
||||
|
|
|
@ -40,33 +40,33 @@ public class MinecartEntity extends Entity {
|
|||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
metadata.put(EntityData.HEALTH, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Direction in which the minecart is shaking
|
||||
if (entityMetadata.getId() == 8) {
|
||||
if (entityMetadata.getId() == 9) {
|
||||
metadata.put(EntityData.HURT_DIRECTION, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// Power in Java, time in Bedrock
|
||||
if (entityMetadata.getId() == 9) {
|
||||
if (entityMetadata.getId() == 10) {
|
||||
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
||||
}
|
||||
|
||||
if (!(this instanceof DefaultBlockMinecartEntity)) { // Handled in the DefaultBlockMinecartEntity class
|
||||
// Custom block
|
||||
if (entityMetadata.getId() == 10) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.put(EntityData.DISPLAY_ITEM, session.getBlockTranslator().getBedrockBlockId((int) entityMetadata.getValue()));
|
||||
}
|
||||
|
||||
// Custom block offset
|
||||
if (entityMetadata.getId() == 11) {
|
||||
if (entityMetadata.getId() == 12) {
|
||||
metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue());
|
||||
}
|
||||
|
||||
// If the custom block should be enabled
|
||||
if (entityMetadata.getId() == 12) {
|
||||
if (entityMetadata.getId() == 13) {
|
||||
// Needs a byte based off of Java's boolean
|
||||
metadata.put(EntityData.CUSTOM_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class TNTEntity extends Entity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
currentTick = (int) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.IGNITED, true);
|
||||
metadata.put(EntityData.FUSE_LENGTH, currentTick);
|
||||
|
|
|
@ -166,13 +166,8 @@ public class ThrowableEntity extends Entity implements Tickable {
|
|||
* @return true if this entity is currently in water.
|
||||
*/
|
||||
protected boolean isInWater(GeyserSession session) {
|
||||
if (session.getConnector().getConfig().isCacheChunks()) {
|
||||
if (0 <= position.getFloorY() && position.getFloorY() <= 255) {
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt());
|
||||
return BlockStateValues.getWaterLevel(block) != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,7 +51,7 @@ public class ThrownPotionEntity extends ThrowableEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7 && entityMetadata.getType() == MetadataType.ITEM) {
|
||||
if (entityMetadata.getId() == 8 && entityMetadata.getType() == MetadataType.ITEM) {
|
||||
ItemStack itemStack = (ItemStack) entityMetadata.getValue();
|
||||
ItemEntry itemEntry = ItemRegistry.getItem(itemStack);
|
||||
if (itemEntry.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) {
|
||||
|
|
|
@ -44,17 +44,17 @@ public class TippedArrowEntity extends AbstractArrowEntity {
|
|||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
// Arrow potion effect color
|
||||
if (entityMetadata.getId() == 9) {
|
||||
if (entityMetadata.getId() == 10) {
|
||||
int potionColor = (int) entityMetadata.getValue();
|
||||
// -1 means no color
|
||||
if (potionColor == -1) {
|
||||
metadata.remove(EntityData.CUSTOM_DISPLAY);
|
||||
metadata.put(EntityData.CUSTOM_DISPLAY, 0);
|
||||
} else {
|
||||
TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor);
|
||||
if (potion != null && potion.getJavaColor() != -1) {
|
||||
metadata.put(EntityData.CUSTOM_DISPLAY, (byte) potion.getBedrockId());
|
||||
} else {
|
||||
metadata.remove(EntityData.CUSTOM_DISPLAY);
|
||||
metadata.put(EntityData.CUSTOM_DISPLAY, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class TridentEntity extends AbstractArrowEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 10) {
|
||||
if (entityMetadata.getId() == 11) {
|
||||
metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public class WitherSkullEntity extends ItemedFireballEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 7) {
|
||||
if (entityMetadata.getId() == 8) {
|
||||
boolean newIsCharged = (boolean) entityMetadata.getValue();
|
||||
if (newIsCharged != isCharged) {
|
||||
isCharged = newIsCharged;
|
||||
|
|
|
@ -40,7 +40,7 @@ public class AgeableEntity extends CreatureEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
boolean isBaby = (boolean) entityMetadata.getValue();
|
||||
metadata.put(EntityData.SCALE, isBaby ? .55f : 1f);
|
||||
metadata.getFlags().setFlag(EntityFlag.BABY, isBaby);
|
||||
|
|
|
@ -126,7 +126,7 @@ public class ArmorStandEntity extends LivingEntity {
|
|||
}
|
||||
} else if (entityMetadata.getId() == 2) {
|
||||
updateSecondEntityStatus(false);
|
||||
} else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
} else if (entityMetadata.getId() == 15 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
|
||||
// isSmall
|
||||
|
@ -169,37 +169,37 @@ public class ArmorStandEntity extends LivingEntity {
|
|||
EntityFlag negativeYToggle = null;
|
||||
EntityFlag negativeZToggle = null;
|
||||
switch (entityMetadata.getId()) {
|
||||
case 15: // Head
|
||||
case 16: // Head
|
||||
dataLeech = EntityData.MARK_VARIANT;
|
||||
negativeXToggle = EntityFlag.INTERESTED;
|
||||
negativeYToggle = EntityFlag.CHARGED;
|
||||
negativeZToggle = EntityFlag.POWERED;
|
||||
break;
|
||||
case 16: // Body
|
||||
case 17: // Body
|
||||
dataLeech = EntityData.VARIANT;
|
||||
negativeXToggle = EntityFlag.IN_LOVE;
|
||||
negativeYToggle = EntityFlag.CELEBRATING;
|
||||
negativeZToggle = EntityFlag.CELEBRATING_SPECIAL;
|
||||
break;
|
||||
case 17: // Left arm
|
||||
case 18: // Left arm
|
||||
dataLeech = EntityData.TRADE_TIER;
|
||||
negativeXToggle = EntityFlag.CHARGING;
|
||||
negativeYToggle = EntityFlag.CRITICAL;
|
||||
negativeZToggle = EntityFlag.DANCING;
|
||||
break;
|
||||
case 18: // Right arm
|
||||
case 19: // Right arm
|
||||
dataLeech = EntityData.MAX_TRADE_TIER;
|
||||
negativeXToggle = EntityFlag.ELDER;
|
||||
negativeYToggle = EntityFlag.EMOTING;
|
||||
negativeZToggle = EntityFlag.IDLING;
|
||||
break;
|
||||
case 19: // Left leg
|
||||
case 20: // Left leg
|
||||
dataLeech = EntityData.SKIN_ID;
|
||||
negativeXToggle = EntityFlag.IS_ILLAGER_CAPTAIN;
|
||||
negativeYToggle = EntityFlag.IS_IN_UI;
|
||||
negativeZToggle = EntityFlag.LINGERING;
|
||||
break;
|
||||
case 20: // Right leg
|
||||
case 21: // Right leg
|
||||
dataLeech = EntityData.HURT_DIRECTION;
|
||||
negativeXToggle = EntityFlag.IS_PREGNANT;
|
||||
negativeYToggle = EntityFlag.SHEARED;
|
||||
|
|
|
@ -39,7 +39,7 @@ public class BatEntity extends AmbientEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.RESTING, (xd & 0x01) == 0x01);
|
||||
}
|
||||
|
|
|
@ -23,37 +23,21 @@
|
|||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.common.window;
|
||||
package org.geysermc.connector.entity.living;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.response.FormResponse;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
|
||||
public abstract class FormWindow {
|
||||
|
||||
@Getter
|
||||
private final String type;
|
||||
|
||||
@Getter
|
||||
protected FormResponse response;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected boolean closed;
|
||||
|
||||
public FormWindow(String type) {
|
||||
this.type = type;
|
||||
public class GlowSquidEntity extends SquidEntity {
|
||||
public GlowSquidEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
// Lombok won't work here, so we need to make our own method
|
||||
public void setResponse(FormResponse response) {
|
||||
this.response = response;
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
// TODO "dark ticks remaining" ??? does this have a Bedrock equivalent?
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public abstract String getJSONData();
|
||||
|
||||
public abstract void setResponse(String response);
|
||||
|
||||
}
|
|
@ -41,7 +41,7 @@ public class InsentientEntity extends LivingEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
if (entityMetadata.getId() == 15 && entityMetadata.getType() == MetadataType.BYTE) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
metadata.getFlags().setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class IronGolemEntity extends GolemEntity {
|
|||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
if (entityMetadata.getId() == 8) {
|
||||
if (entityMetadata.getId() == 9) {
|
||||
// Required so the resource pack sees the entity health
|
||||
attributes.put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(metadata.getFloat(EntityData.HEALTH), 100f));
|
||||
updateBedrockAttributes(session);
|
||||
|
|
|
@ -39,7 +39,7 @@ public class SlimeEntity extends InsentientEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
this.metadata.put(EntityData.SCALE, 0.10f + (int) entityMetadata.getValue());
|
||||
}
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
|
|
|
@ -39,7 +39,7 @@ public class SnowGolemEntity extends GolemEntity {
|
|||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
if (entityMetadata.getId() == 15) {
|
||||
if (entityMetadata.getId() == 16) {
|
||||
byte xd = (byte) entityMetadata.getValue();
|
||||
// Handle the visibility of the pumpkin
|
||||
metadata.getFlags().setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10);
|
||||
|
|
|
@ -29,7 +29,6 @@ import com.nukkitx.math.vector.Vector3f;
|
|||
import org.geysermc.connector.entity.type.EntityType;
|
||||
|
||||
public class SquidEntity extends WaterEntity {
|
||||
|
||||
public SquidEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 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.entity.living.animal;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.geysermc.connector.entity.type.EntityType;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||
|
||||
public class AxolotlEntity extends AnimalEntity {
|
||||
public AxolotlEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||
super(entityId, geyserId, entityType, position, motion, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||
super.updateBedrockMetadata(entityMetadata, session);
|
||||
if (entityMetadata.getId() == 17) {
|
||||
int variant = (int) entityMetadata.getValue();
|
||||
switch (variant) {
|
||||
case 1: // Java - "Wild" (brown)
|
||||
variant = 3;
|
||||
break;
|
||||
case 3: // Java - cyan
|
||||
variant = 1;
|
||||
break;
|
||||
}
|
||||
metadata.put(EntityData.VARIANT, variant);
|
||||
}
|
||||
else if (entityMetadata.getId() == 18) {
|
||||
metadata.getFlags().setFlag(EntityFlag.PLAYING_DEAD, (boolean) entityMetadata.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEat(GeyserSession session, String javaIdentifierStripped, ItemEntry itemEntry) {
|
||||
return javaIdentifierStripped.equals("tropical_fish_bucket");
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue