forked from GeyserMC/Geyser
Merge latest master; copy over old Geyser-Bukkit configs
This commit is contained in:
commit
cc3b4c3eda
68 changed files with 1308 additions and 829 deletions
|
@ -37,7 +37,6 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
||||||
- [ ] Beacon
|
- [ ] Beacon
|
||||||
- [ ] Cartography Table
|
- [ ] Cartography Table
|
||||||
- [ ] Stonecutter
|
- [ ] Stonecutter
|
||||||
- [ ] Villager Trading
|
|
||||||
- Some Entity Flags
|
- Some Entity Flags
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
|
@ -25,216 +25,29 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bungeecord;
|
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.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
import org.geysermc.connector.FloodgateKeyLoader;
|
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.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class GeyserBungeeConfiguration implements GeyserConfiguration {
|
@Getter
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
private File dataFolder;
|
public class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
|
||||||
private Configuration config;
|
|
||||||
|
|
||||||
private BungeeBedrockConfiguration bedrockConfig;
|
|
||||||
private BungeeRemoteConfiguration remoteConfig;
|
|
||||||
private BungeeMetricsInfo metricsInfo;
|
|
||||||
|
|
||||||
private Map<String, BungeeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
|
||||||
|
|
||||||
private Path floodgateKey;
|
private Path floodgateKey;
|
||||||
|
|
||||||
public GeyserBungeeConfiguration(File dataFolder, Configuration config) {
|
public void loadFloodgate(GeyserBungeePlugin plugin, Configuration configuration) {
|
||||||
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) {
|
|
||||||
Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee");
|
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);
|
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 BungeeBedrockConfiguration getBedrock() {
|
|
||||||
return bedrockConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BungeeRemoteConfiguration getRemote() {
|
|
||||||
return remoteConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, BungeeUserAuthenticationInfo> 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return floodgateKey;
|
return floodgateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCacheChunks() {
|
|
||||||
return config.getBoolean("cache-chunks", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,20 +31,19 @@ import net.md_5.bungee.config.Configuration;
|
||||||
import net.md_5.bungee.config.ConfigurationProvider;
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
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.GeyserBungeeCommandExecutor;
|
||||||
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
|
import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@ -62,32 +61,18 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
|
|
||||||
File file = new File(getDataFolder(), "config.yml");
|
|
||||||
Configuration configuration = null;
|
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 {
|
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"));
|
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml"));
|
||||||
} catch(IOException e) {
|
} catch (IOException ex) {
|
||||||
e.printStackTrace();
|
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) {
|
if (getProxy().getConfig().getListeners().size() == 1) {
|
||||||
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
|
ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0];
|
||||||
|
|
||||||
|
@ -96,33 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
// Don't change the ip if its listening on all interfaces
|
// 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
|
// 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("")) {
|
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());
|
this.geyserConfig.getRemote().setPort(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.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
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);
|
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,10 @@
|
||||||
<pattern>it.unimi.dsi.fastutil</pattern>
|
<pattern>it.unimi.dsi.fastutil</pattern>
|
||||||
<shadedPattern>org.geysermc.platform.spigot.shaded.fastutil</shadedPattern>
|
<shadedPattern>org.geysermc.platform.spigot.shaded.fastutil</shadedPattern>
|
||||||
</relocation>
|
</relocation>
|
||||||
|
<relocation>
|
||||||
|
<pattern>com.fasterxml.jackson</pattern>
|
||||||
|
<shadedPattern>org.geysermc.platform.bukkit.shaded.jackson</shadedPattern>
|
||||||
|
</relocation>
|
||||||
</relocations>
|
</relocations>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
|
|
@ -25,120 +25,29 @@
|
||||||
|
|
||||||
package org.geysermc.platform.spigot;
|
package org.geysermc.platform.spigot;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.geysermc.connector.FloodgateKeyLoader;
|
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.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class GeyserSpigotConfiguration implements GeyserConfiguration {
|
@Getter
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class GeyserSpigotConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
private FileConfiguration config;
|
@JsonProperty("floodgate-key-file")
|
||||||
private File dataFolder;
|
private String floodgateKeyFile;
|
||||||
|
|
||||||
private BukkitBedrockConfiguration bedrockConfig;
|
|
||||||
private BukkitRemoteConfiguration remoteConfig;
|
|
||||||
private BukkitMetricsInfo metricsInfo;
|
|
||||||
|
|
||||||
private Map<String, BukkitUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
|
||||||
|
|
||||||
private Path floodgateKey;
|
private Path floodgateKey;
|
||||||
|
|
||||||
public GeyserSpigotConfiguration(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(GeyserSpigotPlugin plugin) {
|
public void loadFloodgate(GeyserSpigotPlugin plugin) {
|
||||||
Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit");
|
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);
|
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
|
|
||||||
public IBedrockConfiguration getBedrock() {
|
|
||||||
return bedrockConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IRemoteConfiguration getRemote() {
|
|
||||||
return remoteConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, BukkitUserAuthenticationInfo> 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -150,92 +59,4 @@ public class GeyserSpigotConfiguration implements GeyserConfiguration {
|
||||||
public boolean isCacheChunks() {
|
public boolean isCacheChunks() {
|
||||||
return true; // We override this as with Bukkit, we have direct access to the server implementation
|
return true; // We override this as with Bukkit, we have direct access to the server implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,10 @@ package org.geysermc.platform.spigot;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.network.translators.world.WorldManager;
|
import org.geysermc.connector.network.translators.world.WorldManager;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
@ -39,9 +39,14 @@ import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
|
||||||
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
||||||
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||||
import org.geysermc.platform.spigot.world.GeyserSpigotWorldManager;
|
import org.geysermc.platform.spigot.world.GeyserSpigotWorldManager;
|
||||||
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import us.myles.ViaVersion.api.Via;
|
import us.myles.ViaVersion.api.Via;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
|
@ -56,26 +61,41 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
saveDefaultConfig();
|
// This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed
|
||||||
|
try {
|
||||||
this.geyserConfig = new GeyserSpigotConfiguration(getDataFolder(), getConfig());
|
if (!getDataFolder().exists()) {
|
||||||
if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) {
|
getDataFolder().mkdir();
|
||||||
getConfig().set("metrics.uuid", UUID.randomUUID().toString());
|
File bukkitConfig = new File("plugins/Geyser-Bukkit/config.yml");
|
||||||
saveConfig();
|
if (bukkitConfig.exists()) { // Copy over old configs
|
||||||
|
getLogger().log(Level.INFO, "Existing config found in the Geyser-Bukkit folder; copying over...");
|
||||||
|
Files.copy(bukkitConfig.toPath(), new File(getDataFolder().toString() + "/config.yml").toPath());
|
||||||
|
getLogger().log(Level.INFO, "Copied!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
||||||
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||||
|
} 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
|
// 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
|
// 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("")) {
|
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());
|
geyserConfig.getRemote().setPort(Bukkit.getPort());
|
||||||
saveConfig();
|
|
||||||
|
|
||||||
this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
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);
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.SPIGOT, this);
|
this.connector = GeyserConnector.start(PlatformType.SPIGOT, this);
|
||||||
|
@ -113,7 +133,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
connector.shutdown();
|
if (connector != null)
|
||||||
|
connector.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -29,7 +29,7 @@ import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
|
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ninja.leaping.configurate.ConfigurationNode;
|
||||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
||||||
import org.geysermc.common.PlatformType;
|
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.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
|
|
@ -26,12 +26,12 @@
|
||||||
package org.geysermc.platform.standalone;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import org.geysermc.common.PlatformType;
|
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.GeyserConnector;
|
||||||
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.platform.standalone.command.GeyserCommandManager;
|
import org.geysermc.platform.standalone.command.GeyserCommandManager;
|
||||||
|
|
||||||
|
|
|
@ -27,110 +27,21 @@ package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserStandaloneConfiguration implements GeyserConfiguration {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
|
||||||
private BedrockConfiguration bedrock;
|
|
||||||
private RemoteConfiguration remote;
|
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
@JsonProperty("floodgate-key-file")
|
||||||
private String floodgateKeyFile;
|
private String floodgateKeyFile;
|
||||||
|
|
||||||
private Map<String, UserAuthenticationInfo> 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("above-bedrock-nether-building")
|
|
||||||
private boolean isAboveBedrockNetherBuilding;
|
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return Paths.get(floodgateKeyFile);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,122 +30,30 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.velocitypowered.api.plugin.PluginContainer;
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
|
||||||
import org.geysermc.connector.FloodgateKeyLoader;
|
import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
|
||||||
@Getter
|
@Getter
|
||||||
public class GeyserVelocityConfiguration implements GeyserConfiguration {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
|
||||||
private BedrockConfiguration bedrock;
|
|
||||||
private RemoteConfiguration remote;
|
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
@JsonProperty("floodgate-key-file")
|
||||||
private String floodgateKeyFile;
|
private String floodgateKeyFile;
|
||||||
|
|
||||||
private Map<String, UserAuthenticationInfo> 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;
|
|
||||||
|
|
||||||
private Path floodgateKey;
|
private Path floodgateKey;
|
||||||
|
|
||||||
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
|
||||||
Optional<PluginContainer> 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
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyFile() {
|
||||||
return floodgateKey;
|
return floodgateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
||||||
public static class BedrockConfiguration implements IBedrockConfiguration {
|
Optional<PluginContainer> 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/")));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import org.geysermc.common.PlatformType;
|
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.GeyserConnector;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||||
|
@ -96,6 +96,11 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
|
||||||
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
|
||||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
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);
|
geyserConfig.loadFloodgate(this, proxyServer, configDir);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
|
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
|
||||||
|
|
|
@ -98,14 +98,8 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>com.github.steveice10</groupId>
|
||||||
<artifactId>opennbt</artifactId>
|
<artifactId>mcprotocollib</artifactId>
|
||||||
<version>1.4-SNAPSHOT</version>
|
<version>4c315aa206</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>packetlib</artifactId>
|
|
||||||
<version>1.5-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
|
@ -115,31 +109,11 @@
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.steveice10</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>mcauthlib</artifactId>
|
<artifactId>netty-resolver-dns</artifactId>
|
||||||
<version>1.3-SNAPSHOT</version>
|
<version>4.1.43.Final</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>mcprotocollib</artifactId>
|
|
||||||
<version>1.15.2-1-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>opennbt</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>packetlib</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.github.steveice10</groupId>
|
|
||||||
<artifactId>mcauthlib</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.reflections</groupId>
|
<groupId>org.reflections</groupId>
|
||||||
<artifactId>reflections</artifactId>
|
<artifactId>reflections</artifactId>
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
|
|
||||||
package org.geysermc.connector;
|
package org.geysermc.connector;
|
||||||
|
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.geysermc.common.AuthType;
|
||||||
import org.geysermc.common.PlatformType;
|
import org.geysermc.common.PlatformType;
|
||||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
import org.geysermc.connector.metrics.Metrics;
|
import org.geysermc.connector.metrics.Metrics;
|
||||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||||
import org.geysermc.connector.network.remote.RemoteServer;
|
import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
package org.geysermc.connector.bootstrap;
|
package org.geysermc.connector.bootstrap;
|
||||||
|
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
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.GeyserLogger;
|
||||||
import org.geysermc.connector.command.CommandManager;
|
import org.geysermc.connector.command.CommandManager;
|
||||||
import org.geysermc.connector.network.translators.world.CachedChunkManager;
|
import org.geysermc.connector.network.translators.world.CachedChunkManager;
|
||||||
|
|
|
@ -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.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
|
@ -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<String, UserAuthenticationInfo> 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;
|
||||||
|
}
|
|
@ -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() { }
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction;
|
||||||
import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace;
|
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.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
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.ClientPlayerActionPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
@ -209,13 +210,12 @@ public class Entity {
|
||||||
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, (xd & 0x01) == 0x01);
|
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, (xd & 0x01) == 0x01);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
|
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);
|
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||||
|
|
||||||
if ((xd & 0x20) == 0x20) {
|
if ((xd & 0x20) == 0x20) {
|
||||||
if (this.is(ArmorStandEntity.class)) {
|
// Armour stands are handled in their own class
|
||||||
metadata.put(EntityData.SCALE, 0.0f);
|
if (!this.is(ArmorStandEntity.class)) {
|
||||||
} else {
|
|
||||||
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -253,9 +253,15 @@ public class Entity {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: // custom name
|
case 2: // custom name
|
||||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
if (entityMetadata.getValue() instanceof TextMessage) {
|
||||||
if (name != null)
|
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||||
metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name));
|
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;
|
break;
|
||||||
case 3: // is custom name visible
|
case 3: // is custom name visible
|
||||||
if (!this.is(PlayerEntity.class))
|
if (!this.is(PlayerEntity.class))
|
||||||
|
|
|
@ -37,6 +37,7 @@ import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.utils.FireworkColor;
|
import org.geysermc.connector.utils.FireworkColor;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -63,7 +64,7 @@ public class FireworkEntity extends Entity {
|
||||||
|
|
||||||
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
|
CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder();
|
||||||
if (fireworks.get("Flight") != null) {
|
if (fireworks.get("Flight") != null) {
|
||||||
fireworksBuilder.byteTag("Flight", (Byte) fireworks.get("Flight").getValue());
|
fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<com.nukkitx.nbt.tag.CompoundTag> explosions = new ArrayList<>();
|
List<com.nukkitx.nbt.tag.CompoundTag> explosions = new ArrayList<>();
|
||||||
|
@ -73,7 +74,7 @@ public class FireworkEntity extends Entity {
|
||||||
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
|
CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder();
|
||||||
|
|
||||||
if (effectData.get("Type") != null) {
|
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) {
|
if (effectData.get("Colors") != null) {
|
||||||
|
@ -101,11 +102,11 @@ public class FireworkEntity extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("Trail") != null) {
|
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) {
|
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());
|
explosions.add(effectBuilder.buildRootTag());
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ public class ItemEntity extends Entity {
|
||||||
itemPacket.setUniqueEntityId(geyserId);
|
itemPacket.setUniqueEntityId(geyserId);
|
||||||
itemPacket.setFromFishing(false);
|
itemPacket.setFromFishing(false);
|
||||||
itemPacket.getMetadata().putAll(metadata);
|
itemPacket.getMetadata().putAll(metadata);
|
||||||
itemPacket.setItemInHand(ItemTranslator.translateToBedrock((ItemStack) entityMetadata.getValue()));
|
itemPacket.setItemInHand(ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()));
|
||||||
session.sendUpstreamPacket(itemPacket);
|
session.sendUpstreamPacket(itemPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class ItemFrameEntity extends Entity {
|
||||||
@Override
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) {
|
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());
|
ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue());
|
||||||
CompoundTagBuilder builder = CompoundTag.builder();
|
CompoundTagBuilder builder = CompoundTag.builder();
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.EntityData;
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
public class MinecartEntity extends Entity {
|
public class MinecartEntity extends Entity {
|
||||||
|
|
||||||
|
@ -54,6 +55,24 @@ public class MinecartEntity extends Entity {
|
||||||
metadata.put(EntityData.HURT_TIME, Math.min((int) (float) entityMetadata.getValue(), 15));
|
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);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,17 +35,42 @@ import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
public class ArmorStandEntity extends LivingEntity {
|
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) {
|
public ArmorStandEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) {
|
||||||
super(entityId, geyserId, entityType, position, motion, 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
|
@Override
|
||||||
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
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();
|
byte xd = (byte) entityMetadata.getValue();
|
||||||
|
|
||||||
// isSmall
|
// isSmall
|
||||||
if ((xd & 0x01) == 0x01) {
|
if ((xd & 0x01) == 0x01) {
|
||||||
|
isSmall = true;
|
||||||
|
|
||||||
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
if (metadata.getFloat(EntityData.SCALE) != 0.55f && metadata.getFloat(EntityData.SCALE) != 0.0f) {
|
||||||
metadata.put(EntityData.SCALE, 0.55f);
|
metadata.put(EntityData.SCALE, 0.55f);
|
||||||
}
|
}
|
||||||
|
@ -60,9 +85,10 @@ public class ArmorStandEntity extends LivingEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setMarker
|
// 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_WIDTH, 0.0f);
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f);
|
||||||
|
isMarker = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
|
@ -105,7 +105,7 @@ public enum EntityType {
|
||||||
THROWN_EXP_BOTTLE(ThrowableEntity.class, 68, 0.25f, 0.25f, 0f, 0f, "minecraft:xp_bottle"),
|
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"),
|
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"),
|
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"),
|
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"),
|
TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"),
|
||||||
TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f),
|
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_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_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_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"),
|
MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"),
|
||||||
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
LINGERING_POTION(ThrowableEntity.class, 101, 0f),
|
||||||
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
LLAMA_SPIT(Entity.class, 102, 0.25f),
|
||||||
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f),
|
EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"),
|
||||||
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.5f),
|
EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"),
|
||||||
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
VEX(MonsterEntity.class, 105, 0.8f, 0.4f),
|
||||||
ICE_BOMB(Entity.class, 106, 0f),
|
ICE_BOMB(Entity.class, 106, 0f),
|
||||||
BALLOON(Entity.class, 107, 0f), //TODO
|
BALLOON(Entity.class, 107, 0f), //TODO
|
||||||
|
|
|
@ -31,7 +31,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
import org.geysermc.common.ping.GeyserPingInfo;
|
import org.geysermc.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
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.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
|
@ -60,6 +60,7 @@ public class QueryPacketHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Query packet handler instance
|
* The Query packet handler instance
|
||||||
|
*
|
||||||
* @param connector Geyser Connector
|
* @param connector Geyser Connector
|
||||||
* @param sender The Sender IP/Port for the Query
|
* @param sender The Sender IP/Port for the Query
|
||||||
* @param buffer The Query data
|
* @param buffer The Query data
|
||||||
|
@ -79,11 +80,12 @@ public class QueryPacketHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the packet is in fact a query packet
|
* Checks the packet is in fact a query packet
|
||||||
|
*
|
||||||
* @param buffer Query data
|
* @param buffer Query data
|
||||||
* @return if the packet is a query packet
|
* @return if the packet is a query packet
|
||||||
*/
|
*/
|
||||||
private boolean isQueryPacket(ByteBuf buffer) {
|
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 @@ public class QueryPacketHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the game data for the query
|
* Gets the game data for the query
|
||||||
|
*
|
||||||
* @return the game data for the query
|
* @return the game data for the query
|
||||||
*/
|
*/
|
||||||
private byte[] getGameData() {
|
private byte[] getGameData() {
|
||||||
|
@ -177,7 +180,7 @@ public class QueryPacketHandler {
|
||||||
// Blank Buffer Bytes
|
// Blank Buffer Bytes
|
||||||
query.write("GeyserMC".getBytes());
|
query.write("GeyserMC".getBytes());
|
||||||
query.write((byte) 0x00);
|
query.write((byte) 0x00);
|
||||||
query.write((byte) 128);
|
query.write((byte) 0x80);
|
||||||
query.write((byte) 0x00);
|
query.write((byte) 0x00);
|
||||||
|
|
||||||
// Fills the game data
|
// Fills the game data
|
||||||
|
@ -189,7 +192,7 @@ public class QueryPacketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final byte to show the end of the game data
|
// 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();
|
return query.toByteArray();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -197,6 +200,11 @@ public class QueryPacketHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a byte[] storing the player names
|
||||||
|
*
|
||||||
|
* @return The byte[] representation of players
|
||||||
|
*/
|
||||||
private byte[] getPlayers() {
|
private byte[] getPlayers() {
|
||||||
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
ByteArrayOutputStream query = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
@ -208,7 +216,7 @@ public class QueryPacketHandler {
|
||||||
try {
|
try {
|
||||||
// Start the player section
|
// Start the player section
|
||||||
query.write("player_".getBytes());
|
query.write("player_".getBytes());
|
||||||
query.write(new byte[]{0x00, 0x00});
|
query.write(new byte[] { 0x00, 0x00 });
|
||||||
|
|
||||||
// Fill player names
|
// Fill player names
|
||||||
if(pingInfo != null) {
|
if(pingInfo != null) {
|
||||||
|
@ -229,6 +237,7 @@ public class QueryPacketHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a packet to the sender
|
* Sends a packet to the sender
|
||||||
|
*
|
||||||
* @param data packet data
|
* @param data packet data
|
||||||
*/
|
*/
|
||||||
private void sendPacket(ByteBuf data) {
|
private void sendPacket(ByteBuf data) {
|
||||||
|
@ -251,18 +260,28 @@ public class QueryPacketHandler {
|
||||||
* Gets an MD5 token for the current IP/Port.
|
* Gets an MD5 token for the current IP/Port.
|
||||||
* This should reset every 30 seconds but a new one is generated per instance
|
* 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.
|
* Seems wasteful to code something in to clear it when it has no use.
|
||||||
|
*
|
||||||
* @param token the token
|
* @param token the token
|
||||||
* @param address the address
|
* @param address the address
|
||||||
* @return an MD5 token for the current IP/Port
|
* @return an MD5 token for the current IP/Port
|
||||||
*/
|
*/
|
||||||
public static byte[] getTokenString(byte[] token, InetAddress address) {
|
public static byte[] getTokenString(byte[] token, InetAddress address) {
|
||||||
try {
|
try {
|
||||||
|
// Generate an MD5 hash from the address
|
||||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||||
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
|
digest.update(address.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
digest.update(token);
|
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) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array();
|
return (ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).getInt() + "\0").getBytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ package org.geysermc.connector.network;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import org.geysermc.common.AuthType;
|
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.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
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.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.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket;
|
||||||
|
@ -41,14 +42,10 @@ import com.github.steveice10.packetlib.event.session.*;
|
||||||
import com.github.steveice10.packetlib.packet.Packet;
|
import com.github.steveice10.packetlib.packet.Packet;
|
||||||
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||||
import com.nukkitx.math.GenericMath;
|
import com.nukkitx.math.GenericMath;
|
||||||
import com.nukkitx.math.TrigMath;
|
|
||||||
import com.nukkitx.math.vector.*;
|
import com.nukkitx.math.vector.*;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.*;
|
||||||
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.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
import it.unimi.dsi.fastutil.objects.Object2LongMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
|
||||||
|
@ -60,6 +57,7 @@ import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.PlayerEntity;
|
import org.geysermc.connector.entity.PlayerEntity;
|
||||||
|
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||||
import org.geysermc.connector.inventory.PlayerInventory;
|
import org.geysermc.connector.inventory.PlayerInventory;
|
||||||
import org.geysermc.connector.network.remote.RemoteServer;
|
import org.geysermc.connector.network.remote.RemoteServer;
|
||||||
import org.geysermc.connector.network.session.auth.AuthData;
|
import org.geysermc.connector.network.session.auth.AuthData;
|
||||||
|
@ -72,6 +70,7 @@ import org.geysermc.connector.network.translators.item.ItemRegistry;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.utils.ChunkUtils;
|
import org.geysermc.connector.utils.ChunkUtils;
|
||||||
import org.geysermc.connector.utils.LocaleUtils;
|
import org.geysermc.connector.utils.LocaleUtils;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
import org.geysermc.connector.utils.SkinUtils;
|
import org.geysermc.connector.utils.SkinUtils;
|
||||||
import org.geysermc.floodgate.util.BedrockData;
|
import org.geysermc.floodgate.util.BedrockData;
|
||||||
import org.geysermc.floodgate.util.EncryptionUtil;
|
import org.geysermc.floodgate.util.EncryptionUtil;
|
||||||
|
@ -81,6 +80,8 @@ import java.net.InetSocketAddress;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -166,6 +167,14 @@ public class GeyserSession implements CommandSender {
|
||||||
@Setter
|
@Setter
|
||||||
private int craftSlot = 0;
|
private int craftSlot = 0;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private long lastWindowCloseTime = 0;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private VillagerTrade[] villagerTrades;
|
||||||
|
@Setter
|
||||||
|
private long lastInteractedVillagerEid;
|
||||||
|
|
||||||
private MinecraftProtocol protocol;
|
private MinecraftProtocol protocol;
|
||||||
|
|
||||||
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) {
|
||||||
|
@ -211,6 +220,15 @@ public class GeyserSession implements CommandSender {
|
||||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||||
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN);
|
||||||
upstream.sendPacket(playStatusPacket);
|
upstream.sendPacket(playStatusPacket);
|
||||||
|
|
||||||
|
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
|
||||||
|
attributesPacket.setRuntimeEntityId(getPlayerEntity().getGeyserId());
|
||||||
|
List<Attribute> 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 fetchOurSkin(PlayerListPacket.Entry entry) {
|
public void fetchOurSkin(PlayerListPacket.Entry entry) {
|
||||||
|
@ -366,6 +384,14 @@ public class GeyserSession implements CommandSender {
|
||||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
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();
|
downstream.getSession().connect();
|
||||||
|
@ -436,7 +462,7 @@ public class GeyserSession implements CommandSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRenderDistance(int renderDistance) {
|
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)
|
if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x)
|
||||||
this.renderDistance = renderDistance;
|
this.renderDistance = renderDistance;
|
||||||
|
|
||||||
|
|
|
@ -25,18 +25,19 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators;
|
package org.geysermc.connector.network.translators;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket;
|
||||||
import java.util.Map;
|
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.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 it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
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 org.reflections.Reflections;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PacketTranslatorRegistry<T> {
|
public class PacketTranslatorRegistry<T> {
|
||||||
private final Map<Class<? extends T>, PacketTranslator<? extends T>> translators = new HashMap<>();
|
private final Map<Class<? extends T>, PacketTranslator<? extends T>> translators = new HashMap<>();
|
||||||
|
|
||||||
|
@ -72,7 +73,9 @@ public class PacketTranslatorRegistry<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
private PacketTranslatorRegistry() {
|
||||||
|
|
|
@ -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<AdventureSettingsPacket> {
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,17 +38,21 @@ public class BedrockContainerCloseTranslator extends PacketTranslator<ContainerC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
public void translate(ContainerClosePacket packet, GeyserSession session) {
|
||||||
|
session.setLastWindowCloseTime(0);
|
||||||
byte windowId = packet.getWindowId();
|
byte windowId = packet.getWindowId();
|
||||||
|
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||||
if (windowId == -1) { //player inventory or crafting table
|
if (windowId == -1) { //player inventory or crafting table
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
windowId = (byte) openInventory.getId();
|
windowId = (byte) openInventory.getId();
|
||||||
} else {
|
} else {
|
||||||
windowId = 0;
|
windowId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
|
||||||
session.sendDownstreamPacket(closeWindowPacket);
|
if (windowId == 0 || (openInventory != null && openInventory.getId() == windowId)) {
|
||||||
InventoryUtils.closeInventory(session, windowId);
|
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(windowId);
|
||||||
|
session.getDownstream().getSession().send(closeWindowPacket);
|
||||||
|
InventoryUtils.closeInventory(session, windowId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,13 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.bedrock;
|
package org.geysermc.connector.network.translators.bedrock;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.window.WindowType;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
import com.nukkitx.protocol.bedrock.packet.EntityEventPacket;
|
||||||
|
import org.geysermc.connector.entity.Entity;
|
||||||
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
@ -41,6 +47,22 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
|
||||||
case EATING_ITEM:
|
case EATING_ITEM:
|
||||||
session.sendUpstreamPacket(packet);
|
session.sendUpstreamPacket(packet);
|
||||||
return;
|
return;
|
||||||
|
case COMPLETE_TRADE:
|
||||||
|
ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
|
||||||
|
session.getDownstream().getSession().send(selectTradePacket);
|
||||||
|
|
||||||
|
Entity villager = session.getPlayerEntity();
|
||||||
|
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||||
|
if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) {
|
||||||
|
VillagerTrade[] trades = session.getVillagerTrades();
|
||||||
|
if (trades != null && packet.getData() >= 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());
|
session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket;
|
||||||
|
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.ItemFrameEntity;
|
import org.geysermc.connector.entity.ItemFrameEntity;
|
||||||
|
import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
|
@ -198,6 +199,10 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||||
session.sendDownstreamPacket(interactAtPacket);
|
session.sendDownstreamPacket(interactAtPacket);
|
||||||
|
|
||||||
EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity);
|
EntitySoundInteractionHandler.handleEntityInteraction(session, vector, entity);
|
||||||
|
|
||||||
|
if (entity instanceof AbstractMerchantEntity) {
|
||||||
|
session.setLastInteractedVillagerEid(packet.getRuntimeEntityId());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1: //Attack
|
case 1: //Attack
|
||||||
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(),
|
||||||
|
|
|
@ -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<InventoryActionData> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,7 +92,10 @@ public class CraftingInventoryTranslator extends BaseInventoryTranslator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int javaSlotToBedrock(int slot) {
|
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
|
@Override
|
||||||
|
|
|
@ -39,15 +39,13 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater;
|
||||||
import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater;
|
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 int blockId;
|
||||||
private final InventoryUpdater updater;
|
|
||||||
|
|
||||||
public DoubleChestInventoryTranslator(int size) {
|
public DoubleChestInventoryTranslator(int size) {
|
||||||
super(size);
|
super(size, 54);
|
||||||
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]");
|
||||||
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState);
|
||||||
this.updater = new ChestInventoryUpdater(54);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,14 +126,4 @@ public class DoubleChestInventoryTranslator extends BaseInventoryTranslator {
|
||||||
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
blockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(realBlock));
|
||||||
session.sendUpstreamPacket(blockPacket);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ public abstract class InventoryTranslator {
|
||||||
put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
put(WindowType.ANVIL, new AnvilInventoryTranslator());
|
||||||
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
put(WindowType.CRAFTING, new CraftingInventoryTranslator());
|
||||||
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator());
|
||||||
|
put(WindowType.MERCHANT, new MerchantInventoryTranslator());
|
||||||
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
//put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO
|
||||||
|
|
||||||
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
InventoryTranslator furnace = new FurnaceInventoryTranslator();
|
||||||
|
|
|
@ -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<InventoryActionData> actions) {
|
||||||
|
for (InventoryActionData action : actions) {
|
||||||
|
if (action.getSource().getType() == InventorySource.Type.NON_IMPLEMENTED_TODO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.translateActions(session, inventory, actions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,11 +59,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||||
ItemData[] contents = new ItemData[36];
|
ItemData[] contents = new ItemData[36];
|
||||||
// Inventory
|
// Inventory
|
||||||
for (int i = 9; i < 36; i++) {
|
for (int i = 9; i < 36; i++) {
|
||||||
contents[i] = ItemTranslator.translateToBedrock(inventory.getItem(i));
|
contents[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||||
}
|
}
|
||||||
// Hotbar
|
// Hotbar
|
||||||
for (int i = 36; i < 45; i++) {
|
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);
|
inventoryContentPacket.setContents(contents);
|
||||||
session.sendUpstreamPacket(inventoryContentPacket);
|
session.sendUpstreamPacket(inventoryContentPacket);
|
||||||
|
@ -73,7 +73,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||||
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
armorContentPacket.setContainerId(ContainerId.ARMOR);
|
||||||
contents = new ItemData[4];
|
contents = new ItemData[4];
|
||||||
for (int i = 5; i < 9; i++) {
|
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);
|
armorContentPacket.setContents(contents);
|
||||||
session.sendUpstreamPacket(armorContentPacket);
|
session.sendUpstreamPacket(armorContentPacket);
|
||||||
|
@ -81,7 +81,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||||
// Offhand
|
// Offhand
|
||||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
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);
|
session.sendUpstreamPacket(offhandPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||||
if (session.getGameMode() == GameMode.CREATIVE) {
|
if (session.getGameMode() == GameMode.CREATIVE) {
|
||||||
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
slotPacket.setItem(UNUSUABLE_CRAFTING_SPACE_BLOCK);
|
||||||
}else{
|
}else{
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
|
@ -125,12 +125,12 @@ public class PlayerInventoryTranslator extends InventoryTranslator {
|
||||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||||
slotPacket.setSlot(slot + 27);
|
slotPacket.setSlot(slot + 27);
|
||||||
}
|
}
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(slot)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
} else if (slot == 45) {
|
} else if (slot == 45) {
|
||||||
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
InventoryContentPacket offhandPacket = new InventoryContentPacket();
|
||||||
offhandPacket.setContainerId(ContainerId.OFFHAND);
|
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);
|
session.sendUpstreamPacket(offhandPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,35 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.inventory;
|
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 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) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,13 +61,13 @@ public class InventoryActionDataTranslator {
|
||||||
worldAction = action;
|
worldAction = action;
|
||||||
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
|
} else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) {
|
||||||
cursorAction = action;
|
cursorAction = action;
|
||||||
ItemData translatedCursor = ItemTranslator.translateToBedrock(session.getInventory().getCursor());
|
ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor());
|
||||||
if (!translatedCursor.equals(action.getFromItem())) {
|
if (!translatedCursor.equals(action.getFromItem())) {
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
containerAction = action;
|
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())) {
|
if (!translatedItem.equals(action.getFromItem())) {
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
|
@ -187,11 +187,12 @@ public class InventoryActionDataTranslator {
|
||||||
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
|
} else if (translator.getSlotType(javaSlot) == SlotType.OUTPUT) {
|
||||||
plan.add(Click.LEFT, javaSlot);
|
plan.add(Click.LEFT, javaSlot);
|
||||||
} else {
|
} 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) {
|
if (cursorSlot != -1) {
|
||||||
plan.add(Click.LEFT, cursorSlot);
|
plan.add(Click.LEFT, cursorSlot);
|
||||||
} else {
|
} else {
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
|
InventoryUtils.updateCursor(session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
plan.add(Click.LEFT, javaSlot);
|
plan.add(Click.LEFT, javaSlot);
|
||||||
|
@ -245,11 +246,15 @@ public class InventoryActionDataTranslator {
|
||||||
|
|
||||||
int cursorSlot = -1;
|
int cursorSlot = -1;
|
||||||
if (session.getInventory().getCursor() != null) { //move cursor contents to a temporary slot
|
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) {
|
if (cursorSlot != -1) {
|
||||||
plan.add(Click.LEFT, cursorSlot);
|
plan.add(Click.LEFT, cursorSlot);
|
||||||
} else {
|
} else {
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
|
InventoryUtils.updateCursor(session);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +303,7 @@ public class InventoryActionDataTranslator {
|
||||||
InventoryUtils.updateCursor(session);
|
InventoryUtils.updateCursor(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist) {
|
private static int findTempSlot(Inventory inventory, ItemStack item, List<Integer> slotBlacklist, boolean emptyOnly) {
|
||||||
/*try and find a slot that can temporarily store the given item
|
/*try and find a slot that can temporarily store the given item
|
||||||
only look in the main inventory and hotbar
|
only look in the main inventory and hotbar
|
||||||
only slots that are empty or contain a different type of item are valid*/
|
only slots that are empty or contain a different type of item are valid*/
|
||||||
|
@ -314,6 +319,9 @@ public class InventoryActionDataTranslator {
|
||||||
ItemStack testItem = inventory.getItem(i);
|
ItemStack testItem = inventory.getItem(i);
|
||||||
boolean acceptable = true;
|
boolean acceptable = true;
|
||||||
if (testItem != null) {
|
if (testItem != null) {
|
||||||
|
if (emptyOnly) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (ItemStack blacklistItem : itemBlacklist) {
|
for (ItemStack blacklistItem : itemBlacklist) {
|
||||||
if (InventoryUtils.canStack(testItem, blacklistItem)) {
|
if (InventoryUtils.canStack(testItem, blacklistItem)) {
|
||||||
acceptable = false;
|
acceptable = false;
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
||||||
ItemData[] bedrockItems = new ItemData[paddedSize];
|
ItemData[] bedrockItems = new ItemData[paddedSize];
|
||||||
for (int i = 0; i < bedrockItems.length; i++) {
|
for (int i = 0; i < bedrockItems.length; i++) {
|
||||||
if (i < translator.size) {
|
if (i < translator.size) {
|
||||||
bedrockItems[i] = ItemTranslator.translateToBedrock(inventory.getItem(i));
|
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||||
} else {
|
} else {
|
||||||
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
bedrockItems[i] = UNUSUABLE_SPACE_BLOCK;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class ChestInventoryUpdater extends InventoryUpdater {
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(inventory.getId());
|
slotPacket.setContainerId(inventory.getId());
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
||||||
|
|
||||||
ItemData[] bedrockItems = new ItemData[translator.size];
|
ItemData[] bedrockItems = new ItemData[translator.size];
|
||||||
for (int i = 0; i < bedrockItems.length; i++) {
|
for (int i = 0; i < bedrockItems.length; i++) {
|
||||||
bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(inventory.getItem(i));
|
bedrockItems[translator.javaSlotToBedrock(i)] = ItemTranslator.translateToBedrock(session, inventory.getItem(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||||
|
@ -57,7 +57,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater {
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(inventory.getId());
|
slotPacket.setContainerId(inventory.getId());
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||||
slotPacket.setSlot(bedrockSlot);
|
slotPacket.setSlot(bedrockSlot);
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(i)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ public class CursorInventoryUpdater extends InventoryUpdater {
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.CURSOR);
|
slotPacket.setContainerId(ContainerId.CURSOR);
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public abstract class InventoryUpdater {
|
||||||
ItemData[] bedrockItems = new ItemData[36];
|
ItemData[] bedrockItems = new ItemData[36];
|
||||||
for (int i = 0; i < 36; i++) {
|
for (int i = 0; i < 36; i++) {
|
||||||
final int offset = i < 9 ? 27 : -9;
|
final int offset = i < 9 ? 27 : -9;
|
||||||
bedrockItems[i] = ItemTranslator.translateToBedrock(inventory.getItem(translator.size + i + offset));
|
bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(translator.size + i + offset));
|
||||||
}
|
}
|
||||||
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
InventoryContentPacket contentPacket = new InventoryContentPacket();
|
||||||
contentPacket.setContainerId(ContainerId.INVENTORY);
|
contentPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
|
@ -52,7 +52,7 @@ public abstract class InventoryUpdater {
|
||||||
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
InventorySlotPacket slotPacket = new InventorySlotPacket();
|
||||||
slotPacket.setContainerId(ContainerId.INVENTORY);
|
slotPacket.setContainerId(ContainerId.INVENTORY);
|
||||||
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot));
|
||||||
slotPacket.setItem(ItemTranslator.translateToBedrock(inventory.getItem(javaSlot)));
|
slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot)));
|
||||||
session.sendUpstreamPacket(slotPacket);
|
session.sendUpstreamPacket(slotPacket);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
package org.geysermc.connector.network.translators.item;
|
package org.geysermc.connector.network.translators.item;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
|
||||||
|
import com.github.steveice10.mc.protocol.data.message.Message;
|
||||||
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||||
import com.nukkitx.nbt.tag.CompoundTag;
|
import com.nukkitx.nbt.tag.CompoundTag;
|
||||||
import com.nukkitx.nbt.tag.Tag;
|
import com.nukkitx.nbt.tag.Tag;
|
||||||
|
@ -34,7 +36,9 @@ import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -115,7 +119,7 @@ public abstract class ItemTranslator {
|
||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemData translateToBedrock(ItemStack stack) {
|
public static ItemData translateToBedrock(GeyserSession session, ItemStack stack) {
|
||||||
if (stack == null) {
|
if (stack == null) {
|
||||||
return ItemData.AIR;
|
return ItemData.AIR;
|
||||||
}
|
}
|
||||||
|
@ -132,12 +136,42 @@ public abstract class ItemTranslator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ItemData itemData;
|
||||||
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId());
|
ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId());
|
||||||
if (itemStackTranslator != null) {
|
if (itemStackTranslator != null) {
|
||||||
return itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
itemData = itemStackTranslator.translateToBedrock(itemStack, bedrockItem);
|
||||||
} else {
|
} else {
|
||||||
return DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the display name of the item
|
||||||
|
CompoundTag tag = itemData.getTag();
|
||||||
|
if (tag != null) {
|
||||||
|
CompoundTag display = tag.getCompound("display");
|
||||||
|
if (display != null) {
|
||||||
|
String name = display.getString("Name");
|
||||||
|
|
||||||
|
// Check if its a message to translate
|
||||||
|
if (MessageUtils.isMessage(name)) {
|
||||||
|
// Get the translated name
|
||||||
|
name = MessageUtils.getTranslatedBedrockMessage(Message.fromString(name), session.getClientData().getLanguageCode());
|
||||||
|
|
||||||
|
// Build the new display tag
|
||||||
|
CompoundTagBuilder displayBuilder = display.toBuilder();
|
||||||
|
displayBuilder.stringTag("Name", name);
|
||||||
|
|
||||||
|
// Build the new root tag
|
||||||
|
CompoundTagBuilder builder = tag.toBuilder();
|
||||||
|
builder.tag(displayBuilder.build("display"));
|
||||||
|
|
||||||
|
// Create a new item with the original data + updated name
|
||||||
|
itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() {
|
||||||
|
@ -351,5 +385,49 @@ public abstract class ItemTranslator {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an {@link ItemStack} is equal to another item stack
|
||||||
|
*
|
||||||
|
* @param itemStack the item stack to check
|
||||||
|
* @param equalsItemStack the item stack to check if equal to
|
||||||
|
* @param checkAmount if the amount should be taken into account
|
||||||
|
* @param trueIfAmountIsGreater if this should return true if the amount of the
|
||||||
|
* first item stack is greater than that of the second
|
||||||
|
* @param checkNbt if NBT data should be checked
|
||||||
|
* @return if an item stack is equal to another item stack
|
||||||
|
*/
|
||||||
|
public boolean equals(ItemStack itemStack, ItemStack equalsItemStack, boolean checkAmount, boolean trueIfAmountIsGreater, boolean checkNbt) {
|
||||||
|
if (itemStack.getId() != equalsItemStack.getId()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkAmount) {
|
||||||
|
if (trueIfAmountIsGreater) {
|
||||||
|
if (itemStack.getAmount() < equalsItemStack.getAmount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (itemStack.getAmount() != equalsItemStack.getAmount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkNbt) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((itemStack.getNbt() == null || itemStack.getNbt().isEmpty()) && (equalsItemStack.getNbt() != null && !equalsItemStack.getNbt().isEmpty())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((itemStack.getNbt() != null && !itemStack.getNbt().isEmpty() && (equalsItemStack.getNbt() == null || !equalsItemStack.getNbt().isEmpty()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemStack.getNbt() != null && equalsItemStack.getNbt() != null) {
|
||||||
|
return itemStack.getNbt().equals(equalsItemStack.getNbt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,10 @@ package org.geysermc.connector.network.translators.item.translators.nbt;
|
||||||
|
|
||||||
import com.github.steveice10.opennbt.tag.builtin.*;
|
import com.github.steveice10.opennbt.tag.builtin.*;
|
||||||
import org.geysermc.connector.network.translators.ItemRemapper;
|
import org.geysermc.connector.network.translators.ItemRemapper;
|
||||||
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
|
||||||
import org.geysermc.connector.network.translators.item.ItemEntry;
|
import org.geysermc.connector.network.translators.item.ItemEntry;
|
||||||
|
import org.geysermc.connector.network.translators.item.NbtItemStackTranslator;
|
||||||
import org.geysermc.connector.utils.FireworkColor;
|
import org.geysermc.connector.utils.FireworkColor;
|
||||||
|
import org.geysermc.connector.utils.MathUtils;
|
||||||
|
|
||||||
@ItemRemapper
|
@ItemRemapper
|
||||||
public class FireworkTranslator extends NbtItemStackTranslator {
|
public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
|
@ -41,6 +42,10 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||||
|
if (fireworks.get("Flight") != null) {
|
||||||
|
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
ListTag explosions = fireworks.get("Explosions");
|
ListTag explosions = fireworks.get("Explosions");
|
||||||
if (explosions == null) {
|
if (explosions == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -51,7 +56,7 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
CompoundTag newEffectData = new CompoundTag("");
|
CompoundTag newEffectData = new CompoundTag("");
|
||||||
|
|
||||||
if (effectData.get("Type") != null) {
|
if (effectData.get("Type") != null) {
|
||||||
newEffectData.put(new ByteTag("FireworkType", (Byte) effectData.get("Type").getValue()));
|
newEffectData.put(new ByteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("Colors") != null) {
|
if (effectData.get("Colors") != null) {
|
||||||
|
@ -79,11 +84,11 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("Trail") != null) {
|
if (effectData.get("Trail") != null) {
|
||||||
newEffectData.put(new ByteTag("FireworkTrail", (Byte) effectData.get("Trail").getValue()));
|
newEffectData.put(new ByteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("Flicker") != null) {
|
if (effectData.get("Flicker") != null) {
|
||||||
newEffectData.put(new ByteTag("FireworkFlicker", (Byte) effectData.get("Flicker").getValue()));
|
newEffectData.put(new ByteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
explosions.remove(effect);
|
explosions.remove(effect);
|
||||||
|
@ -94,6 +99,9 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
@Override
|
@Override
|
||||||
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) {
|
||||||
CompoundTag fireworks = itemTag.get("Fireworks");
|
CompoundTag fireworks = itemTag.get("Fireworks");
|
||||||
|
if (fireworks.get("Flight") != null) {
|
||||||
|
fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
ListTag explosions = fireworks.get("Explosions");
|
ListTag explosions = fireworks.get("Explosions");
|
||||||
for (Tag effect : explosions.getValue()) {
|
for (Tag effect : explosions.getValue()) {
|
||||||
|
@ -102,7 +110,7 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
CompoundTag newEffectData = new CompoundTag("");
|
CompoundTag newEffectData = new CompoundTag("");
|
||||||
|
|
||||||
if (effectData.get("FireworkType") != null) {
|
if (effectData.get("FireworkType") != null) {
|
||||||
newEffectData.put(new ByteTag("Type", (Byte) effectData.get("FireworkType").getValue()));
|
newEffectData.put(new ByteTag("Type", MathUtils.convertByte(effectData.get("FireworkType").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("FireworkColor") != null) {
|
if (effectData.get("FireworkColor") != null) {
|
||||||
|
@ -130,11 +138,11 @@ public class FireworkTranslator extends NbtItemStackTranslator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("FireworkTrail") != null) {
|
if (effectData.get("FireworkTrail") != null) {
|
||||||
newEffectData.put(new ByteTag("Trail", (Byte) effectData.get("FireworkTrail").getValue()));
|
newEffectData.put(new ByteTag("Trail", MathUtils.convertByte(effectData.get("FireworkTrail").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectData.get("FireworkFlicker") != null) {
|
if (effectData.get("FireworkFlicker") != null) {
|
||||||
newEffectData.put(new ByteTag("Flicker", (Byte) effectData.get("FireworkFlicker").getValue()));
|
newEffectData.put(new ByteTag("Flicker", MathUtils.convertByte(effectData.get("FireworkFlicker").getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
explosions.remove(effect);
|
explosions.remove(effect);
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
||||||
switch (recipe.getType()) {
|
switch (recipe.getType()) {
|
||||||
case CRAFTING_SHAPELESS: {
|
case CRAFTING_SHAPELESS: {
|
||||||
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
|
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
|
||||||
ItemData output = ItemTranslator.translateToBedrock(shapelessRecipeData.getResult());
|
ItemData output = ItemTranslator.translateToBedrock(session, shapelessRecipeData.getResult());
|
||||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||||
ItemData[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
|
ItemData[][] inputCombinations = combinations(session, shapelessRecipeData.getIngredients());
|
||||||
for (ItemData[] inputs : inputCombinations) {
|
for (ItemData[] inputs : inputCombinations) {
|
||||||
|
@ -76,7 +76,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
||||||
}
|
}
|
||||||
case CRAFTING_SHAPED: {
|
case CRAFTING_SHAPED: {
|
||||||
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
|
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
|
||||||
ItemData output = ItemTranslator.translateToBedrock(shapedRecipeData.getResult());
|
ItemData output = ItemTranslator.translateToBedrock(session, shapedRecipeData.getResult());
|
||||||
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
output = ItemData.of(output.getId(), output.getDamage(), output.getCount()); //strip NBT
|
||||||
ItemData[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
|
ItemData[][] inputCombinations = combinations(session, shapedRecipeData.getIngredients());
|
||||||
for (ItemData[] inputs : inputCombinations) {
|
for (ItemData[] inputs : inputCombinations) {
|
||||||
|
@ -103,7 +103,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
||||||
}
|
}
|
||||||
Ingredient ingredient = ingredients[i];
|
Ingredient ingredient = ingredients[i];
|
||||||
Map<GroupedItem, List<ItemData>> groupedByIds = Arrays.stream(ingredient.getOptions())
|
Map<GroupedItem, List<ItemData>> 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())));
|
.collect(Collectors.groupingBy(item -> new GroupedItem(item.getId(), item.getCount(), item.getTag())));
|
||||||
Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
|
Set<ItemData> optionSet = new HashSet<>(groupedByIds.size());
|
||||||
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
|
for (Map.Entry<GroupedItem, List<ItemData>> entry : groupedByIds.entrySet()) {
|
||||||
|
@ -136,7 +136,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator<ServerDeclare
|
||||||
ItemData[] translatedItems = new ItemData[ingredients.length];
|
ItemData[] translatedItems = new ItemData[ingredients.length];
|
||||||
for (int i = 0; i < ingredients.length; i++) {
|
for (int i = 0; i < ingredients.length; i++) {
|
||||||
if (ingredients[i].getOptions().length > 0) {
|
if (ingredients[i].getOptions().length > 0) {
|
||||||
translatedItems[i] = ItemTranslator.translateToBedrock(ingredients[i].getOptions()[0]);
|
translatedItems[i] = ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0]);
|
||||||
} else {
|
} else {
|
||||||
translatedItems[i] = ItemData.AIR;
|
translatedItems[i] = ItemData.AIR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator<ServerEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
LivingEntity livingEntity = (LivingEntity) entity;
|
LivingEntity livingEntity = (LivingEntity) entity;
|
||||||
ItemData item = ItemTranslator.translateToBedrock(packet.getItem());
|
ItemData item = ItemTranslator.translateToBedrock(session, packet.getItem());
|
||||||
switch (packet.getSlot()) {
|
switch (packet.getSlot()) {
|
||||||
case HELMET:
|
case HELMET:
|
||||||
livingEntity.setHelmet(item);
|
livingEntity.setHelmet(item);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.entity.player;
|
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.client.world.ClientTeleportConfirmPacket;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
@ -95,20 +96,35 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator<Serve
|
||||||
|
|
||||||
session.setSpawned(true);
|
session.setSpawned(true);
|
||||||
|
|
||||||
if (!packet.getRelative().isEmpty()) {
|
// Ignore certain move correction packets for smoother movement
|
||||||
session.setTeleportCache(new TeleportCache(packet.getX(), packet.getY(), packet.getZ(), packet.getTeleportId()));
|
// These are never relative
|
||||||
entity.moveRelative(session, packet.getX(), packet.getY() + EntityType.PLAYER.getOffset() + 0.1f, packet.getZ(), packet.getYaw(), packet.getPitch(), true);
|
if (packet.getRelative().isEmpty()) {
|
||||||
} else {
|
|
||||||
double xDis = Math.abs(entity.getPosition().getX() - packet.getX());
|
double xDis = Math.abs(entity.getPosition().getX() - packet.getX());
|
||||||
double yDis = entity.getPosition().getY() - packet.getY();
|
double yDis = entity.getPosition().getY() - packet.getY();
|
||||||
double zDis = Math.abs(entity.getPosition().getZ() - packet.getZ());
|
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) {
|
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()));
|
// Fake confirm the teleport but don't send it to the client
|
||||||
entity.moveAbsolute(session, Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), true, true);
|
|
||||||
} else {
|
|
||||||
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
|
ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(packet.getTeleportId());
|
||||||
session.sendDownstreamPacket(teleportConfirmPacket);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
package org.geysermc.connector.network.translators.java.window;
|
package org.geysermc.connector.network.translators.java.window;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerCloseWindowPacket;
|
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.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
@ -37,9 +36,7 @@ public class JavaCloseWindowTranslator extends PacketTranslator<ServerCloseWindo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
|
public void translate(ServerCloseWindowPacket packet, GeyserSession session) {
|
||||||
ContainerClosePacket closePacket = new ContainerClosePacket();
|
InventoryUtils.closeWindow(session, packet.getWindowId());
|
||||||
closePacket.setWindowId((byte)packet.getWindowId());
|
|
||||||
session.sendUpstreamPacket(closePacket);
|
|
||||||
InventoryUtils.closeInventory(session, packet.getWindowId());
|
InventoryUtils.closeInventory(session, packet.getWindowId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,6 @@ import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
import org.geysermc.connector.network.translators.inventory.InventoryTranslator;
|
||||||
import org.geysermc.connector.utils.InventoryUtils;
|
import org.geysermc.connector.utils.InventoryUtils;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
@Translator(packet = ServerOpenWindowPacket.class)
|
@Translator(packet = ServerOpenWindowPacket.class)
|
||||||
public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowPacket> {
|
public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowPacket> {
|
||||||
|
|
||||||
|
@ -52,10 +50,8 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
|
||||||
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
Inventory openInventory = session.getInventoryCache().getOpenInventory();
|
||||||
if (newTranslator == null) {
|
if (newTranslator == null) {
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
ContainerClosePacket closePacket = new ContainerClosePacket();
|
InventoryUtils.closeWindow(session, openInventory.getId());
|
||||||
closePacket.setWindowId((byte)openInventory.getId());
|
InventoryUtils.closeInventory(session, openInventory.getId());
|
||||||
session.sendUpstreamPacket(closePacket);
|
|
||||||
InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType()).closeInventory(session, openInventory);
|
|
||||||
}
|
}
|
||||||
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
|
ClientCloseWindowPacket closeWindowPacket = new ClientCloseWindowPacket(packet.getWindowId());
|
||||||
session.sendDownstreamPacket(closeWindowPacket);
|
session.sendDownstreamPacket(closeWindowPacket);
|
||||||
|
@ -80,9 +76,8 @@ public class JavaOpenWindowTranslator extends PacketTranslator<ServerOpenWindowP
|
||||||
if (openInventory != null) {
|
if (openInventory != null) {
|
||||||
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
|
InventoryTranslator openTranslator = InventoryTranslator.INVENTORY_TRANSLATORS.get(openInventory.getWindowType());
|
||||||
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
|
if (!openTranslator.getClass().equals(newTranslator.getClass())) {
|
||||||
|
InventoryUtils.closeWindow(session, openInventory.getId());
|
||||||
InventoryUtils.closeInventory(session, openInventory.getId());
|
InventoryUtils.closeInventory(session, openInventory.getId());
|
||||||
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> InventoryUtils.openInventory(session, newInventory), 500, TimeUnit.MILLISECONDS);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,6 @@ public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket>
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
|
public void translate(ServerSetSlotPacket packet, GeyserSession session) {
|
||||||
if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
|
if (packet.getWindowId() == 255 && packet.getSlot() == -1) { //cursor
|
||||||
if (Objects.equals(session.getInventory().getCursor(), packet.getItem()))
|
|
||||||
return;
|
|
||||||
if (session.getCraftSlot() != 0)
|
if (session.getCraftSlot() != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -46,14 +46,17 @@ public class JavaExplosionTranslator extends PacketTranslator<ServerExplosionPac
|
||||||
public void translate(ServerExplosionPacket packet, GeyserSession session) {
|
public void translate(ServerExplosionPacket packet, GeyserSession session) {
|
||||||
for (ExplodedBlockRecord record : packet.getExploded()) {
|
for (ExplodedBlockRecord record : packet.getExploded()) {
|
||||||
Vector3f pos = Vector3f.from(packet.getX() + record.getX(), packet.getY() + record.getY(), packet.getZ() + record.getZ());
|
Vector3f pos = Vector3f.from(packet.getX() + record.getX(), packet.getY() + record.getY(), packet.getZ() + record.getZ());
|
||||||
// Since bedrock does not play an explosion sound and particles sound, we have to manually do so
|
|
||||||
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
|
||||||
levelEventPacket.setType(LevelEventType.PARTICLE_LARGE_EXPLOSION);
|
|
||||||
levelEventPacket.setData(0);
|
|
||||||
levelEventPacket.setPosition(pos.toFloat());
|
|
||||||
session.sendUpstreamPacket(levelEventPacket);
|
|
||||||
ChunkUtils.updateBlock(session, BlockTranslator.AIR, pos.toInt());
|
ChunkUtils.updateBlock(session, BlockTranslator.AIR, pos.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ());
|
||||||
|
// Since bedrock does not play an explosion sound and particles sound, we have to manually do so
|
||||||
|
LevelEventPacket levelEventPacket = new LevelEventPacket();
|
||||||
|
levelEventPacket.setType(packet.getRadius() >= 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 levelSoundEventPacket = new LevelSoundEventPacket();
|
||||||
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
levelSoundEventPacket.setRelativeVolumeDisabled(false);
|
||||||
levelSoundEventPacket.setBabySound(false);
|
levelSoundEventPacket.setBabySound(false);
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator<ServerSpawnPar
|
||||||
break;
|
break;
|
||||||
case ITEM:
|
case ITEM:
|
||||||
ItemStack javaItem = ((ItemParticleData)packet.getParticle().getData()).getItemStack();
|
ItemStack javaItem = ((ItemParticleData)packet.getParticle().getData()).getItemStack();
|
||||||
ItemData bedrockItem = ItemTranslator.translateToBedrock(javaItem);
|
ItemData bedrockItem = ItemTranslator.translateToBedrock(session, javaItem);
|
||||||
int id = bedrockItem.getId();
|
int id = bedrockItem.getId();
|
||||||
short damage = bedrockItem.getDamage();
|
short damage = bedrockItem.getDamage();
|
||||||
particle.setType(LevelEventType.PARTICLE_ITEM_BREAK);
|
particle.setType(LevelEventType.PARTICLE_ITEM_BREAK);
|
||||||
|
|
|
@ -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<ServerTradeListPacket> {
|
||||||
|
|
||||||
|
@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<CompoundTag> 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<CompoundTag> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,11 @@ public class BlockTranslator {
|
||||||
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
|
public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet();
|
||||||
public static final int JAVA_RUNTIME_COBWEB_ID;
|
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;
|
private static final int BLOCK_STATE_VERSION = 17760256;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -108,6 +113,9 @@ public class BlockTranslator {
|
||||||
int javaRuntimeId = -1;
|
int javaRuntimeId = -1;
|
||||||
int bedrockRuntimeId = 0;
|
int bedrockRuntimeId = 0;
|
||||||
int cobwebRuntimeId = -1;
|
int cobwebRuntimeId = -1;
|
||||||
|
int furnaceRuntimeId = -1;
|
||||||
|
int furnaceLitRuntimeId = -1;
|
||||||
|
int spawnerRuntimeId = -1;
|
||||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = blocks.fields();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
javaRuntimeId++;
|
||||||
|
@ -186,6 +194,18 @@ public class BlockTranslator {
|
||||||
}
|
}
|
||||||
JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId);
|
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++;
|
bedrockRuntimeId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +214,21 @@ public class BlockTranslator {
|
||||||
}
|
}
|
||||||
JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId;
|
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) {
|
if (waterRuntimeId == -1) {
|
||||||
throw new AssertionError("Unable to find water in palette");
|
throw new AssertionError("Unable to find water in palette");
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,19 @@ public abstract class BlockEntityTranslator {
|
||||||
public static final Map<String, BlockEntityTranslator> BLOCK_ENTITY_TRANSLATORS = new HashMap<>();
|
public static final Map<String, BlockEntityTranslator> BLOCK_ENTITY_TRANSLATORS = new HashMap<>();
|
||||||
public static ObjectArrayList<RequiresBlockState> REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>();
|
public static ObjectArrayList<RequiresBlockState> 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<String, String> BLOCK_ENTITY_TRANSLATIONS = new HashMap<String, String>() {
|
||||||
|
{
|
||||||
|
// 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() {
|
protected BlockEntityTranslator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,7 @@ import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler;
|
||||||
import com.github.steveice10.packetlib.Client;
|
import com.github.steveice10.packetlib.Client;
|
||||||
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||||
import org.geysermc.common.ping.GeyserPingInfo;
|
import org.geysermc.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.connector.GeyserConfiguration;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
|
@ -12,29 +12,24 @@ public class BlockEntityUtils {
|
||||||
|
|
||||||
public static String getBedrockBlockEntityId(String id) {
|
public static String getBedrockBlockEntityId(String id) {
|
||||||
// These are the only exceptions when it comes to block entity ids
|
// These are the only exceptions when it comes to block entity ids
|
||||||
if (id.contains("piston_head"))
|
if (BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.containsKey(id)) {
|
||||||
return "PistonArm";
|
return BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id);
|
||||||
|
|
||||||
if (id.contains("trapped_chest"))
|
|
||||||
return "Chest";
|
|
||||||
|
|
||||||
if (id.contains("EnderChest"))
|
|
||||||
return "EnderChest";
|
|
||||||
|
|
||||||
if (id.contains("enchanting_table")) {
|
|
||||||
return "EnchantTable";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
id = id.toLowerCase()
|
id = id.replace("minecraft:", "")
|
||||||
.replace("minecraft:", "")
|
|
||||||
.replace("_", " ");
|
.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++) {
|
for (int i = 0; i < words.length; i++) {
|
||||||
words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase();
|
words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
id = String.join(" ", words);
|
return String.join("", words);
|
||||||
return id.replace(" ", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockEntityTranslator getBlockEntityTranslator(String name) {
|
public static BlockEntityTranslator getBlockEntityTranslator(String name) {
|
||||||
|
|
|
@ -30,6 +30,8 @@ import com.github.steveice10.mc.protocol.data.game.chunk.Column;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position;
|
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.mc.protocol.data.game.world.block.BlockState;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
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.Vector2i;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.nbt.CompoundTagBuilder;
|
import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
|
@ -137,11 +139,23 @@ public class ChunkUtils {
|
||||||
while (i < blockEntities.length) {
|
while (i < blockEntities.length) {
|
||||||
CompoundTag tag = blockEntities[i];
|
CompoundTag tag = blockEntities[i];
|
||||||
String tagName;
|
String tagName;
|
||||||
if (!tag.contains("id")) {
|
if (tag.contains("id")) {
|
||||||
GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue());
|
|
||||||
tagName = "Empty";
|
|
||||||
} else {
|
|
||||||
tagName = (String) tag.get("id").getValue();
|
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);
|
String id = BlockEntityUtils.getBedrockBlockEntityId(tagName);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.nukkitx.nbt.CompoundTagBuilder;
|
||||||
import com.nukkitx.nbt.tag.StringTag;
|
import com.nukkitx.nbt.tag.StringTag;
|
||||||
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.ContainerId;
|
||||||
import com.nukkitx.protocol.bedrock.data.ItemData;
|
import com.nukkitx.protocol.bedrock.data.ItemData;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket;
|
||||||
import org.geysermc.common.ChatColor;
|
import org.geysermc.common.ChatColor;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
@ -53,12 +54,18 @@ public class InventoryUtils {
|
||||||
if (translator != null) {
|
if (translator != null) {
|
||||||
session.getInventoryCache().setOpenInventory(inventory);
|
session.getInventoryCache().setOpenInventory(inventory);
|
||||||
translator.prepareInventory(session, 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
|
//TODO: find better way to handle double chest delay
|
||||||
if (translator instanceof DoubleChestInventoryTranslator) {
|
if (translator instanceof DoubleChestInventoryTranslator) {
|
||||||
|
delay = Math.max(delay, 200);
|
||||||
|
}
|
||||||
|
if (delay > 0) {
|
||||||
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> {
|
GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> {
|
||||||
translator.openInventory(session, inventory);
|
translator.openInventory(session, inventory);
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
}, 200, TimeUnit.MILLISECONDS);
|
}, delay, TimeUnit.MILLISECONDS);
|
||||||
} else {
|
} else {
|
||||||
translator.openInventory(session, inventory);
|
translator.openInventory(session, inventory);
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
|
@ -69,26 +76,41 @@ public class InventoryUtils {
|
||||||
public static void closeInventory(GeyserSession session, int windowId) {
|
public static void closeInventory(GeyserSession session, int windowId) {
|
||||||
if (windowId != 0) {
|
if (windowId != 0) {
|
||||||
Inventory inventory = session.getInventoryCache().getInventories().get(windowId);
|
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());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
translator.closeInventory(session, inventory);
|
translator.closeInventory(session, inventory);
|
||||||
session.getInventoryCache().uncacheInventory(windowId);
|
|
||||||
session.getInventoryCache().setOpenInventory(null);
|
session.getInventoryCache().setOpenInventory(null);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Inventory inventory = session.getInventory();
|
Inventory inventory = session.getInventory();
|
||||||
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType());
|
||||||
translator.updateInventory(session, inventory);
|
translator.updateInventory(session, inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setCraftSlot(0);
|
session.setCraftSlot(0);
|
||||||
session.getInventory().setCursor(null);
|
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) {
|
public static void updateCursor(GeyserSession session) {
|
||||||
InventorySlotPacket cursorPacket = new InventorySlotPacket();
|
InventorySlotPacket cursorPacket = new InventorySlotPacket();
|
||||||
cursorPacket.setContainerId(ContainerId.CURSOR);
|
cursorPacket.setContainerId(ContainerId.CURSOR);
|
||||||
cursorPacket.setSlot(0);
|
cursorPacket.setSlot(0);
|
||||||
cursorPacket.setItem(ItemTranslator.translateToBedrock(session.getInventory().getCursor()));
|
cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()));
|
||||||
session.sendUpstreamPacket(cursorPacket);
|
session.sendUpstreamPacket(cursorPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ package org.geysermc.connector.utils;
|
||||||
|
|
||||||
public class MathUtils {
|
public class MathUtils {
|
||||||
|
|
||||||
|
public static final double SQRT_OF_TWO = Math.sqrt(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round the given float to the next whole number
|
* Round the given float to the next whole number
|
||||||
*
|
*
|
||||||
|
@ -37,4 +39,19 @@ public class MathUtils {
|
||||||
int truncated = (int) floatNumber;
|
int truncated = (int) floatNumber;
|
||||||
return floatNumber > truncated ? truncated + 1 : truncated;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
10
pom.xml
10
pom.xml
|
@ -38,14 +38,8 @@
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>CodeMC-repo</id>
|
<id>jitpack.io</id>
|
||||||
<url>https://repo.codemc.org/repository/maven-public</url>
|
<url>https://jitpack.io</url>
|
||||||
<releases>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</releases>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>nukkitx-release-repo</id>
|
<id>nukkitx-release-repo</id>
|
||||||
|
|
Loading…
Reference in a new issue