diff --git a/README.md b/README.md
index 874c79f33a2..9878fa5a04c 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,6 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
- [ ] Beacon
- [ ] Cartography Table
- [ ] Stonecutter
- - [ ] Villager Trading
- Some Entity Flags
## Compiling
diff --git a/bootstrap/bukkit/pom.xml b/bootstrap/bukkit/pom.xml
index 1f831d6733a..95926854dec 100644
--- a/bootstrap/bukkit/pom.xml
+++ b/bootstrap/bukkit/pom.xml
@@ -71,6 +71,10 @@
it.unimi.dsi.fastutil
org.geysermc.platform.bukkit.shaded.fastutil
+
+ com.fasterxml.jackson
+ org.geysermc.platform.bukkit.shaded.jackson
+
diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java
index fbfcce80c29..327c41dae3e 100644
--- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java
+++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java
@@ -25,120 +25,29 @@
package org.geysermc.platform.bukkit;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
import org.bukkit.Bukkit;
-import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.Plugin;
import org.geysermc.connector.FloodgateKeyLoader;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
-import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
-public class GeyserBukkitConfiguration implements GeyserConfiguration {
+@Getter
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class GeyserBukkitConfiguration extends GeyserJacksonConfiguration {
- private FileConfiguration config;
- private File dataFolder;
-
- private BukkitBedrockConfiguration bedrockConfig;
- private BukkitRemoteConfiguration remoteConfig;
- private BukkitMetricsInfo metricsInfo;
-
- private Map userAuthInfo = new HashMap<>();
+ @JsonProperty("floodgate-key-file")
+ private String floodgateKeyFile;
private Path floodgateKey;
- public GeyserBukkitConfiguration(File dataFolder, FileConfiguration config) {
- this.dataFolder = dataFolder;
- this.config = config;
-
- bedrockConfig = new BukkitBedrockConfiguration();
- remoteConfig = new BukkitRemoteConfiguration();
- metricsInfo = new BukkitMetricsInfo();
-
- if (!config.contains("userAuths"))
- return;
-
- for (String key : config.getConfigurationSection("userAuths").getKeys(false)) {
- userAuthInfo.put(key, new BukkitUserAuthenticationInfo(key));
- }
- }
-
public void loadFloodgate(GeyserBukkitPlugin plugin) {
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit");
- floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
- }
-
- @Override
- public IBedrockConfiguration getBedrock() {
- return bedrockConfig;
- }
-
- @Override
- public IRemoteConfiguration getRemote() {
- return remoteConfig;
- }
-
- @Override
- public Map getUserAuths() {
- return userAuthInfo;
- }
-
- @Override
- public boolean isCommandSuggestions() {
- return config.getBoolean("command-suggestions", true);
- }
-
- @Override
- public boolean isPassthroughMotd() {
- return config.getBoolean("passthrough-motd", false);
- }
-
- @Override
- public boolean isPassthroughPlayerCounts() {
- return config.getBoolean("passthrough-player-counts", false);
- }
-
- @Override
- public boolean isLegacyPingPassthrough() {
- return config.getBoolean("legacy-ping-passthrough", false);
- }
-
- @Override
- public int getPingPassthroughInterval() {
- return config.getInt("ping-passthrough-interval", 3);
- }
-
- @Override
- public int getMaxPlayers() {
- return config.getInt("max-players", 10);
- }
-
- @Override
- public boolean isDebugMode() {
- return config.getBoolean("debug-mode", false);
- }
-
- @Override
- public int getGeneralThreadPool() {
- return config.getInt("general-thread-pool", 32);
- }
-
- @Override
- public boolean isAllowThirdPartyCapes() {
- return config.getBoolean("allow-third-party-capes", true);
- }
-
- @Override
- public boolean isAllowThirdPartyEars() {
- return config.getBoolean("allow-third-party-ears", false);
- }
-
- @Override
- public String getDefaultLocale() {
- return config.getString("default-locale", "en_us");
+ floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(plugin.getDataFolder().toString(), plugin.getConfig().getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
}
@Override
@@ -150,97 +59,4 @@ public Path getFloodgateKeyFile() {
public boolean isCacheChunks() {
return true; // We override this as with Bukkit, we have direct access to the server implementation
}
-
- @Override
- public int getCacheSkins() {
- return config.getInt("cache-skins", 0);
- }
-
- @Override
- public boolean isAboveBedrockNetherBuilding() {
- return config.getBoolean("above-bedrock-nether-building", false);
- }
-
- @Override
- public IMetricsInfo getMetrics() {
- return metricsInfo;
- }
-
- public class BukkitBedrockConfiguration implements IBedrockConfiguration {
-
- @Override
- public String getAddress() {
- return config.getString("bedrock.address", "0.0.0.0");
- }
-
- @Override
- public int getPort() {
- return config.getInt("bedrock.port", 25565);
- }
-
- @Override
- public String getMotd1() {
- return config.getString("bedrock.motd1", "GeyserMC");
- }
-
- @Override
- public String getMotd2() {
- return config.getString("bedrock.motd2", "GeyserMC");
- }
- }
-
- public class BukkitRemoteConfiguration implements IRemoteConfiguration {
-
- @Override
- public String getAddress() {
- return config.getString("remote.address", "127.0.0.1");
- }
-
- @Override
- public int getPort() {
- return config.getInt("remote.port", 25565);
- }
-
- @Override
- public String getAuthType() {
- return config.getString("remote.auth-type", "online");
- }
- }
-
- public class BukkitUserAuthenticationInfo implements IUserAuthenticationInfo {
-
- private String key;
-
- public BukkitUserAuthenticationInfo(String key) {
- this.key = key;
- }
-
- @Override
- public String getEmail() {
- return config.getString("userAuths." + key + ".email");
- }
-
- @Override
- public String getPassword() {
- return config.getString("userAuths." + key + ".password");
- }
- }
-
- public class BukkitMetricsInfo implements IMetricsInfo {
-
- @Override
- public boolean isEnabled() {
- return config.getBoolean("metrics.enabled", true);
- }
-
- @Override
- public String getUniqueId() {
- return config.getString("metrics.uuid", "generateduuid");
- }
- }
-
- @Override
- public int getConfigVersion() {
- return config.getInt("config-version", 0);
- }
}
diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java
index 5f0e967a2f2..52893fc89e5 100644
--- a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java
+++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java
@@ -28,20 +28,24 @@
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.common.PlatformType;
-import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
+import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor;
import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager;
import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener;
import org.geysermc.platform.bukkit.world.GeyserBukkitWorldManager;
import us.myles.ViaVersion.api.Via;
+import java.io.File;
+import java.io.IOException;
import java.util.UUID;
+import java.util.logging.Level;
public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
@@ -56,26 +60,34 @@ public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap {
@Override
public void onEnable() {
- saveDefaultConfig();
-
- this.geyserConfig = new GeyserBukkitConfiguration(getDataFolder(), getConfig());
- if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
- getConfig().set("metrics.uuid", UUID.randomUUID().toString());
- saveConfig();
+ // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
+ try {
+ if (!getDataFolder().exists())
+ getDataFolder().mkdir();
+ File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
+ this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBukkitConfiguration.class);
+ } catch (IOException ex) {
+ getLogger().log(Level.WARNING, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
+ ex.printStackTrace();
}
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) {
- getConfig().set("remote.address", Bukkit.getIp());
+ geyserConfig.getRemote().setAddress(Bukkit.getIp());
}
- getConfig().set("remote.port", Bukkit.getPort());
- saveConfig();
+ geyserConfig.getRemote().setPort(Bukkit.getPort());
this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
+ if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") == null) {
+ geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
+ this.getPluginLoader().disablePlugin(this);
+ return;
+ }
+
geyserConfig.loadFloodgate(this);
this.connector = GeyserConnector.start(PlatformType.BUKKIT, this);
@@ -113,7 +125,8 @@ public void onEnable() {
@Override
public void onDisable() {
- connector.shutdown();
+ if (connector != null)
+ connector.shutdown();
}
@Override
diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java
index 59dc077f0aa..839fc185de6 100644
--- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java
+++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java
@@ -25,221 +25,29 @@
package org.geysermc.platform.bungeecord;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Getter;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import org.geysermc.connector.FloodgateKeyLoader;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
-import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
-public class GeyserBungeeConfiguration implements GeyserConfiguration {
-
- private File dataFolder;
- private Configuration config;
-
- private BungeeBedrockConfiguration bedrockConfig;
- private BungeeRemoteConfiguration remoteConfig;
- private BungeeMetricsInfo metricsInfo;
-
- private Map userAuthInfo = new HashMap<>();
+@Getter
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
private Path floodgateKey;
- public GeyserBungeeConfiguration(File dataFolder, Configuration config) {
- this.dataFolder = dataFolder;
- this.config = config;
-
- bedrockConfig = new BungeeBedrockConfiguration();
- remoteConfig = new BungeeRemoteConfiguration();
- metricsInfo = new BungeeMetricsInfo();
-
- if (!config.contains("userAuths"))
- return;
-
- for (String key : config.getSection("userAuths").getKeys()) {
- userAuthInfo.put(key, new BungeeUserAuthenticationInfo(key));
- }
- }
-
- public void loadFloodgate(GeyserBungeePlugin plugin) {
+ public void loadFloodgate(GeyserBungeePlugin plugin, Configuration configuration) {
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee");
- floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
- }
-
- @Override
- public BungeeBedrockConfiguration getBedrock() {
- return bedrockConfig;
- }
-
- @Override
- public BungeeRemoteConfiguration getRemote() {
- return remoteConfig;
- }
-
- @Override
- public Map getUserAuths() {
- return userAuthInfo;
- }
-
- @Override
- public boolean isCommandSuggestions() {
- return config.getBoolean("command-suggestions", true);
- }
-
- @Override
- public boolean isPassthroughMotd() {
- return config.getBoolean("passthrough-motd", false);
- }
-
- @Override
- public boolean isPassthroughPlayerCounts() {
- return config.getBoolean("passthrough-player-counts", false);
- }
-
- @Override
- public boolean isLegacyPingPassthrough() {
- return config.getBoolean("legacy-ping-passthrough", false);
- }
-
- @Override
- public int getPingPassthroughInterval() {
- return config.getInt("ping-passthrough-interval", 3);
- }
-
- @Override
- public int getMaxPlayers() {
- return config.getInt("max-players", 10);
- }
-
- @Override
- public boolean isDebugMode() {
- return config.getBoolean("debug-mode", false);
- }
-
- @Override
- public int getGeneralThreadPool() {
- return config.getInt("general-thread-pool", 32);
- }
-
- @Override
- public boolean isAllowThirdPartyCapes() {
- return config.getBoolean("allow-third-party-capes", true);
- }
-
- @Override
- public boolean isAllowThirdPartyEars() {
- return config.getBoolean("allow-third-party-ears", false);
- }
-
- @Override
- public String getDefaultLocale() {
- return config.getString("default-locale", "en_us");
+ floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(plugin.getDataFolder().toString(), configuration.getString("floodgate-key-file"), "public-key.pem"), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
}
@Override
public Path getFloodgateKeyFile() {
return floodgateKey;
}
-
- @Override
- public boolean isCacheChunks() {
- return config.getBoolean("cache-chunks", false);
- }
-
- @Override
- public int getCacheSkins() {
- return config.getInt("cache-skins", 0);
- }
-
- @Override
- public boolean isAboveBedrockNetherBuilding() {
- return config.getBoolean("above-bedrock-nether-building", false);
- }
-
- @Override
- public BungeeMetricsInfo getMetrics() {
- return metricsInfo;
- }
-
- public class BungeeBedrockConfiguration implements IBedrockConfiguration {
-
- @Override
- public String getAddress() {
- return config.getString("bedrock.address", "0.0.0.0");
- }
-
- @Override
- public int getPort() {
- return config.getInt("bedrock.port", 25565);
- }
-
- @Override
- public String getMotd1() {
- return config.getString("bedrock.motd1", "GeyserMC");
- }
-
- @Override
- public String getMotd2() {
- return config.getString("bedrock.motd2", "GeyserMC");
- }
- }
-
- public class BungeeRemoteConfiguration implements IRemoteConfiguration {
-
- @Override
- public String getAddress() {
- return config.getString("remote.address", "127.0.0.1");
- }
-
- @Override
- public int getPort() {
- return config.getInt("remote.port", 25565);
- }
-
- @Override
- public String getAuthType() {
- return config.getString("remote.auth-type", "online");
- }
- }
-
- public class BungeeUserAuthenticationInfo implements IUserAuthenticationInfo {
-
- private String key;
-
- public BungeeUserAuthenticationInfo(String key) {
- this.key = key;
- }
-
- @Override
- public String getEmail() {
- return config.getString("userAuths." + key + ".email");
- }
-
- @Override
- public String getPassword() {
- return config.getString("userAuths." + key + ".password");
- }
- }
-
- public class BungeeMetricsInfo implements IMetricsInfo {
-
- @Override
- public boolean isEnabled() {
- return config.getBoolean("metrics.enabled", true);
- }
-
- @Override
- public String getUniqueId() {
- return config.getString("metrics.uuid", "generateduuid");
- }
- }
-
- @Override
- public int getConfigVersion() {
- return config.getInt("config-version", 0);
- }
}
diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java
index 525b9b6db42..24793839d3e 100644
--- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java
+++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java
@@ -31,20 +31,19 @@
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import org.geysermc.common.PlatformType;
-import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
+import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor;
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.net.InetSocketAddress;
-import java.nio.file.Files;
import java.util.UUID;
import java.util.logging.Level;
@@ -62,32 +61,18 @@ public void onEnable() {
if (!getDataFolder().exists())
getDataFolder().mkdir();
- File file = new File(getDataFolder(), "config.yml");
Configuration configuration = null;
-
- if (!file.exists()) {
- try (InputStream in = getResourceAsStream("config.yml")) {
- Files.copy(in, file.toPath());
- } catch (IOException ex) {
- getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
- return;
- }
- }
try {
+ if (!getDataFolder().exists())
+ getDataFolder().mkdir();
+ File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
+ this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml"));
- } catch(IOException e) {
- e.printStackTrace();
+ } catch (IOException ex) {
+ getLogger().log(Level.WARNING, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
+ ex.printStackTrace();
}
- if (configuration == null) {
- getLogger().severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!");
- return;
- }
-
- this.geyserConfig = new GeyserBungeeConfiguration(getDataFolder(), configuration);
-
- boolean configHasChanged = false;
-
if (getProxy().getConfig().getListeners().size() == 1) {
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
@@ -96,33 +81,21 @@ public void onEnable() {
// Don't change the ip if its listening on all interfaces
// By default this should be 127.0.0.1 but may need to be changed in some circumstances
if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) {
- configuration.set("remote.address", javaAddr.getHostString());
+ this.geyserConfig.getRemote().setAddress(javaAddr.getHostString());
}
- configuration.set("remote.port", javaAddr.getPort());
-
- configHasChanged = true;
- }
-
- if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
- configuration.set("metrics.uuid", UUID.randomUUID().toString());
-
- configHasChanged = true;
- }
-
- if (configHasChanged) {
- try {
- ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, new File(getDataFolder(), "config.yml"));
- } catch (IOException ex) {
- getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex);
- return;
- }
+ this.geyserConfig.getRemote().setPort(javaAddr.getPort());
}
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
- geyserConfig.loadFloodgate(this);
+ if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate-bungee") == null) {
+ geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
+ return;
+ }
+
+ geyserConfig.loadFloodgate(this, configuration);
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java
index 627b0ac48c3..68b43e315d8 100644
--- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java
+++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java
@@ -29,7 +29,7 @@
import ninja.leaping.configurate.ConfigurationNode;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import java.io.File;
import java.nio.file.Path;
diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
index d226add77cc..2288fc67474 100644
--- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
+++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java
@@ -30,7 +30,7 @@
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.geysermc.common.PlatformType;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
index aa0d2392e5a..a1c47238786 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java
@@ -26,12 +26,12 @@
package org.geysermc.platform.standalone;
import org.geysermc.common.PlatformType;
-import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
-import org.geysermc.connector.GeyserConfiguration;
-import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.GeyserConnector;
+import org.geysermc.connector.bootstrap.GeyserBootstrap;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
+import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.utils.FileUtils;
import org.geysermc.platform.standalone.command.GeyserCommandManager;
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java
index d9eb6c822dc..29e18d08f50 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java
@@ -27,113 +27,21 @@
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
-
import lombok.Getter;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Map;
-@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
-public class GeyserStandaloneConfiguration implements GeyserConfiguration {
-
- private BedrockConfiguration bedrock;
- private RemoteConfiguration remote;
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
@JsonProperty("floodgate-key-file")
private String floodgateKeyFile;
- private Map userAuths;
-
- @JsonProperty("command-suggestions")
- private boolean isCommandSuggestions;
-
- @JsonProperty("passthrough-motd")
- private boolean isPassthroughMotd;
-
- @JsonProperty("passthrough-player-counts")
- private boolean isPassthroughPlayerCounts;
-
- @JsonProperty("legacy-ping-passthrough")
- private boolean isLegacyPingPassthrough;
-
- @JsonProperty("ping-passthrough-interval")
- private int pingPassthroughInterval;
-
- @JsonProperty("max-players")
- private int maxPlayers;
-
- @JsonProperty("debug-mode")
- private boolean debugMode;
-
- @JsonProperty("general-thread-pool")
- private int generalThreadPool;
-
- @JsonProperty("allow-third-party-capes")
- private boolean allowThirdPartyCapes;
-
- @JsonProperty("allow-third-party-ears")
- private boolean allowThirdPartyEars;
-
- @JsonProperty("default-locale")
- private String defaultLocale;
-
- @JsonProperty("cache-chunks")
- private boolean cacheChunks;
-
- @JsonProperty(value = "cache-skins", defaultValue = "0")
- private int cacheSkins;
-
- @JsonProperty("above-bedrock-nether-building")
- private boolean isAboveBedrockNetherBuilding;
-
- private MetricsInfo metrics;
-
@Override
public Path getFloodgateKeyFile() {
return Paths.get(floodgateKeyFile);
}
-
- @Getter
- public static class BedrockConfiguration implements IBedrockConfiguration {
-
- private String address;
- private int port;
-
- private String motd1;
- private String motd2;
- }
-
- @Getter
- public static class RemoteConfiguration implements IRemoteConfiguration {
-
- private String address;
- private int port;
-
- private String motd1;
- private String motd2;
-
- @JsonProperty("auth-type")
- private String authType;
- }
-
- @Getter
- public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
- private String email;
- private String password;
- }
-
- @Getter
- public static class MetricsInfo implements IMetricsInfo {
-
- private boolean enabled;
-
- @JsonProperty("uuid")
- private String uniqueId;
- }
-
- @JsonProperty("config-version")
- private int configVersion;
}
diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java
index 5f5f9503bf6..574941c4805 100644
--- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java
+++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java
@@ -30,125 +30,30 @@
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
-import lombok.Setter;
import org.geysermc.connector.FloodgateKeyLoader;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Map;
import java.util.Optional;
-@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
-public class GeyserVelocityConfiguration implements GeyserConfiguration {
-
- private BedrockConfiguration bedrock;
- private RemoteConfiguration remote;
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
@JsonProperty("floodgate-key-file")
private String floodgateKeyFile;
- private Map userAuths;
-
- @JsonProperty("command-suggestions")
- private boolean commandSuggestions;
-
- @JsonProperty("passthrough-motd")
- private boolean isPassthroughMotd;
-
- @JsonProperty("passthrough-player-counts")
- private boolean isPassthroughPlayerCounts;
-
- @JsonProperty("legacy-ping-passthrough")
- private boolean isLegacyPingPassthrough;
-
- @JsonProperty("ping-passthrough-interval")
- private int pingPassthroughInterval;
-
- @JsonProperty("max-players")
- private int maxPlayers;
-
- @JsonProperty("debug-mode")
- private boolean debugMode;
-
- @JsonProperty("general-thread-pool")
- private int generalThreadPool;
-
- @JsonProperty("allow-third-party-capes")
- private boolean allowThirdPartyCapes;
-
- @JsonProperty("allow-third-party-ears")
- private boolean allowThirdPartyEars;
-
- @JsonProperty("default-locale")
- private String defaultLocale;
-
- @JsonProperty(value = "cache-chunks")
- private boolean cacheChunks;
-
- @JsonProperty(value = "cache-skins", defaultValue = "0")
- private int cacheSkins;
-
- @JsonProperty("above-bedrock-nether-building")
- private boolean aboveBedrockNetherBuilding;
-
- private MetricsInfo metrics;
-
private Path floodgateKey;
- public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
- Optional floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
- floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/")));
- }
-
@Override
public Path getFloodgateKeyFile() {
return floodgateKey;
}
- @Getter
- public static class BedrockConfiguration implements IBedrockConfiguration {
-
- private String address;
- private int port;
-
- private String motd1;
- private String motd2;
- }
-
- @Getter
- public static class RemoteConfiguration implements IRemoteConfiguration {
-
- @Setter
- private String address;
-
- @Setter
- private int port;
-
- private String motd1;
- private String motd2;
-
- @JsonProperty("auth-type")
- private String authType;
- }
-
- @Getter
- public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
- private String email;
- private String password;
- }
-
- @Getter
- public static class MetricsInfo implements IMetricsInfo {
-
- private boolean enabled;
-
- @JsonProperty("uuid")
- private String uniqueId;
+ public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
+ Optional floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
+ floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/")));
}
-
- @JsonProperty("config-version")
- private int configVersion;
}
diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java
index e7b44da53ab..e2a4787b4f0 100644
--- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java
+++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java
@@ -35,7 +35,7 @@
import com.velocitypowered.api.proxy.ProxyServer;
import org.geysermc.common.PlatformType;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
@@ -96,6 +96,11 @@ public void onEnable() {
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
+ if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) {
+ geyserLogger.severe("Auth type set to Floodgate but Floodgate not found! Disabling...");
+ return;
+ }
+
geyserConfig.loadFloodgate(this, proxyServer, configDir);
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
diff --git a/connector/pom.xml b/connector/pom.xml
index 229761adf29..91cf6f3db31 100644
--- a/connector/pom.xml
+++ b/connector/pom.xml
@@ -98,14 +98,8 @@
com.github.steveice10
- opennbt
- 1.4-SNAPSHOT
- compile
-
-
- com.github.steveice10
- packetlib
- 1.5-SNAPSHOT
+ mcprotocollib
+ 4c315aa206
compile
@@ -115,31 +109,11 @@
- com.github.steveice10
- mcauthlib
- 1.3-SNAPSHOT
+ io.netty
+ netty-resolver-dns
+ 4.1.43.Final
compile
-
- com.github.steveice10
- mcprotocollib
- 1.15.2-1-SNAPSHOT
- compile
-
-
- com.github.steveice10
- opennbt
-
-
- com.github.steveice10
- packetlib
-
-
- com.github.steveice10
- mcauthlib
-
-
-
org.reflections
reflections
diff --git a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java
index 0b631b2d2ad..617ac83eb3f 100644
--- a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java
+++ b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java
@@ -26,6 +26,8 @@
package org.geysermc.connector;
+import org.geysermc.connector.configuration.GeyserConfiguration;
+
import java.nio.file.Files;
import java.nio.file.Path;
diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
index 02e0c500360..abd48bc29e7 100644
--- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
+++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
@@ -35,6 +35,7 @@
import org.geysermc.common.PlatformType;
import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler;
import org.geysermc.connector.network.remote.RemoteServer;
diff --git a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java
index 24ce81cfd42..5cc6d06f3e2 100644
--- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java
+++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java
@@ -27,7 +27,7 @@
package org.geysermc.connector.bootstrap;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserLogger;
import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.network.translators.world.CachedChunkManager;
diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
similarity index 97%
rename from connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java
rename to connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
index e641dfbdb92..0d64afb37e7 100644
--- a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java
+++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java
@@ -24,7 +24,9 @@
*
*/
-package org.geysermc.connector;
+package org.geysermc.connector.configuration;
+
+import org.geysermc.connector.GeyserLogger;
import java.nio.file.Path;
import java.util.Map;
diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java
new file mode 100644
index 00000000000..a1d0db217d0
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ *
+ */
+
+package org.geysermc.connector.configuration;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+@Getter
+@JsonIgnoreProperties(ignoreUnknown = true)
+public abstract class GeyserJacksonConfiguration implements GeyserConfiguration {
+
+ private BedrockConfiguration bedrock;
+ private RemoteConfiguration remote;
+
+ @JsonProperty("floodgate-key-file")
+ private String floodgateKeyFile;
+
+ public abstract Path getFloodgateKeyFile();
+
+ private Map userAuths;
+
+ @JsonProperty("command-suggestions")
+ private boolean commandSuggestions;
+
+ @JsonProperty("passthrough-motd")
+ private boolean isPassthroughMotd;
+
+ @JsonProperty("passthrough-player-counts")
+ private boolean isPassthroughPlayerCounts;
+
+ @JsonProperty("legacy-ping-passthrough")
+ private boolean isLegacyPingPassthrough;
+
+ @JsonProperty("ping-passthrough-interval")
+ private int pingPassthroughInterval;
+
+ @JsonProperty("max-players")
+ private int maxPlayers;
+
+ @JsonProperty("debug-mode")
+ private boolean debugMode;
+
+ @JsonProperty("general-thread-pool")
+ private int generalThreadPool;
+
+ @JsonProperty("allow-third-party-capes")
+ private boolean allowThirdPartyCapes;
+
+ @JsonProperty("allow-third-party-ears")
+ private boolean allowThirdPartyEars;
+
+ @JsonProperty("default-locale")
+ private String defaultLocale;
+
+ @JsonProperty("cache-chunks")
+ private boolean cacheChunks;
+
+ @JsonProperty("above-bedrock-nether-building")
+ private boolean aboveBedrockNetherBuilding;
+
+ private MetricsInfo metrics;
+
+ @Getter
+ public static class BedrockConfiguration implements IBedrockConfiguration {
+
+ private String address;
+ private int port;
+
+ private String motd1;
+ private String motd2;
+ }
+
+ @Getter
+ public static class RemoteConfiguration implements IRemoteConfiguration {
+
+ @Setter
+ private String address;
+
+ @Setter
+ private int port;
+
+ private String motd1;
+ private String motd2;
+
+ @JsonProperty("auth-type")
+ private String authType;
+ }
+
+ @Getter
+ public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
+ private String email;
+ private String password;
+ }
+
+ @Getter
+ public static class MetricsInfo implements IMetricsInfo {
+
+ private boolean enabled;
+
+ @JsonProperty("uuid")
+ private String uniqueId;
+ }
+
+ @JsonProperty("config-version")
+ private int configVersion;
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java
new file mode 100644
index 00000000000..b774af9804c
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+
+/**
+ * This class is used as a base for minecarts with a default block to display like furnaces and spawners
+ */
+public class DefaultBlockMinecartEntity extends MinecartEntity {
+
+ public int customBlock = 0;
+ public int customBlockOffset = 0;
+ public boolean showCustomBlock = false;
+
+ public DefaultBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+ super(entityId, geyserId, entityType, position, motion, rotation);
+
+ updateDefaultBlockMetadata();
+ metadata.put(EntityData.HAS_DISPLAY, (byte) 1);
+ }
+
+ @Override
+ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
+
+ // Custom block
+ if (entityMetadata.getId() == 10) {
+ customBlock = (int) entityMetadata.getValue();
+
+ if (showCustomBlock) {
+ metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
+ }
+ }
+
+ // Custom block offset
+ if (entityMetadata.getId() == 11) {
+ customBlockOffset = (int) entityMetadata.getValue();
+
+ if (showCustomBlock) {
+ metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
+ }
+ }
+
+ // If the custom block should be enabled
+ if (entityMetadata.getId() == 12) {
+ if ((boolean) entityMetadata.getValue()) {
+ showCustomBlock = true;
+ metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(customBlock));
+ metadata.put(EntityData.DISPLAY_OFFSET, customBlockOffset);
+ } else {
+ showCustomBlock = false;
+ updateDefaultBlockMetadata();
+ }
+ }
+
+ super.updateBedrockMetadata(entityMetadata, session);
+ }
+
+ public void updateDefaultBlockMetadata() { }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
index 434c983bb3b..c5fcde9ef84 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java
@@ -34,6 +34,7 @@
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import com.github.steveice10.mc.protocol.data.message.TextMessage;
+import com.github.steveice10.mc.protocol.data.message.TranslationMessage;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
import com.nukkitx.math.vector.Vector3f;
@@ -209,13 +210,12 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, (xd & 0x01) == 0x01);
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
- metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10);
+ metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
if ((xd & 0x20) == 0x20) {
- if (this.is(ArmorStandEntity.class)) {
- metadata.put(EntityData.SCALE, 0.0f);
- } else {
+ // Armour stands are handled in their own class
+ if (!this.is(ArmorStandEntity.class)) {
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
}
} else {
@@ -253,9 +253,15 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
}
break;
case 2: // custom name
- TextMessage name = (TextMessage) entityMetadata.getValue();
- if (name != null)
- metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
+ if (entityMetadata.getValue() instanceof TextMessage) {
+ TextMessage name = (TextMessage) entityMetadata.getValue();
+ if (name != null)
+ metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
+ } else if (entityMetadata.getValue() instanceof TranslationMessage) {
+ TranslationMessage message = (TranslationMessage) entityMetadata.getValue();
+ if (message != null)
+ metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true));
+ }
break;
case 3: // is custom name visible
if (!this.is(PlayerEntity.class))
diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java
index cb050e86086..1db4f757a06 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java
@@ -37,6 +37,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 java.util.ArrayList;
import java.util.List;
@@ -63,7 +64,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
if (fireworks.get("Flight") != null) {
- fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue());
+ fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()));
}
List explosions = new ArrayList<>();
@@ -73,7 +74,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
if (effectData.get("Type") != null) {
- effectBuilder.byteTag("FireworkType", (Byte) effectData.get("Type").getValue());
+ effectBuilder.byteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue()));
}
if (effectData.get("Colors") != null) {
@@ -101,11 +102,11 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
}
if (effectData.get("Trail") != null) {
- effectBuilder.byteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue());
+ effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue()));
}
if (effectData.get("Flicker") != null) {
- effectBuilder.byteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue());
+ effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue()));
}
explosions.add(effectBuilder.buildRootTag());
diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java
new file mode 100644
index 00000000000..29ade193510
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.entity;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+
+public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
+
+ private boolean hasFuel = false;
+
+ public FurnaceMinecartEntity(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) {
+ if (entityMetadata.getId() == 13 && !showCustomBlock) {
+ hasFuel = (boolean) entityMetadata.getValue();
+ updateDefaultBlockMetadata();
+ }
+
+ super.updateBedrockMetadata(entityMetadata, session);
+ }
+
+ @Override
+ public void updateDefaultBlockMetadata() {
+ metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(hasFuel ? BlockTranslator.JAVA_RUNTIME_FURNACE_LIT_ID : BlockTranslator.JAVA_RUNTIME_FURNACE_ID));
+ metadata.put(EntityData.DISPLAY_OFFSET, 6);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
index bd18dc46e76..41308a0ded6 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java
@@ -49,7 +49,7 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
itemPacket.setUniqueEntityId(geyserId);
itemPacket.setFromFishing(false);
itemPacket.getMetadata().putAll(metadata);
- itemPacket.setItemInHand(ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue()));
+ itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
session.sendUpstreamPacket(itemPacket);
}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java
index a6d8af154c6..3680945cb99 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java
@@ -98,7 +98,7 @@ public void spawnEntity(GeyserSession session) {
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
- ItemData itemData = ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue());
+ ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue());
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
CompoundTagBuilder builder = CompoundTag.builder();
diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java
index ee004a2574b..a67c0be565f 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java
@@ -30,6 +30,7 @@
import com.nukkitx.protocol.bedrock.data.EntityData;
import org.geysermc.connector.entity.type.EntityType;
import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
public class MinecartEntity extends Entity {
@@ -54,6 +55,24 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
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) {
+ metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue()));
+ }
+
+ // Custom block offset
+ if (entityMetadata.getId() == 11) {
+ metadata.put(EntityData.DISPLAY_OFFSET, entityMetadata.getValue());
+ }
+
+ // If the custom block should be enabled
+ if (entityMetadata.getId() == 12) {
+ // Needs a byte based off of Java's boolean
+ metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0));
+ }
+ }
+
super.updateBedrockMetadata(entityMetadata, session);
}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java
new file mode 100644
index 00000000000..6be138c07bd
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java
@@ -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.connector.entity;
+
+import com.nukkitx.math.vector.Vector3f;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import org.geysermc.connector.entity.type.EntityType;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+
+public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
+
+ public SpawnerMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
+ super(entityId, geyserId, entityType, position, motion, rotation);
+ }
+
+ @Override
+ public void updateDefaultBlockMetadata() {
+ metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.getBedrockBlockId(BlockTranslator.JAVA_RUNTIME_SPAWNER_ID));
+ metadata.put(EntityData.DISPLAY_OFFSET, 6);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java
index 8d3c8f8fde4..47faad36720 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java
@@ -35,17 +35,42 @@
public class ArmorStandEntity extends LivingEntity {
+ // These are used to store the state of the armour stand for use when handling invisibility
+ private boolean isMarker = false;
+ private boolean isInvisible = false;
+ private boolean isSmall = false;
+
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
super(entityId, geyserId, entityType, position, motion, rotation);
}
+ @Override
+ public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) {
+ // Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands
+ if (!isMarker && isInvisible) {
+ position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d);
+ }
+
+ super.moveAbsolute(session, position, rotation, isOnGround, teleported);
+ }
+
@Override
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
- if (entityMetadata.getType() == MetadataType.BYTE) {
+ if (entityMetadata.getId() == 0 && entityMetadata.getType() == MetadataType.BYTE) {
+ byte xd = (byte) entityMetadata.getValue();
+
+ // Check if the armour stand is invisible and store accordingly
+ if ((xd & 0x20) == 0x20) {
+ metadata.put(EntityData.SCALE, 0.0f);
+ isInvisible = true;
+ }
+ } else if (entityMetadata.getId() == 14 && entityMetadata.getType() == MetadataType.BYTE) {
byte xd = (byte) entityMetadata.getValue();
// isSmall
if ((xd & 0x01) == 0x01) {
+ isSmall = true;
+
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
metadata.put(EntityData.SCALE, 0.55f);
}
@@ -60,9 +85,10 @@ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s
}
// setMarker
- if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) != null && !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
+ if ((xd & 0x10) == 0x10 && (metadata.get(EntityData.BOUNDING_BOX_WIDTH) == null || !metadata.get(EntityData.BOUNDING_BOX_WIDTH).equals(0.0f))) {
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f);
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
+ isMarker = true;
}
}
super.updateBedrockMetadata(entityMetadata, session);
diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
index 88934196521..3acc17c379d 100644
--- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
+++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java
@@ -105,7 +105,7 @@ public enum EntityType {
THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
EXPERIENCE_ORB(ExpOrbEntity.class, 69, 0f, 0f, 0f, 0f, "minecraft:xp_orb"),
EYE_OF_ENDER(Entity.class, 70, 0.25f, 0.25f, 0f, 0f, "minecraft:eye_of_ender_signal"),
- END_CRYSTAL(EnderCrystalEntity.class, 71, 0f, 0f, 0f, 0f, "minecraft:ender_crystal"),
+ END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"),
FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"),
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
@@ -133,12 +133,13 @@ public enum EntityType {
MINECART_HOPPER(MinecartEntity.class, 96, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:hopper_minecart"),
MINECART_TNT(MinecartEntity.class, 97, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:tnt_minecart"),
MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"),
-
+ MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
+ MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"),
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
LLAMA_SPIT(Entity.class, 102, 0.25f),
- EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f),
- EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.5f),
+ EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
+ EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
ICE_BOMB(Entity.class, 106, 0f),
BALLOON(Entity.class, 107, 0f), //TODO
diff --git a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
index 29ba1567852..49f81e3f8f1 100644
--- a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java
@@ -31,7 +31,7 @@
import io.netty.channel.socket.DatagramPacket;
import org.geysermc.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.MessageUtils;
diff --git a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java
index 061e0f86b44..6ad206b335f 100644
--- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java
@@ -60,6 +60,7 @@ public class QueryPacketHandler {
/**
* The Query packet handler instance
+ *
* @param connector Geyser Connector
* @param sender The Sender IP/Port for the Query
* @param buffer The Query data
@@ -79,11 +80,12 @@ public QueryPacketHandler(GeyserConnector connector, InetSocketAddress sender, B
/**
* Checks the packet is in fact a query packet
+ *
* @param buffer Query data
* @return if the packet is a query packet
*/
private boolean isQueryPacket(ByteBuf buffer) {
- return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false;
+ return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 0xFEFD : false;
}
/**
@@ -130,6 +132,7 @@ private void sendQueryData() {
/**
* Gets the game data for the query
+ *
* @return the game data for the query
*/
private byte[] getGameData() {
@@ -177,7 +180,7 @@ private byte[] getGameData() {
// Blank Buffer Bytes
query.write("GeyserMC".getBytes());
query.write((byte) 0x00);
- query.write((byte) 128);
+ query.write((byte) 0x80);
query.write((byte) 0x00);
// Fills the game data
@@ -189,7 +192,7 @@ private byte[] getGameData() {
}
// Final byte to show the end of the game data
- query.write(new byte[]{0x00, 0x01});
+ query.write(new byte[] { 0x00, 0x01 });
return query.toByteArray();
} catch (IOException e) {
e.printStackTrace();
@@ -197,6 +200,11 @@ private byte[] getGameData() {
}
}
+ /**
+ * Generate a byte[] storing the player names
+ *
+ * @return The byte[] representation of players
+ */
private byte[] getPlayers() {
ByteArrayOutputStream query = new ByteArrayOutputStream();
@@ -208,7 +216,7 @@ private byte[] getPlayers() {
try {
// Start the player section
query.write("player_".getBytes());
- query.write(new byte[]{0x00, 0x00});
+ query.write(new byte[] { 0x00, 0x00 });
// Fill player names
if(pingInfo != null) {
@@ -229,6 +237,7 @@ private byte[] getPlayers() {
/**
* Sends a packet to the sender
+ *
* @param data packet data
*/
private void sendPacket(ByteBuf data) {
@@ -251,18 +260,28 @@ public void regenerateToken() {
* Gets an MD5 token for the current IP/Port.
* This should reset every 30 seconds but a new one is generated per instance
* Seems wasteful to code something in to clear it when it has no use.
+ *
* @param token the token
* @param address the address
* @return an MD5 token for the current IP/Port
*/
public static byte[] getTokenString(byte[] token, InetAddress address) {
try {
+ // Generate an MD5 hash from the address
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
digest.update(token);
- return Arrays.copyOf(digest.digest(), 4);
+
+ // Get the first 4 bytes of the digest
+ byte[] digestBytes = Arrays.copyOf(digest.digest(), 4);
+
+ // Convert the bytes to a buffer
+ ByteBuffer byteBuffer = ByteBuffer.wrap(digestBytes);
+
+ // Turn the number into a null terminated string
+ return (byteBuffer.getInt() + "\0").getBytes();
} catch (NoSuchAlgorithmException e) {
- return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array();
+ return (ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).getInt() + "\0").getBytes();
}
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
index 67862d0e733..5a40b24670c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
+++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java
@@ -28,7 +28,7 @@
import com.nukkitx.protocol.bedrock.BedrockPacket;
import com.nukkitx.protocol.bedrock.packet.*;
import org.geysermc.common.AuthType;
-import org.geysermc.connector.GeyserConfiguration;
+import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
index 43fe9962160..4535f1330c4 100644
--- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
+++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java
@@ -31,6 +31,7 @@
import com.github.steveice10.mc.protocol.MinecraftProtocol;
import com.github.steveice10.mc.protocol.data.SubProtocol;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
+import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
@@ -41,14 +42,10 @@
import com.github.steveice10.packetlib.packet.Packet;
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
import com.nukkitx.math.GenericMath;
-import com.nukkitx.math.TrigMath;
import com.nukkitx.math.vector.*;
import com.nukkitx.protocol.bedrock.BedrockPacket;
import com.nukkitx.protocol.bedrock.BedrockServerSession;
-import com.nukkitx.protocol.bedrock.data.ContainerId;
-import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
-import com.nukkitx.protocol.bedrock.data.GameRuleData;
-import com.nukkitx.protocol.bedrock.data.PlayerPermission;
+import com.nukkitx.protocol.bedrock.data.*;
import com.nukkitx.protocol.bedrock.packet.*;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
@@ -60,6 +57,7 @@
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.PlayerEntity;
+import org.geysermc.connector.entity.attribute.AttributeType;
import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.remote.RemoteServer;
import org.geysermc.connector.network.session.auth.AuthData;
@@ -72,6 +70,7 @@
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.utils.ChunkUtils;
import org.geysermc.connector.utils.LocaleUtils;
+import org.geysermc.connector.utils.MathUtils;
import org.geysermc.connector.utils.SkinUtils;
import org.geysermc.floodgate.util.BedrockData;
import org.geysermc.floodgate.util.EncryptionUtil;
@@ -81,6 +80,8 @@
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
@@ -166,6 +167,14 @@ public class GeyserSession implements CommandSender {
@Setter
private int craftSlot = 0;
+ @Setter
+ private long lastWindowCloseTime = 0;
+
+ @Setter
+ private VillagerTrade[] villagerTrades;
+ @Setter
+ private long lastInteractedVillagerEid;
+
private MinecraftProtocol protocol;
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
@@ -211,6 +220,15 @@ public void connect(RemoteServer remoteServer) {
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
upstream.sendPacket(playStatusPacket);
+
+ UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
+ attributesPacket.setRuntimeEntityId(getPlayerEntity().getGeyserId());
+ List attributes = new ArrayList<>();
+ // Default move speed
+ // Bedrock clients move very fast by default until they get an attribute packet correcting the speed
+ attributes.add(new Attribute("minecraft:movement", 0.0f, 1024f, 0.1f, 0.1f));
+ attributesPacket.setAttributes(attributes);
+ upstream.sendPacket(attributesPacket);
}
public void login() {
@@ -355,6 +373,14 @@ public void packetReceived(PacketReceivedEvent event) {
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
}
}
+
+ @Override
+ public void packetError(PacketErrorEvent event) {
+ connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage());
+ if (connector.getConfig().isDebugMode())
+ event.getCause().printStackTrace();
+ event.setSuppress(true);
+ }
});
downstream.getSession().connect();
@@ -425,7 +451,7 @@ public void sendForm(FormWindow window, int id) {
}
public void setRenderDistance(int renderDistance) {
- renderDistance = GenericMath.ceil(++renderDistance * TrigMath.SQRT_OF_TWO); //square to circle
+ renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle
if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x)
this.renderDistance = renderDistance;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java
index 13136331717..a11dd40aff2 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java
@@ -25,18 +25,19 @@
package org.geysermc.connector.network.translators;
-import java.util.HashMap;
-import java.util.Map;
-
+import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket;
+import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListDataPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket;
+import com.github.steveice10.packetlib.packet.Packet;
+import com.nukkitx.protocol.bedrock.BedrockPacket;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession;
-
-import com.github.steveice10.packetlib.packet.Packet;
-import com.nukkitx.protocol.bedrock.BedrockPacket;
import org.reflections.Reflections;
+import java.util.HashMap;
+import java.util.Map;
+
public class PacketTranslatorRegistry {
private final Map, PacketTranslator extends T>> translators = new HashMap<>();
@@ -72,7 +73,9 @@ public class PacketTranslatorRegistry {
}
}
- IGNORED_PACKETS.add(ServerUpdateLightPacket.class);
+ IGNORED_PACKETS.add(ServerKeepAlivePacket.class); // Handled by MCProtocolLib
+ IGNORED_PACKETS.add(ServerUpdateLightPacket.class); // Light is handled on Bedrock for us
+ IGNORED_PACKETS.add(ServerPlayerListDataPacket.class); // Cant be implemented in bedrock
}
private PacketTranslatorRegistry() {
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java
new file mode 100644
index 00000000000..75a1547f508
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java
@@ -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.connector.network.translators.bedrock;
+
+import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
+import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
+import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.network.translators.Translator;
+
+@Translator(packet = AdventureSettingsPacket.class)
+public class BedrockAdventureSettingsTranslator extends PacketTranslator {
+
+ @Override
+ public void translate(AdventureSettingsPacket packet, GeyserSession session) {
+ // Only canFly and flying are used by the server
+ // https://wiki.vg/Protocol#Player_Abilities_.28serverbound.29
+ boolean canFly = packet.getFlags().contains(AdventureSettingsPacket.Flag.MAY_FLY);
+ boolean flying = packet.getFlags().contains(AdventureSettingsPacket.Flag.FLYING);
+ boolean creative = session.getGameMode() == GameMode.CREATIVE;
+ ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(
+ false, canFly, flying, creative, 0.05f, 0.1f
+ );
+ session.sendDownstreamPacket(abilitiesPacket);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
index 6f4a243f0fc..4c531c4858c 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockContainerCloseTranslator.java
@@ -38,17 +38,21 @@ public class BedrockContainerCloseTranslator extends PacketTranslator= 0 && packet.getData() < trades.length) {
+ VillagerTrade trade = session.getVillagerTrades()[packet.getData()];
+ openInventory.setItem(2, trade.getOutput());
+ villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP));
+ villager.updateBedrockMetadata(session);
+ }
+ }
+ return;
}
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
index 8f96b8004a0..777d4d9e3bd 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java
@@ -45,6 +45,7 @@
import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.ItemFrameEntity;
+import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
import org.geysermc.connector.inventory.Inventory;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
@@ -198,6 +199,10 @@ public void translate(InventoryTransactionPacket packet, GeyserSession session)
session.sendDownstreamPacket(interactAtPacket);
EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity);
+
+ if (entity instanceof AbstractMerchantEntity) {
+ session.setLastInteractedVillagerEid(packet.getRuntimeEntityId());
+ }
break;
case 1: //Attack
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java
new file mode 100644
index 00000000000..13684a609fb
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.connector.network.translators.inventory;
+
+import com.nukkitx.protocol.bedrock.data.InventoryActionData;
+import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
+import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
+import org.geysermc.connector.utils.InventoryUtils;
+
+import java.util.List;
+
+public abstract class ChestInventoryTranslator extends BaseInventoryTranslator {
+ private final InventoryUpdater updater;
+
+ public ChestInventoryTranslator(int size, int paddedSize) {
+ super(size);
+ this.updater = new ChestInventoryUpdater(paddedSize);
+ }
+
+ @Override
+ public void updateInventory(GeyserSession session, Inventory inventory) {
+ updater.updateInventory(this, session, inventory);
+ }
+
+ @Override
+ public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
+ updater.updateSlot(this, session, inventory, slot);
+ }
+
+ @Override
+ public void translateActions(GeyserSession session, Inventory inventory, List actions) {
+ for (InventoryActionData action : actions) {
+ if (action.getSource().getContainerId() == inventory.getId()) {
+ if (action.getSlot() >= size) {
+ updateInventory(session, inventory);
+ InventoryUtils.updateCursor(session);
+ return;
+ }
+ }
+ }
+
+ super.translateActions(session, inventory, actions);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java
index 3f887001f0e..e31eb1e3688 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java
@@ -92,7 +92,10 @@ public int bedrockSlotToJava(InventoryActionData action) {
@Override
public int javaSlotToBedrock(int slot) {
- return slot == 0 ? 50 : slot + 31;
+ if (slot < size) {
+ return slot == 0 ? 50 : slot + 31;
+ }
+ return super.javaSlotToBedrock(slot);
}
@Override
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java
index 8c5b2cf20e9..6d6cadd7d1a 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java
@@ -39,15 +39,13 @@
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
-public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
+public class DoubleChestInventoryTranslator extends ChestInventoryTranslator {
private final int blockId;
- private final InventoryUpdater updater;
public DoubleChestInventoryTranslator(int size) {
- super(size);
+ super(size, 54);
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
- this.updater = new ChestInventoryUpdater(54);
}
@Override
@@ -128,14 +126,4 @@ public void closeInventory(GeyserSession session, Inventory inventory) {
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
session.sendUpstreamPacket(blockPacket);
}
-
- @Override
- public void updateInventory(GeyserSession session, Inventory inventory) {
- updater.updateInventory(this, session, inventory);
- }
-
- @Override
- public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
- updater.updateSlot(this, session, inventory, slot);
- }
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
index 7b4b26e6258..975949070cb 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java
@@ -54,6 +54,7 @@ public abstract class InventoryTranslator {
put(WindowType.ANVIL, new AnvilInventoryTranslator());
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
+ put(WindowType.MERCHANT, new MerchantInventoryTranslator());
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
InventoryTranslator furnace = new FurnaceInventoryTranslator();
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java
new file mode 100644
index 00000000000..3f7636b9e5d
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ *
+ */
+
+package org.geysermc.connector.network.translators.inventory;
+
+import com.nukkitx.protocol.bedrock.data.ContainerId;
+import com.nukkitx.protocol.bedrock.data.InventoryActionData;
+import com.nukkitx.protocol.bedrock.data.InventorySource;
+import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater;
+import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
+
+import java.util.List;
+
+public class MerchantInventoryTranslator extends BaseInventoryTranslator {
+
+ private final InventoryUpdater updater;
+
+ public MerchantInventoryTranslator() {
+ super(3);
+ this.updater = new CursorInventoryUpdater();
+ }
+
+ @Override
+ public int javaSlotToBedrock(int slot) {
+ switch (slot) {
+ case 0:
+ return 4;
+ case 1:
+ return 5;
+ case 2:
+ return 50;
+ }
+ return super.javaSlotToBedrock(slot);
+ }
+
+ @Override
+ public int bedrockSlotToJava(InventoryActionData action) {
+ if (action.getSource().getContainerId() == ContainerId.CURSOR) {
+ switch (action.getSlot()) {
+ case 4:
+ return 0;
+ case 5:
+ return 1;
+ case 50:
+ return 2;
+ }
+ }
+ return super.bedrockSlotToJava(action);
+ }
+
+ @Override
+ public SlotType getSlotType(int javaSlot) {
+ if (javaSlot == 2) {
+ return SlotType.OUTPUT;
+ }
+ return SlotType.NORMAL;
+ }
+
+ @Override
+ public void prepareInventory(GeyserSession session, Inventory inventory) {
+
+ }
+
+ @Override
+ public void openInventory(GeyserSession session, Inventory inventory) {
+
+ }
+
+ @Override
+ public void closeInventory(GeyserSession session, Inventory inventory) {
+ session.setLastInteractedVillagerEid(-1);
+ session.setVillagerTrades(null);
+ }
+
+ @Override
+ public void updateInventory(GeyserSession session, Inventory inventory) {
+ updater.updateInventory(this, session, inventory);
+ }
+
+ @Override
+ public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
+ updater.updateSlot(this, session, inventory, slot);
+ }
+
+ @Override
+ public void translateActions(GeyserSession session, Inventory inventory, List actions) {
+ for (InventoryActionData action : actions) {
+ if (action.getSource().getType() == InventorySource.Type.NON_IMPLEMENTED_TODO) {
+ return;
+ }
+ }
+
+ super.translateActions(session, inventory, actions);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
index 055b69efd63..28986e58cef 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java
@@ -59,11 +59,11 @@ public void updateInventory(GeyserSession session, Inventory inventory) {
ItemData[] contents = new ItemData[36];
// Inventory
for (int i = 9; i < 36; i++) {
- contents[i] = ItemTranslator.translateToBedrock(inventory.getItem(i));
+ contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
}
// Hotbar
for (int i = 36; i < 45; i++) {
- contents[i - 36] = ItemTranslator.translateToBedrock(inventory.getItem(i));
+ contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
}
inventoryContentPacket.setContents(contents);
session.sendUpstreamPacket(inventoryContentPacket);
@@ -73,7 +73,7 @@ public void updateInventory(GeyserSession session, Inventory inventory) {
armorContentPacket.setContainerId(ContainerId.ARMOR);
contents = new ItemData[4];
for (int i = 5; i < 9; i++) {
- contents[i - 5] = ItemTranslator.translateToBedrock(inventory.getItem(i));
+ contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
}
armorContentPacket.setContents(contents);
session.sendUpstreamPacket(armorContentPacket);
@@ -81,7 +81,7 @@ public void updateInventory(GeyserSession session, Inventory inventory) {
// Offhand
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
- offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(45))});
+ offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))});
session.sendUpstreamPacket(offhandPacket);
}
@@ -100,7 +100,7 @@ public static void updateCraftingGrid(GeyserSession session, Inventory inventory
if (session.getGameMode() == GameMode.CREATIVE) {
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
}else{
- slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i)));
+ slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
}
session.sendUpstreamPacket(slotPacket);
@@ -125,12 +125,12 @@ public void updateSlot(GeyserSession session, Inventory inventory, int slot) {
slotPacket.setContainerId(ContainerId.CURSOR);
slotPacket.setSlot(slot + 27);
}
- slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(slot)));
+ slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
session.sendUpstreamPacket(slotPacket);
} else if (slot == 45) {
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
- offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(inventory.getItem(slot))});
+ offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))});
session.sendUpstreamPacket(offhandPacket);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java
index 5c99b0126e0..3f1a58f4d05 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java
@@ -25,11 +25,35 @@
package org.geysermc.connector.network.translators.inventory;
+import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import com.nukkitx.protocol.bedrock.data.ContainerType;
-import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
+import org.geysermc.connector.inventory.Inventory;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder;
+import org.geysermc.connector.network.translators.inventory.holder.InventoryHolder;
+import org.geysermc.connector.network.translators.world.block.BlockTranslator;
+
+public class SingleChestInventoryTranslator extends ChestInventoryTranslator {
+ private final InventoryHolder holder;
-public class SingleChestInventoryTranslator extends BlockInventoryTranslator {
public SingleChestInventoryTranslator(int size) {
- super(size, "minecraft:chest[facing=north,type=single,waterlogged=false]", ContainerType.CONTAINER, new ChestInventoryUpdater(27));
+ super(size, 27);
+ BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
+ this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER);
+ }
+
+ @Override
+ public void prepareInventory(GeyserSession session, Inventory inventory) {
+ holder.prepareInventory(this, session, inventory);
+ }
+
+ @Override
+ public void openInventory(GeyserSession session, Inventory inventory) {
+ holder.openInventory(this, session, inventory);
+ }
+
+ @Override
+ public void closeInventory(GeyserSession session, Inventory inventory) {
+ holder.closeInventory(this, session, inventory);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java
index 9139da1fd43..209df07481d 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java
@@ -61,13 +61,13 @@ public static void translate(InventoryTranslator translator, GeyserSession sessi
worldAction = action;
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
cursorAction = action;
- ItemData translatedCursor = ItemTranslator.translateToBedrock(session.getInventory().getCursor());
+ ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor());
if (!translatedCursor.equals(action.getFromItem())) {
refresh = true;
}
} else {
containerAction = action;
- ItemData translatedItem = ItemTranslator.translateToBedrock(inventory.getItem(translator.bedrockSlotToJava(action)));
+ ItemData translatedItem = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.bedrockSlotToJava(action)));
if (!translatedItem.equals(action.getFromItem())) {
refresh = true;
}
@@ -187,11 +187,12 @@ public static void translate(InventoryTranslator translator, GeyserSession sessi
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
plan.add(Click.LEFT, javaSlot);
} else {
- int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot));
+ int cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Collections.singletonList(javaSlot), false);
if (cursorSlot != -1) {
plan.add(Click.LEFT, cursorSlot);
} else {
translator.updateInventory(session, inventory);
+ InventoryUtils.updateCursor(session);
return;
}
plan.add(Click.LEFT, javaSlot);
@@ -245,11 +246,15 @@ public static void translate(InventoryTranslator translator, GeyserSession sessi
int cursorSlot = -1;
if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
- cursorSlot = findTempSlot(inventory, session.getInventory().getCursor(), Arrays.asList(fromSlot, toSlot));
+ cursorSlot = findTempSlot(inventory,
+ session.getInventory().getCursor(),
+ Arrays.asList(fromSlot, toSlot),
+ translator.getSlotType(fromSlot) == SlotType.OUTPUT);
if (cursorSlot != -1) {
plan.add(Click.LEFT, cursorSlot);
} else {
translator.updateInventory(session, inventory);
+ InventoryUtils.updateCursor(session);
return;
}
}
@@ -298,7 +303,7 @@ public static void translate(InventoryTranslator translator, GeyserSession sessi
InventoryUtils.updateCursor(session);
}
- private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist) {
+ private static int findTempSlot(Inventory inventory, ItemStack item, List slotBlacklist, boolean emptyOnly) {
/*try and find a slot that can temporarily store the given item
only look in the main inventory and hotbar
only slots that are empty or contain a different type of item are valid*/
@@ -314,6 +319,9 @@ private static int findTempSlot(Inventory inventory, ItemStack item, List> groupedByIds = Arrays.stream(ingredient.getOptions())
- .map(ItemTranslator::translateToBedrock)
+ .map(item -> ItemTranslator.translateToBedrock(session, item))
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
Set optionSet = new HashSet<>(groupedByIds.size());
for (Map.Entry> entry : groupedByIds.entrySet()) {
@@ -136,7 +136,7 @@ private ItemData[][] combinations(GeyserSession session, Ingredient[] ingredient
ItemData[] translatedItems = new ItemData[ingredients.length];
for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i].getOptions().length > 0) {
- translatedItems[i] = ItemTranslator.translateToBedrock(ingredients[i].getOptions()[0]);
+ translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]);
} else {
translatedItems[i] = ItemData.AIR;
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java
index e977e9b0c7f..8918217a10b 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java
@@ -55,7 +55,7 @@ public void translate(ServerEntityEquipmentPacket packet, GeyserSession session)
}
LivingEntity livingEntity = (LivingEntity) entity;
- ItemData item = ItemTranslator.translateToBedrock(packet.getItem());
+ ItemData item = ItemTranslator.translateToBedrock(session, packet.getItem());
switch (packet.getSlot()) {
case HELMET:
livingEntity.setHelmet(item);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
index 37fb96fb84f..a44b200e3d9 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerPositionRotationTranslator.java
@@ -25,6 +25,7 @@
package org.geysermc.connector.network.translators.java.entity.player;
+import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement;
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
import com.nukkitx.math.vector.Vector3f;
@@ -95,20 +96,35 @@ public void translate(ServerPlayerPositionRotationPacket packet, GeyserSession s
session.setSpawned(true);
- if (!packet.getRelative().isEmpty()) {
- session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId()));
- entity.moveRelative(session, packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ(), packet.getYaw(), packet.getPitch(), true);
- } else {
+ // Ignore certain move correction packets for smoother movement
+ // These are never relative
+ if (packet.getRelative().isEmpty()) {
double xDis = Math.abs(entity.getPosition().getX() - packet.getX());
double yDis = entity.getPosition().getY() - packet.getY();
double zDis = Math.abs(entity.getPosition().getZ() - packet.getZ());
- if (xDis > 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5) {
- session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId()));
- entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), true, true);
- } else {
+ if (!(xDis > 1.5 || (yDis < 1.45 || yDis > (session.isJumping() ? 4.3 : (session.isSprinting() ? 2.5 : 1.9))) || zDis > 1.5)) {
+ // Fake confirm the teleport but don't send it to the client
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
session.sendDownstreamPacket(teleportConfirmPacket);
+ return;
}
}
+
+ // If coordinates are relative, then add to the existing coordinate
+ double newX = packet.getX() +
+ (packet.getRelative().contains(PositionElement.X) ? entity.getPosition().getX() : 0);
+ double newY = packet.getY() +
+ (packet.getRelative().contains(PositionElement.Y) ? entity.getPosition().getY() - EntityType.PLAYER.getOffset() : 0);
+ double newZ = packet.getZ() +
+ (packet.getRelative().contains(PositionElement.Z) ? entity.getPosition().getZ() : 0);
+
+ double newPitch = packet.getPitch() +
+ (packet.getRelative().contains(PositionElement.PITCH) ? entity.getBedrockRotation().getX() : 0);
+ double newYaw = packet.getYaw() +
+ (packet.getRelative().contains(PositionElement.YAW) ? entity.getBedrockRotation().getY() : 0);
+
+
+ session.setTeleportCache(new TeleportCache(newX, newY, newZ, packet.getTeleportId()));
+ entity.moveAbsolute(session, Vector3f.from(newX, newY, newZ), (float) newYaw, (float) newPitch, true, true);
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
index 7360cbb2ea5..93cfa08e46b 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java
@@ -26,7 +26,6 @@
package org.geysermc.connector.network.translators.java.window;
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
-import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator;
@@ -37,9 +36,7 @@ public class JavaCloseWindowTranslator extends PacketTranslator {
@@ -52,10 +50,8 @@ public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
Inventory openInventory = session.getInventoryCache().getOpenInventory();
if (newTranslator == null) {
if (openInventory != null) {
- ContainerClosePacket closePacket = new ContainerClosePacket();
- closePacket.setWindowId((byte)openInventory.getId());
- session.sendUpstreamPacket(closePacket);
- InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType()).closeInventory(session, openInventory);
+ InventoryUtils.closeWindow(session, openInventory.getId());
+ InventoryUtils.closeInventory(session, openInventory.getId());
}
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
session.sendDownstreamPacket(closeWindowPacket);
@@ -80,9 +76,8 @@ public void translate(ServerOpenWindowPacket packet, GeyserSession session) {
if (openInventory != null) {
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
+ InventoryUtils.closeWindow(session, openInventory.getId());
InventoryUtils.closeInventory(session, openInventory.getId());
- GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS);
- return;
}
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
index 5d44069fe3f..19d7db217e0 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaSetSlotTranslator.java
@@ -41,8 +41,6 @@ public class JavaSetSlotTranslator extends PacketTranslator
@Override
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
- if (Objects.equals(session.getInventory().getCursor(), packet.getItem()))
- return;
if (session.getCraftSlot() != 0)
return;
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java
index 49a17f987ff..79b27f6a5f2 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java
@@ -46,14 +46,17 @@ public class JavaExplosionTranslator extends PacketTranslator= 2.0f ? LevelEventType.PARTICLE_HUGE_EXPLODE : LevelEventType.PARTICLE_LARGE_EXPLOSION);
+ levelEventPacket.setData(0);
+ levelEventPacket.setPosition(pos.toFloat());
+ session.sendUpstreamPacket(levelEventPacket);
+
LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket();
levelSoundEventPacket.setRelativeVolumeDisabled(false);
levelSoundEventPacket.setBabySound(false);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java
index cc45e345696..63512047f8e 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java
@@ -64,7 +64,7 @@ public void translate(ServerSpawnParticlePacket packet, GeyserSession session) {
break;
case ITEM:
ItemStack javaItem = ((ItemParticleData)packet.getParticle().getData()).getItemStack();
- ItemData bedrockItem = ItemTranslator.translateToBedrock(javaItem);
+ ItemData bedrockItem = ItemTranslator.translateToBedrock(session, javaItem);
int id = bedrockItem.getId();
short damage = bedrockItem.getDamage();
particle.setType(LevelEventType.PARTICLE_ITEM_BREAK);
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java
new file mode 100644
index 00000000000..97f04ee580d
--- /dev/null
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaTradeListTranslator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ *
+ */
+
+package org.geysermc.connector.network.translators.java.world;
+
+import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
+import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerTradeListPacket;
+import com.nukkitx.nbt.CompoundTagBuilder;
+import com.nukkitx.nbt.tag.CompoundTag;
+import com.nukkitx.protocol.bedrock.data.ContainerType;
+import com.nukkitx.protocol.bedrock.data.EntityData;
+import com.nukkitx.protocol.bedrock.data.ItemData;
+import com.nukkitx.protocol.bedrock.packet.UpdateTradePacket;
+import org.geysermc.connector.entity.Entity;
+import org.geysermc.connector.network.session.GeyserSession;
+import org.geysermc.connector.network.translators.PacketTranslator;
+import org.geysermc.connector.network.translators.Translator;
+import org.geysermc.connector.network.translators.item.ItemEntry;
+import org.geysermc.connector.network.translators.item.ItemRegistry;
+import org.geysermc.connector.network.translators.item.ItemTranslator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Translator(packet = ServerTradeListPacket.class)
+public class JavaTradeListTranslator extends PacketTranslator {
+
+ @Override
+ public void translate(ServerTradeListPacket packet, GeyserSession session) {
+ Entity villager = session.getPlayerEntity();
+ session.setVillagerTrades(packet.getTrades());
+ villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1);
+ villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4);
+ villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience());
+ villager.updateBedrockMetadata(session);
+
+ UpdateTradePacket updateTradePacket = new UpdateTradePacket();
+ updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1);
+ updateTradePacket.setWindowId((short) packet.getWindowId());
+ updateTradePacket.setWindowType((short) ContainerType.TRADING.id());
+ String displayName;
+ Entity realVillager = session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid());
+ if (realVillager != null && realVillager.getMetadata().containsKey(EntityData.NAMETAG) && realVillager.getMetadata().getString(EntityData.NAMETAG) != null) {
+ displayName = realVillager.getMetadata().getString(EntityData.NAMETAG);
+ } else {
+ displayName = packet.isRegularVillager() ? "Villager" : "Wandering Trader";
+ }
+ updateTradePacket.setDisplayName(displayName);
+ updateTradePacket.setUnknownInt(0);
+ updateTradePacket.setScreen2(true);
+ updateTradePacket.setWilling(true);
+ updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId());
+ updateTradePacket.setTraderUniqueEntityId(session.getPlayerEntity().getGeyserId());
+ CompoundTagBuilder builder = CompoundTagBuilder.builder();
+ List tags = new ArrayList<>();
+ for (VillagerTrade trade : packet.getTrades()) {
+ CompoundTagBuilder recipe = CompoundTagBuilder.builder();
+ recipe.intTag("maxUses", trade.getMaxUses());
+ recipe.intTag("traderExp", trade.getXp());
+ recipe.floatTag("priceMultiplierA", trade.getPriceMultiplier());
+ recipe.tag(getItemTag(session, trade.getOutput(), "sell", 0));
+ recipe.floatTag("priceMultiplierB", 0.0f);
+ recipe.intTag("buyCountB", trade.getSecondInput() != null ? trade.getSecondInput().getAmount() : 0);
+ recipe.intTag("buyCountA", trade.getFirstInput().getAmount());
+ recipe.intTag("demand", trade.getDemand());
+ recipe.intTag("tier", packet.getVillagerLevel() - 1);
+ recipe.tag(getItemTag(session, trade.getFirstInput(), "buyA", trade.getSpecialPrice()));
+ if (trade.getSecondInput() != null) {
+ recipe.tag(getItemTag(session, trade.getSecondInput(), "buyB", 0));
+ }
+ recipe.intTag("uses", trade.getNumUses());
+ recipe.byteTag("rewardExp", (byte) 1);
+ tags.add(recipe.buildRootTag());
+ }
+
+ //Hidden trade to fix visual experience bug
+ if (packet.isRegularVillager() && packet.getVillagerLevel() < 5) {
+ tags.add(CompoundTagBuilder.builder()
+ .intTag("maxUses", 0)
+ .intTag("traderExp", 0)
+ .floatTag("priceMultiplierA", 0.0f)
+ .floatTag("priceMultiplierB", 0.0f)
+ .intTag("buyCountB", 0)
+ .intTag("buyCountA", 0)
+ .intTag("demand", 0)
+ .intTag("tier", 5)
+ .intTag("uses", 0)
+ .byteTag("rewardExp", (byte) 0)
+ .buildRootTag());
+ }
+
+ builder.listTag("Recipes", CompoundTag.class, tags);
+ List expTags = new ArrayList<>();
+ expTags.add(CompoundTagBuilder.builder().intTag("0", 0).buildRootTag());
+ expTags.add(CompoundTagBuilder.builder().intTag("1", 10).buildRootTag());
+ expTags.add(CompoundTagBuilder.builder().intTag("2", 70).buildRootTag());
+ expTags.add(CompoundTagBuilder.builder().intTag("3", 150).buildRootTag());
+ expTags.add(CompoundTagBuilder.builder().intTag("4", 250).buildRootTag());
+ builder.listTag("TierExpRequirements", CompoundTag.class, expTags);
+ updateTradePacket.setOffers(builder.buildRootTag());
+ session.sendUpstreamPacket(updateTradePacket);
+ }
+
+ private CompoundTag getItemTag(GeyserSession session, ItemStack stack, String name, int specialPrice) {
+ ItemData itemData = ItemTranslator.translateToBedrock(session, stack);
+ ItemEntry itemEntry = ItemRegistry.getItem(stack);
+ CompoundTagBuilder builder = CompoundTagBuilder.builder();
+ builder.byteTag("Count", (byte) (Math.max(itemData.getCount() + specialPrice, 1)));
+ builder.shortTag("Damage", itemData.getDamage());
+ builder.shortTag("id", (short) itemEntry.getBedrockId());
+ if (itemData.getTag() != null) {
+ CompoundTag tag = itemData.getTag().toBuilder().build("tag");
+ builder.tag(tag);
+ }
+ return builder.build(name);
+ }
+}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
index a40dd15f3d1..d6f446f0887 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java
@@ -69,6 +69,11 @@ public class BlockTranslator {
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
public static final int JAVA_RUNTIME_COBWEB_ID;
+ public static final int JAVA_RUNTIME_FURNACE_ID;
+ public static final int JAVA_RUNTIME_FURNACE_LIT_ID;
+
+ public static final int JAVA_RUNTIME_SPAWNER_ID;
+
private static final int BLOCK_STATE_VERSION = 17760256;
static {
@@ -108,6 +113,9 @@ public class BlockTranslator {
int javaRuntimeId = -1;
int bedrockRuntimeId = 0;
int cobwebRuntimeId = -1;
+ int furnaceRuntimeId = -1;
+ int furnaceLitRuntimeId = -1;
+ int spawnerRuntimeId = -1;
Iterator> blocksIterator = blocks.fields();
while (blocksIterator.hasNext()) {
javaRuntimeId++;
@@ -186,6 +194,18 @@ public class BlockTranslator {
}
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId);
+ if (javaId.startsWith("minecraft:furnace[facing=north")) {
+ if (javaId.contains("lit=true")) {
+ furnaceLitRuntimeId = javaRuntimeId;
+ } else {
+ furnaceRuntimeId = javaRuntimeId;
+ }
+ }
+
+ if (javaId.startsWith("minecraft:spawner")) {
+ spawnerRuntimeId = javaRuntimeId;
+ }
+
bedrockRuntimeId++;
}
@@ -194,6 +214,21 @@ public class BlockTranslator {
}
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
+ if (furnaceRuntimeId == -1) {
+ throw new AssertionError("Unable to find furnace in palette");
+ }
+ JAVA_RUNTIME_FURNACE_ID = furnaceRuntimeId;
+
+ if (furnaceLitRuntimeId == -1) {
+ throw new AssertionError("Unable to find lit furnace in palette");
+ }
+ JAVA_RUNTIME_FURNACE_LIT_ID = furnaceLitRuntimeId;
+
+ if (spawnerRuntimeId == -1) {
+ throw new AssertionError("Unable to find spawner in palette");
+ }
+ JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
+
if (waterRuntimeId == -1) {
throw new AssertionError("Unable to find water in palette");
}
diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java
index 3d663926d7b..c87938dd953 100644
--- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java
+++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java
@@ -46,6 +46,19 @@ public abstract class BlockEntityTranslator {
public static final Map BLOCK_ENTITY_TRANSLATORS = new HashMap<>();
public static ObjectArrayList REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>();
+ /**
+ * Contains a list of irregular block entity name translations that can't be fit into the regex
+ */
+ public static final Map BLOCK_ENTITY_TRANSLATIONS = new HashMap() {
+ {
+ // Bedrock/Java differences
+ put("minecraft:enchanting_table", "EnchantTable");
+ put("minecraft:piston_head", "PistonArm");
+ put("minecraft:trapped_chest", "Chest");
+ // There are some legacy IDs sent but as far as I can tell they are not needed for things to work properly
+ }
+ };
+
protected BlockEntityTranslator() {
}
diff --git a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java
index ea0d67c2116..6a323d549e6 100644
--- a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java
+++ b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java
@@ -33,9 +33,7 @@
import com.github.steveice10.packetlib.Client;
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
import org.geysermc.common.ping.GeyserPingInfo;
-import org.geysermc.connector.GeyserConfiguration;
import org.geysermc.connector.GeyserConnector;
-import org.geysermc.connector.GeyserLogger;
import java.util.concurrent.TimeUnit;
diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java
index 038084c3acf..3a356e03131 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java
@@ -12,29 +12,24 @@ public class BlockEntityUtils {
public static String getBedrockBlockEntityId(String id) {
// These are the only exceptions when it comes to block entity ids
- if (id.contains("piston_head"))
- return "PistonArm";
-
- if (id.contains("trapped_chest"))
- return "Chest";
-
- if (id.contains("EnderChest"))
- return "EnderChest";
-
- if (id.contains("enchanting_table")) {
- return "EnchantTable";
+ if (BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.containsKey(id)) {
+ return BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id);
}
- id = id.toLowerCase()
- .replace("minecraft:", "")
+ id = id.replace("minecraft:", "")
.replace("_", " ");
- String[] words = id.split(" ");
+ // Split at every space or capital letter - for the latter, some legacy Java block entity tags are the correct format already
+ String[] words;
+ if (!id.toUpperCase().equals(id)) { // Otherwise we get [S, K, U, L, L]
+ words = id.split("(?=[A-Z])| "); // Split at every space or note or before every capital letter
+ } else {
+ words = id.split(" ");
+ }
for (int i = 0; i < words.length; i++) {
words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase();
}
- id = String.join(" ", words);
- return id.replace(" ", "");
+ return String.join("", words);
}
public static BlockEntityTranslator getBlockEntityTranslator(String name) {
diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java
index 010a87afa92..f86173e24b6 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java
@@ -30,6 +30,8 @@
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
import com.github.steveice10.mc.protocol.data.game.world.block.BlockState;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import com.github.steveice10.opennbt.tag.builtin.StringTag;
+import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.nukkitx.math.vector.Vector2i;
import com.nukkitx.math.vector.Vector3i;
import com.nukkitx.nbt.CompoundTagBuilder;
@@ -137,11 +139,23 @@ public static ChunkData translateToBedrock(Column column) {
while (i < blockEntities.length) {
CompoundTag tag = blockEntities[i];
String tagName;
- if (!tag.contains("id")) {
- GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue());
- tagName = "Empty";
- } else {
+ if (tag.contains("id")) {
tagName = (String) tag.get("id").getValue();
+ } else {
+ tagName = "Empty";
+ // Sometimes legacy tags have their ID be a StringTag with empty value
+ for (Tag subTag : tag) {
+ if (subTag instanceof StringTag) {
+ StringTag stringTag = (StringTag) subTag;
+ if (stringTag.getValue().equals("")) {
+ tagName = stringTag.getName();
+ break;
+ }
+ }
+ }
+ if (tagName.equals("Empty")) {
+ GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue());
+ }
}
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
index fd4c5e4e535..ded47723a85 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java
@@ -31,6 +31,7 @@
import com.nukkitx.nbt.tag.StringTag;
import com.nukkitx.protocol.bedrock.data.ContainerId;
import com.nukkitx.protocol.bedrock.data.ItemData;
+import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
import org.geysermc.common.ChatColor;
import org.geysermc.connector.GeyserConnector;
@@ -53,12 +54,18 @@ public static void openInventory(GeyserSession session, Inventory inventory) {
if (translator != null) {
session.getInventoryCache().setOpenInventory(inventory);
translator.prepareInventory(session, inventory);
+ //Ensure at least half a second passes between closing and opening a new window
+ //The client will not open the new window if it is still closing the old one
+ long delay = 500 - (System.currentTimeMillis() - session.getLastWindowCloseTime());
//TODO: find better way to handle double chest delay
if (translator instanceof DoubleChestInventoryTranslator) {
+ delay = Math.max(delay, 200);
+ }
+ if (delay > 0) {
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> {
translator.openInventory(session, inventory);
translator.updateInventory(session, inventory);
- }, 200, TimeUnit.MILLISECONDS);
+ }, delay, TimeUnit.MILLISECONDS);
} else {
translator.openInventory(session, inventory);
translator.updateInventory(session, inventory);
@@ -69,26 +76,41 @@ public static void openInventory(GeyserSession session, Inventory inventory) {
public static void closeInventory(GeyserSession session, int windowId) {
if (windowId != 0) {
Inventory inventory = session.getInventoryCache().getInventories().get(windowId);
- if (inventory != null) {
+ Inventory openInventory = session.getInventoryCache().getOpenInventory();
+ session.getInventoryCache().uncacheInventory(windowId);
+ if (inventory != null && openInventory != null && inventory.getId() == openInventory.getId()) {
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
translator.closeInventory(session, inventory);
- session.getInventoryCache().uncacheInventory(windowId);
session.getInventoryCache().setOpenInventory(null);
+ } else {
+ return;
}
} else {
Inventory inventory = session.getInventory();
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
translator.updateInventory(session, inventory);
}
+
session.setCraftSlot(0);
session.getInventory().setCursor(null);
+ updateCursor(session);
+ }
+
+ public static void closeWindow(GeyserSession session, int windowId) {
+ //Spamming close window packets can bug the client
+ if (System.currentTimeMillis() - session.getLastWindowCloseTime() > 500) {
+ ContainerClosePacket closePacket = new ContainerClosePacket();
+ closePacket.setWindowId((byte) windowId);
+ session.sendUpstreamPacket(closePacket);
+ session.setLastWindowCloseTime(System.currentTimeMillis());
+ }
}
public static void updateCursor(GeyserSession session) {
InventorySlotPacket cursorPacket = new InventorySlotPacket();
cursorPacket.setContainerId(ContainerId.CURSOR);
cursorPacket.setSlot(0);
- cursorPacket.setItem(ItemTranslator.translateToBedrock(session.getInventory().getCursor()));
+ cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()));
session.sendUpstreamPacket(cursorPacket);
}
diff --git a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java
index 4e8497c6d13..48702492252 100644
--- a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java
+++ b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java
@@ -27,6 +27,8 @@
public class MathUtils {
+ public static final double SQRT_OF_TWO = Math.sqrt(2);
+
/**
* Round the given float to the next whole number
*
@@ -37,4 +39,19 @@ public static int ceil(float floatNumber) {
int truncated = (int) floatNumber;
return floatNumber > truncated ? truncated + 1 : truncated;
}
+
+ /**
+ * Converts the given object from an int or byte to byte.
+ * This is used for NBT data that might be either an int
+ * or byte and bedrock only takes it as an byte
+ *
+ * @param value The value to convert
+ * @return The converted byte
+ */
+ public static Byte convertByte(Object value) {
+ if (value instanceof Integer) {
+ return ((Integer) value).byteValue();
+ }
+ return (Byte) value;
+ }
}
diff --git a/pom.xml b/pom.xml
index a82d6217e70..3e119eb1197 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,14 +38,8 @@
- CodeMC-repo
- https://repo.codemc.org/repository/maven-public
-
- true
-
-
- true
-
+ jitpack.io
+ https://jitpack.io
nukkitx-release-repo