forked from GeyserMC/Geyser
Scoreboard improvements (#1166)
* Added a way to check if debug logging is enabled * Improved scoreboard performance * Include Teams in pps and return pending pps instead when higher then pps Some servers have a huge amount of score packets when the player logs in, but before this commit, only after the first high pps (packets per second) the ScoreboardUpdater will be used (after pending packets per second have been moved to packets per second). But this commit fixes that the ScoreboardUpdater can be used on the second that the pps is getting high. * Fixed team pre + suffix "null" issue and added threshold config option Fixed team pre + suffix "null" issue. When the prefix and/or suffix of a Team is null, "null" will be returned instead of null (Due to the way that MCProtocolLib is made and designed). This is fixed by simply checking if the prefix and/or suffix equal "null" and if that is the case, replace it with "". Added threshold option. Gave the person who is running Geyser an option to specify the first Scoreboard packets per second threshold to further improve performance by lowering the setting or decrease performance by relaxing the setting a bit. The value can't be higher then 250 (the second threshold), because it'll always choose the lowest threshold. * Forgot to bump config version * Small changes * Reverted version bump, changed Sponge config, changed FloodgateKeyLoader Reverted version bump Camotoy said that you only need to bump the config version if the change is breaking, the config version bump has been reverted. Changed Sponge config The Sponge config has been modified to look like the other platform configurations. Changed FloodgateKeyLoader * Changed default-locale and (remote) address as requested by Camotoy * Reduce bandwidth and a few final tweaks * Made the scoreboard-packet-threshold a bit higher due to improvements
This commit is contained in:
parent
7cbfdcf521
commit
1c84993853
29 changed files with 549 additions and 616 deletions
|
@ -29,27 +29,22 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import lombok.Getter;
|
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 org.geysermc.connector.FloodgateKeyLoader;
|
import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
|
public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Path floodgateKey;
|
private Path floodgateKeyPath;
|
||||||
|
|
||||||
public void loadFloodgate(GeyserBungeePlugin plugin, Configuration configuration) {
|
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(plugin.getDataFolder().toString(), configuration.getString("floodgate-key-file"), "public-key.pem"), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
|
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||||
}
|
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||||
|
|
||||||
@Override
|
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||||
public Path getFloodgateKeyFile() {
|
|
||||||
return floodgateKey;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,19 +25,21 @@
|
||||||
|
|
||||||
package org.geysermc.platform.bungeecord;
|
package org.geysermc.platform.bungeecord;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class GeyserBungeeLogger implements GeyserLogger {
|
public class GeyserBungeeLogger implements GeyserLogger {
|
||||||
|
private final Logger logger;
|
||||||
|
@Getter @Setter
|
||||||
|
private boolean debug;
|
||||||
|
|
||||||
private Logger logger;
|
public GeyserBungeeLogger(Logger logger, boolean debug) {
|
||||||
private boolean debugMode;
|
|
||||||
|
|
||||||
public GeyserBungeeLogger(Logger logger, boolean debugMode) {
|
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.debugMode = debugMode;
|
this.debug = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,12 +74,8 @@ public class GeyserBungeeLogger implements GeyserLogger {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void debug(String message) {
|
public void debug(String message) {
|
||||||
if (debugMode)
|
if (debug) {
|
||||||
info(message);
|
info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDebug(boolean debug) {
|
|
||||||
debugMode = debug;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@ package org.geysermc.platform.bungeecord;
|
||||||
|
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
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.ConfigurationProvider;
|
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
|
||||||
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;
|
||||||
|
@ -64,13 +61,11 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
|
|
||||||
Configuration configuration = null;
|
|
||||||
try {
|
try {
|
||||||
if (!getDataFolder().exists())
|
if (!getDataFolder().exists())
|
||||||
getDataFolder().mkdir();
|
getDataFolder().mkdir();
|
||||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
|
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);
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
|
||||||
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml"));
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
|
getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
@ -108,7 +103,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
|
||||||
geyserConfig.getRemote().setAuthType("floodgate");
|
geyserConfig.getRemote().setAuthType("floodgate");
|
||||||
}
|
}
|
||||||
|
|
||||||
geyserConfig.loadFloodgate(this, configuration);
|
geyserConfig.loadFloodgate(this);
|
||||||
|
|
||||||
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
|
this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.platform.spigot;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
@ -35,26 +34,19 @@ import org.geysermc.connector.FloodgateKeyLoader;
|
||||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class GeyserSpigotConfiguration extends GeyserJacksonConfiguration {
|
public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
|
||||||
private String floodgateKeyFile;
|
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Path floodgateKey;
|
private Path floodgateKeyPath;
|
||||||
|
|
||||||
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(plugin.getDataFolder().toString(), plugin.getConfig().getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null);
|
Path geyserDataFolder = plugin.getDataFolder().toPath();
|
||||||
}
|
Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null;
|
||||||
|
|
||||||
@Override
|
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger());
|
||||||
public Path getFloodgateKeyFile() {
|
|
||||||
return floodgateKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
package org.geysermc.platform.spigot;
|
package org.geysermc.platform.spigot;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
@ -34,9 +35,9 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpigotLogger implements GeyserLogger {
|
public class GeyserSpigotLogger implements GeyserLogger {
|
||||||
|
private final Logger logger;
|
||||||
private Logger logger;
|
@Getter @Setter
|
||||||
private boolean debugMode;
|
private boolean debug;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void severe(String message) {
|
public void severe(String message) {
|
||||||
|
@ -70,12 +71,8 @@ public class GeyserSpigotLogger implements GeyserLogger {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void debug(String message) {
|
public void debug(String message) {
|
||||||
if (debugMode)
|
if (debug) {
|
||||||
info(message);
|
info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDebug(boolean debug) {
|
|
||||||
debugMode = debug;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,268 +25,13 @@
|
||||||
|
|
||||||
package org.geysermc.platform.sponge;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
|
||||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class GeyserSpongeConfiguration implements GeyserConfiguration {
|
|
||||||
|
|
||||||
private File dataFolder;
|
|
||||||
private ConfigurationNode node;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the config was originally 'auto' before the values changed
|
|
||||||
*/
|
|
||||||
private boolean autoconfiguredRemote = false;
|
|
||||||
|
|
||||||
private SpongeBedrockConfiguration bedrockConfig;
|
|
||||||
private SpongeRemoteConfiguration remoteConfig;
|
|
||||||
private SpongeMetricsInfo metricsInfo;
|
|
||||||
|
|
||||||
private Map<String, SpongeUserAuthenticationInfo> userAuthInfo = new HashMap<>();
|
|
||||||
|
|
||||||
public GeyserSpongeConfiguration(File dataFolder, ConfigurationNode node) {
|
|
||||||
this.dataFolder = dataFolder;
|
|
||||||
this.node = node;
|
|
||||||
|
|
||||||
this.bedrockConfig = new SpongeBedrockConfiguration(node.getNode("bedrock"));
|
|
||||||
this.remoteConfig = new SpongeRemoteConfiguration(node.getNode("remote"));
|
|
||||||
this.metricsInfo = new SpongeMetricsInfo();
|
|
||||||
|
|
||||||
if (node.getNode("userAuths").getValue() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
List<String> userAuths = new ArrayList<String>(((LinkedHashMap)node.getNode("userAuths").getValue()).keySet());
|
|
||||||
for (String key : userAuths) {
|
|
||||||
userAuthInfo.put(key, new SpongeUserAuthenticationInfo(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoconfiguredRemote(boolean autoconfiguredRemote) {
|
|
||||||
this.autoconfiguredRemote = autoconfiguredRemote;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public final class GeyserSpongeConfiguration extends GeyserJacksonConfiguration {
|
||||||
@Override
|
@Override
|
||||||
public SpongeBedrockConfiguration getBedrock() {
|
public Path getFloodgateKeyPath() {
|
||||||
return bedrockConfig;
|
return null; //floodgate isn't available for Sponge
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SpongeRemoteConfiguration getRemote() {
|
|
||||||
return remoteConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, SpongeUserAuthenticationInfo> getUserAuths() {
|
|
||||||
return userAuthInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCommandSuggestions() {
|
|
||||||
return node.getNode("command-suggestions").getBoolean(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPassthroughMotd() {
|
|
||||||
return node.getNode("passthrough-motd").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPassthroughProtocolName() {
|
|
||||||
return node.getNode("passthrough-protocol-name").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPassthroughPlayerCounts() {
|
|
||||||
return node.getNode("passthrough-player-counts").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLegacyPingPassthrough() {
|
|
||||||
return node.getNode("legacy-ping-passthrough").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPingPassthroughInterval() {
|
|
||||||
return node.getNode("ping-passthrough-interval").getInt(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxPlayers() {
|
|
||||||
return node.getNode("max-players").getInt(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDebugMode() {
|
|
||||||
return node.getNode("debug-mode").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getGeneralThreadPool() {
|
|
||||||
return node.getNode("genereal-thread-pool").getInt(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAllowThirdPartyCapes() {
|
|
||||||
return node.getNode("allow-third-party-capes").getBoolean(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAllowThirdPartyEars() {
|
|
||||||
return node.getNode("allow-third-party-ears").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isShowCooldown() {
|
|
||||||
return node.getNode("show-cooldown").getBoolean(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDefaultLocale() {
|
|
||||||
return node.getNode("default-locale").getString("en_us");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Path getFloodgateKeyFile() {
|
|
||||||
return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCacheChunks() {
|
|
||||||
return node.getNode("cache-chunks").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCacheImages() {
|
|
||||||
return node.getNode("cache-skins").getInt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAboveBedrockNetherBuilding() {
|
|
||||||
return node.getNode("above-bedrock-nether-building").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SpongeMetricsInfo getMetrics() {
|
|
||||||
return metricsInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SpongeBedrockConfiguration implements IBedrockConfiguration {
|
|
||||||
|
|
||||||
private ConfigurationNode node;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAddress() {
|
|
||||||
return node.getNode("address").getString("0.0.0.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPort() {
|
|
||||||
return node.getNode("port").getInt(19132);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCloneRemotePort() {
|
|
||||||
return node.getNode("clone-remote-port").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMotd1() {
|
|
||||||
return node.getNode("motd1").getString("GeyserMC");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMotd2() {
|
|
||||||
return node.getNode("motd2").getString("GeyserMC");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getServerName() {
|
|
||||||
return node.getNode("server-name").getString("Geyser");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SpongeRemoteConfiguration implements IRemoteConfiguration {
|
|
||||||
|
|
||||||
private ConfigurationNode node;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAddress() {
|
|
||||||
return node.getNode("address").getString("127.0.0.1");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAddress(String address) {
|
|
||||||
node.getNode("address").setValue(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPort() {
|
|
||||||
return node.getNode("port").getInt(25565);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPort(int port) {
|
|
||||||
node.getNode("port").setValue(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthType() {
|
|
||||||
return node.getNode("auth-type").getString("online");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SpongeUserAuthenticationInfo implements IUserAuthenticationInfo {
|
|
||||||
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
public SpongeUserAuthenticationInfo(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getEmail() {
|
|
||||||
return node.getNode("userAuths").getNode(key).getNode("email").getString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return node.getNode("userAuths").getNode(key).getNode("password").getString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SpongeMetricsInfo implements IMetricsInfo {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return node.getNode("metrics").getNode("enabled").getBoolean(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUniqueId() {
|
|
||||||
return node.getNode("metrics").getNode("uuid").getString("generateduuid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnableProxyConnections() {
|
|
||||||
return node.getNode("enable-proxy-connections").getBoolean(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMtu() {
|
|
||||||
return node.getNode("mtu").getInt(1400);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getConfigVersion() {
|
|
||||||
return node.getNode("config-version").getInt(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,16 @@
|
||||||
package org.geysermc.platform.sponge;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserSpongeLogger implements GeyserLogger {
|
public class GeyserSpongeLogger implements GeyserLogger {
|
||||||
|
private final Logger logger;
|
||||||
private Logger logger;
|
@Getter @Setter
|
||||||
private boolean debugMode;
|
private boolean debug;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void severe(String message) {
|
public void severe(String message) {
|
||||||
|
@ -68,12 +69,8 @@ public class GeyserSpongeLogger implements GeyserLogger {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void debug(String message) {
|
public void debug(String message) {
|
||||||
if (debugMode)
|
if (debug) {
|
||||||
info(message);
|
info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDebug(boolean debugMode) {
|
|
||||||
this.debugMode = debugMode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
package org.geysermc.platform.sponge;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
|
||||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
|
||||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
|
||||||
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;
|
||||||
|
@ -85,20 +82,14 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationLoader loader = YAMLConfigurationLoader.builder().setPath(configFile.toPath()).build();
|
|
||||||
ConfigurationNode config;
|
|
||||||
try {
|
try {
|
||||||
config = loader.load();
|
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class);
|
||||||
this.geyserConfig = new GeyserSpongeConfiguration(configDir, config);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
|
logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"));
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationNode serverIP = config.getNode("remote").getNode("address");
|
|
||||||
ConfigurationNode serverPort = config.getNode("remote").getNode("port");
|
|
||||||
|
|
||||||
if (Sponge.getServer().getBoundAddress().isPresent()) {
|
if (Sponge.getServer().getBoundAddress().isPresent()) {
|
||||||
InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get();
|
InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get();
|
||||||
|
|
||||||
|
@ -106,13 +97,12 @@ public class GeyserSpongePlugin implements GeyserBootstrap {
|
||||||
// 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 (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
|
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
|
||||||
this.geyserConfig.setAutoconfiguredRemote(true);
|
this.geyserConfig.setAutoconfiguredRemote(true);
|
||||||
serverPort.setValue(javaAddr.getPort());
|
geyserConfig.getRemote().setPort(javaAddr.getPort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigurationNode bedrockPort = config.getNode("bedrock").getNode("port");
|
|
||||||
if (geyserConfig.getBedrock().isCloneRemotePort()){
|
if (geyserConfig.getBedrock().isCloneRemotePort()){
|
||||||
bedrockPort.setValue(serverPort.getValue());
|
geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode());
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
package org.geysermc.platform.standalone;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
|
|
||||||
|
@ -35,13 +34,9 @@ import java.nio.file.Paths;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
|
public final class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
|
||||||
private String floodgateKeyFile;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path getFloodgateKeyFile() {
|
public Path getFloodgateKeyPath() {
|
||||||
return Paths.get(floodgateKeyFile);
|
return Paths.get(getFloodgateKeyFile());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,18 +26,16 @@
|
||||||
package org.geysermc.platform.standalone;
|
package org.geysermc.platform.standalone;
|
||||||
|
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||||
|
|
||||||
import org.apache.logging.log4j.Level;
|
import org.apache.logging.log4j.Level;
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
import org.geysermc.connector.common.ChatColor;
|
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.geysermc.connector.command.CommandSender;
|
import org.geysermc.connector.command.CommandSender;
|
||||||
|
import org.geysermc.connector.common.ChatColor;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements org.geysermc.connector.GeyserLogger, CommandSender {
|
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, CommandSender {
|
||||||
|
|
||||||
private boolean colored = true;
|
private boolean colored = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,10 +97,6 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements org
|
||||||
Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO);
|
Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for setting debug mode in GUI mode
|
|
||||||
* @return if debug is enabled
|
|
||||||
*/
|
|
||||||
public boolean isDebug() {
|
public boolean isDebug() {
|
||||||
return log.isDebugEnabled();
|
return log.isDebugEnabled();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.platform.velocity;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
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;
|
||||||
|
@ -37,25 +36,15 @@ 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.Optional;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
|
public final class GeyserVelocityConfiguration extends GeyserJacksonConfiguration {
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
|
||||||
private String floodgateKeyFile;
|
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Path floodgateKey;
|
private Path floodgateKeyPath;
|
||||||
|
|
||||||
@Override
|
|
||||||
public Path getFloodgateKeyFile() {
|
|
||||||
return floodgateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) {
|
||||||
Optional<PluginContainer> floodgate = proxyServer.getPluginManager().getPlugin("floodgate");
|
PluginContainer floodgate = proxyServer.getPluginManager().getPlugin("floodgate").orElse(null);
|
||||||
floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/")));
|
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, Paths.get("plugins/floodgate/"), dataFolder.toPath(), plugin.getGeyserLogger());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,15 +26,16 @@
|
||||||
package org.geysermc.platform.velocity;
|
package org.geysermc.platform.velocity;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GeyserVelocityLogger implements GeyserLogger {
|
public class GeyserVelocityLogger implements GeyserLogger {
|
||||||
|
private final Logger logger;
|
||||||
private Logger logger;
|
@Getter @Setter
|
||||||
private boolean debugMode;
|
private boolean debug;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void severe(String message) {
|
public void severe(String message) {
|
||||||
|
@ -68,12 +69,8 @@ public class GeyserVelocityLogger implements GeyserLogger {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void debug(String message) {
|
public void debug(String message) {
|
||||||
if (debugMode)
|
if (debug) {
|
||||||
info(message);
|
info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDebug(boolean debugMode) {
|
|
||||||
this.debugMode = debugMode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,17 +25,19 @@
|
||||||
|
|
||||||
package org.geysermc.connector;
|
package org.geysermc.connector;
|
||||||
|
|
||||||
|
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
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;
|
||||||
|
|
||||||
public class FloodgateKeyLoader {
|
public class FloodgateKeyLoader {
|
||||||
public static Path getKey(GeyserLogger logger, GeyserConfiguration config, Path floodgateKey, Object floodgate, Path floodgateFolder) {
|
public static Path getKeyPath(GeyserJacksonConfiguration config, Object floodgate, Path floodgateDataFolder, Path geyserDataFolder, GeyserLogger logger) {
|
||||||
|
Path floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile());
|
||||||
|
|
||||||
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) {
|
||||||
if (floodgate != null) {
|
if (floodgate != null) {
|
||||||
Path autoKey = floodgateFolder.resolve("public-key.pem");
|
Path autoKey = floodgateDataFolder.resolve("public-key.pem");
|
||||||
if (Files.exists(autoKey)) {
|
if (Files.exists(autoKey)) {
|
||||||
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
|
logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded"));
|
||||||
floodgateKey = autoKey;
|
floodgateKey = autoKey;
|
||||||
|
|
|
@ -84,4 +84,9 @@ public interface GeyserLogger {
|
||||||
* @param debug if the logger should print debug messages
|
* @param debug if the logger should print debug messages
|
||||||
*/
|
*/
|
||||||
void setDebug(boolean debug);
|
void setDebug(boolean debug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If debug is enabled for this logger
|
||||||
|
*/
|
||||||
|
boolean isDebug();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.connector.configuration;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.geysermc.connector.GeyserLogger;
|
import org.geysermc.connector.GeyserLogger;
|
||||||
|
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -74,7 +73,7 @@ public interface GeyserConfiguration {
|
||||||
|
|
||||||
String getDefaultLocale();
|
String getDefaultLocale();
|
||||||
|
|
||||||
Path getFloodgateKeyFile();
|
Path getFloodgateKeyPath();
|
||||||
|
|
||||||
boolean isAboveBedrockNetherBuilding();
|
boolean isAboveBedrockNetherBuilding();
|
||||||
|
|
||||||
|
@ -125,6 +124,8 @@ public interface GeyserConfiguration {
|
||||||
String getUniqueId();
|
String getUniqueId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getScoreboardPacketThreshold();
|
||||||
|
|
||||||
// if u have offline mode enabled pls be safe
|
// if u have offline mode enabled pls be safe
|
||||||
boolean isEnableProxyConnections();
|
boolean isEnableProxyConnections();
|
||||||
|
|
||||||
|
|
|
@ -49,76 +49,75 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
private RemoteConfiguration remote;
|
private RemoteConfiguration remote;
|
||||||
|
|
||||||
@JsonProperty("floodgate-key-file")
|
@JsonProperty("floodgate-key-file")
|
||||||
private String floodgateKeyFile;
|
private String floodgateKeyFile = "public-key.pem";
|
||||||
|
|
||||||
public abstract Path getFloodgateKeyFile();
|
public abstract Path getFloodgateKeyPath();
|
||||||
|
|
||||||
private Map<String, UserAuthenticationInfo> userAuths;
|
private Map<String, UserAuthenticationInfo> userAuths;
|
||||||
|
|
||||||
@JsonProperty("command-suggestions")
|
@JsonProperty("command-suggestions")
|
||||||
private boolean commandSuggestions;
|
private boolean commandSuggestions = true;
|
||||||
|
|
||||||
@JsonProperty("passthrough-motd")
|
@JsonProperty("passthrough-motd")
|
||||||
private boolean isPassthroughMotd;
|
private boolean isPassthroughMotd = false;
|
||||||
|
|
||||||
@JsonProperty("passthrough-player-counts")
|
@JsonProperty("passthrough-player-counts")
|
||||||
private boolean isPassthroughPlayerCounts;
|
private boolean isPassthroughPlayerCounts = false;
|
||||||
|
|
||||||
@JsonProperty("passthrough-protocol-name")
|
@JsonProperty("passthrough-protocol-name")
|
||||||
private boolean isPassthroughProtocolName;
|
private boolean isPassthroughProtocolName = false;
|
||||||
|
|
||||||
@JsonProperty("legacy-ping-passthrough")
|
@JsonProperty("legacy-ping-passthrough")
|
||||||
private boolean isLegacyPingPassthrough;
|
private boolean isLegacyPingPassthrough = false;
|
||||||
|
|
||||||
@JsonProperty("ping-passthrough-interval")
|
@JsonProperty("ping-passthrough-interval")
|
||||||
private int pingPassthroughInterval;
|
private int pingPassthroughInterval = 3;
|
||||||
|
|
||||||
@JsonProperty("max-players")
|
@JsonProperty("max-players")
|
||||||
private int maxPlayers;
|
private int maxPlayers = 100;
|
||||||
|
|
||||||
@JsonProperty("debug-mode")
|
@JsonProperty("debug-mode")
|
||||||
private boolean debugMode;
|
private boolean debugMode = false;
|
||||||
|
|
||||||
@JsonProperty("general-thread-pool")
|
@JsonProperty("general-thread-pool")
|
||||||
private int generalThreadPool;
|
private int generalThreadPool = 32;
|
||||||
|
|
||||||
@JsonProperty("allow-third-party-capes")
|
@JsonProperty("allow-third-party-capes")
|
||||||
private boolean allowThirdPartyCapes;
|
private boolean allowThirdPartyCapes = true;
|
||||||
|
|
||||||
@JsonProperty("show-cooldown")
|
@JsonProperty("show-cooldown")
|
||||||
private boolean showCooldown = true;
|
private boolean showCooldown = true;
|
||||||
|
|
||||||
@JsonProperty("allow-third-party-ears")
|
@JsonProperty("allow-third-party-ears")
|
||||||
private boolean allowThirdPartyEars;
|
private boolean allowThirdPartyEars = false;
|
||||||
|
|
||||||
@JsonProperty("default-locale")
|
@JsonProperty("default-locale")
|
||||||
private String defaultLocale;
|
private String defaultLocale = null; // is null by default so system language takes priority
|
||||||
|
|
||||||
@JsonProperty("cache-chunks")
|
@JsonProperty("cache-chunks")
|
||||||
private boolean cacheChunks;
|
private boolean cacheChunks = false;
|
||||||
|
|
||||||
@JsonProperty("cache-images")
|
@JsonProperty("cache-images")
|
||||||
private int cacheImages = 0;
|
private int cacheImages = 0;
|
||||||
|
|
||||||
@JsonProperty("above-bedrock-nether-building")
|
@JsonProperty("above-bedrock-nether-building")
|
||||||
private boolean aboveBedrockNetherBuilding;
|
private boolean aboveBedrockNetherBuilding = false;
|
||||||
|
|
||||||
private MetricsInfo metrics;
|
private MetricsInfo metrics;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class BedrockConfiguration implements IBedrockConfiguration {
|
public static class BedrockConfiguration implements IBedrockConfiguration {
|
||||||
|
|
||||||
@AsteriskSerializer.Asterisk(sensitive = true)
|
@AsteriskSerializer.Asterisk(sensitive = true)
|
||||||
private String address;
|
private String address = "0.0.0.0";
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private int port;
|
private int port = 19132;
|
||||||
|
|
||||||
@JsonProperty("clone-remote-port")
|
@JsonProperty("clone-remote-port")
|
||||||
private boolean cloneRemotePort;
|
private boolean cloneRemotePort = false;
|
||||||
|
|
||||||
private String motd1;
|
private String motd1 = "GeyserMC";
|
||||||
private String motd2;
|
private String motd2 = "Geyser";
|
||||||
|
|
||||||
@JsonProperty("server-name")
|
@JsonProperty("server-name")
|
||||||
private String serverName = GeyserConnector.NAME;
|
private String serverName = GeyserConnector.NAME;
|
||||||
|
@ -126,17 +125,16 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class RemoteConfiguration implements IRemoteConfiguration {
|
public static class RemoteConfiguration implements IRemoteConfiguration {
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@AsteriskSerializer.Asterisk(sensitive = true)
|
@AsteriskSerializer.Asterisk(sensitive = true)
|
||||||
private String address;
|
private String address = "auto";
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private int port;
|
private int port = 25565;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@JsonProperty("auth-type")
|
@JsonProperty("auth-type")
|
||||||
private String authType;
|
private String authType = "online";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -150,13 +148,15 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class MetricsInfo implements IMetricsInfo {
|
public static class MetricsInfo implements IMetricsInfo {
|
||||||
|
private boolean enabled = true;
|
||||||
private boolean enabled;
|
|
||||||
|
|
||||||
@JsonProperty("uuid")
|
@JsonProperty("uuid")
|
||||||
private String uniqueId;
|
private String uniqueId = "generateuuid";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonProperty("scoreboard-packet-threshold")
|
||||||
|
private int scoreboardPacketThreshold = 10;
|
||||||
|
|
||||||
@JsonProperty("enable-proxy-connections")
|
@JsonProperty("enable-proxy-connections")
|
||||||
private boolean enableProxyConnections = false;
|
private boolean enableProxyConnections = false;
|
||||||
|
|
||||||
|
@ -164,5 +164,5 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
||||||
private int mtu = 1400;
|
private int mtu = 1400;
|
||||||
|
|
||||||
@JsonProperty("config-version")
|
@JsonProperty("config-version")
|
||||||
private int configVersion;
|
private int configVersion = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,15 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat
|
||||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.protocol.bedrock.data.AdventureSetting;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
import com.nukkitx.protocol.bedrock.data.AttributeData;
|
||||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||||
|
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.connector.entity.attribute.Attribute;
|
import org.geysermc.connector.entity.attribute.Attribute;
|
||||||
|
@ -48,7 +50,10 @@ import org.geysermc.connector.scoreboard.Team;
|
||||||
import org.geysermc.connector.utils.AttributeUtils;
|
import org.geysermc.connector.utils.AttributeUtils;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
|
@ -209,11 +214,6 @@ public class PlayerEntity extends LivingEntity {
|
||||||
super.updateBedrockMetadata(entityMetadata, session);
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
|
||||||
if (entityMetadata.getId() == 2) {
|
if (entityMetadata.getId() == 2) {
|
||||||
// System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet());
|
|
||||||
for (Team team : session.getWorldCache().getScoreboard().getTeams().values()) {
|
|
||||||
// session.getConnector().getLogger().info("team name " + team.getName());
|
|
||||||
// session.getConnector().getLogger().info("team entities " + team.getEntities());
|
|
||||||
}
|
|
||||||
String username = this.username;
|
String username = this.username;
|
||||||
TextMessage name = (TextMessage) entityMetadata.getValue();
|
TextMessage name = (TextMessage) entityMetadata.getValue();
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
|
@ -221,7 +221,6 @@ public class PlayerEntity extends LivingEntity {
|
||||||
}
|
}
|
||||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
// session.getConnector().getLogger().info("team name es " + team.getName() + " with prefix " + team.getPrefix() + " and suffix " + team.getSuffix());
|
|
||||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -346,7 +346,7 @@ public class GeyserSession implements CommandSender {
|
||||||
PublicKey key = null;
|
PublicKey key = null;
|
||||||
try {
|
try {
|
||||||
key = EncryptionUtil.getKeyFromFile(
|
key = EncryptionUtil.getKeyFromFile(
|
||||||
connector.getConfig().getFloodgateKeyFile(),
|
connector.getConfig().getFloodgateKeyPath(),
|
||||||
PublicKey.class
|
PublicKey.class
|
||||||
);
|
);
|
||||||
} catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
|
} catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||||
|
@ -626,7 +626,7 @@ public class GeyserSession implements CommandSender {
|
||||||
* @param packet the bedrock packet from the NukkitX protocol lib
|
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||||
*/
|
*/
|
||||||
public void sendUpstreamPacket(BedrockPacket packet) {
|
public void sendUpstreamPacket(BedrockPacket packet) {
|
||||||
if (upstream != null && !upstream.isClosed()) {
|
if (upstream != null) {
|
||||||
upstream.sendPacket(packet);
|
upstream.sendPacket(packet);
|
||||||
} else {
|
} else {
|
||||||
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " but the session was null");
|
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " but the session was null");
|
||||||
|
@ -639,7 +639,7 @@ public class GeyserSession implements CommandSender {
|
||||||
* @param packet the bedrock packet from the NukkitX protocol lib
|
* @param packet the bedrock packet from the NukkitX protocol lib
|
||||||
*/
|
*/
|
||||||
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
|
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
|
||||||
if (upstream != null && !upstream.isClosed()) {
|
if (upstream != null) {
|
||||||
upstream.sendPacketImmediately(packet);
|
upstream.sendPacketImmediately(packet);
|
||||||
} else {
|
} else {
|
||||||
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " immediately but the session was null");
|
connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " immediately but the session was null");
|
||||||
|
|
|
@ -41,17 +41,15 @@ public class UpstreamSession {
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|
||||||
public void sendPacket(@NonNull BedrockPacket packet) {
|
public void sendPacket(@NonNull BedrockPacket packet) {
|
||||||
if (isClosed())
|
if (!isClosed()) {
|
||||||
return;
|
session.sendPacket(packet);
|
||||||
|
}
|
||||||
session.sendPacket(packet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacketImmediately(@NonNull BedrockPacket packet) {
|
public void sendPacketImmediately(@NonNull BedrockPacket packet) {
|
||||||
if (isClosed())
|
if (!isClosed()) {
|
||||||
return;
|
session.sendPacketImmediately(packet);
|
||||||
|
}
|
||||||
session.sendPacketImmediately(packet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(String reason) {
|
public void disconnect(String reason) {
|
||||||
|
|
|
@ -31,37 +31,40 @@ import lombok.Setter;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.scoreboard.Objective;
|
import org.geysermc.connector.scoreboard.Objective;
|
||||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||||
|
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class WorldCache {
|
public class WorldCache {
|
||||||
|
private final GeyserSession session;
|
||||||
private GeyserSession session;
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private Difficulty difficulty = Difficulty.EASY;
|
private Difficulty difficulty = Difficulty.EASY;
|
||||||
|
|
||||||
private boolean showCoordinates = true;
|
private boolean showCoordinates = true;
|
||||||
|
|
||||||
private Scoreboard scoreboard;
|
private Scoreboard scoreboard;
|
||||||
|
private final ScoreboardUpdater scoreboardUpdater;
|
||||||
|
|
||||||
public WorldCache(GeyserSession session) {
|
public WorldCache(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.scoreboard = new Scoreboard(session);
|
this.scoreboard = new Scoreboard(session);
|
||||||
|
scoreboardUpdater = new ScoreboardUpdater(this);
|
||||||
|
scoreboardUpdater.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeScoreboard() {
|
public void removeScoreboard() {
|
||||||
if (scoreboard != null) {
|
if (scoreboard != null) {
|
||||||
Collection<Objective> objectives = scoreboard.getObjectives().values();
|
for (Objective objective : scoreboard.getObjectives().values()) {
|
||||||
scoreboard = new Scoreboard(session);
|
|
||||||
|
|
||||||
for (Objective objective : objectives) {
|
|
||||||
scoreboard.despawnObjective(objective);
|
scoreboard.despawnObjective(objective);
|
||||||
}
|
}
|
||||||
|
scoreboard = new Scoreboard(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int increaseAndGetScoreboardPacketsPerSecond() {
|
||||||
|
int pendingPps = scoreboardUpdater.incrementAndGetPacketsPerSecond();
|
||||||
|
int pps = scoreboardUpdater.getPacketsPerSecond();
|
||||||
|
return Math.max(pps, pendingPps);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the client to hide or show the coordinates
|
* Tell the client to hide or show the coordinates
|
||||||
*
|
*
|
||||||
|
|
|
@ -41,13 +41,11 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
||||||
WorldCache cache = session.getWorldCache();
|
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||||
Scoreboard scoreboard = cache.getScoreboard();
|
|
||||||
|
|
||||||
Objective objective = scoreboard.getObjective(packet.getName());
|
Objective objective = scoreboard.getObjective(packet.getName());
|
||||||
|
|
||||||
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
||||||
objective = scoreboard.registerNewObjective(packet.getName(), true);
|
objective = scoreboard.registerNewObjective(packet.getName(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
|
@ -61,6 +59,8 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objective != null && !objective.isTemp()) scoreboard.onUpdate();
|
if (objective != null && objective.isActive()) {
|
||||||
|
scoreboard.onUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,12 @@ package org.geysermc.connector.network.translators.java.scoreboard;
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.GeyserLogger;
|
||||||
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;
|
||||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||||
|
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||||
import org.geysermc.connector.scoreboard.Team;
|
import org.geysermc.connector.scoreboard.Team;
|
||||||
import org.geysermc.connector.scoreboard.UpdateType;
|
import org.geysermc.connector.scoreboard.UpdateType;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
@ -42,10 +44,15 @@ import java.util.Set;
|
||||||
|
|
||||||
@Translator(packet = ServerTeamPacket.class)
|
@Translator(packet = ServerTeamPacket.class)
|
||||||
public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||||
|
private static final GeyserLogger LOGGER = GeyserConnector.getInstance().getLogger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerTeamPacket packet, GeyserSession session) {
|
public void translate(ServerTeamPacket packet, GeyserSession session) {
|
||||||
GeyserConnector.getInstance().getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers()));
|
if (LOGGER.isDebug()) {
|
||||||
|
LOGGER.debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int pps = session.getWorldCache().increaseAndGetScoreboardPacketsPerSecond();
|
||||||
|
|
||||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||||
Team team = scoreboard.getTeam(packet.getTeamName());
|
Team team = scoreboard.getTeam(packet.getTeamName());
|
||||||
|
@ -58,38 +65,53 @@ public class JavaTeamTranslator extends PacketTranslator<ServerTeamPacket> {
|
||||||
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode()));
|
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode()));
|
||||||
break;
|
break;
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
if (team != null) {
|
if (team == null) {
|
||||||
team.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
LOGGER.debug(LanguageUtils.getLocaleStringLog(
|
||||||
.setColor(packet.getColor())
|
"geyser.network.translator.team.failed_not_registered",
|
||||||
.setPrefix(MessageUtils.getTranslatedBedrockMessage(packet.getPrefix(), session.getClientData().getLanguageCode()))
|
packet.getAction(), packet.getTeamName()
|
||||||
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode()))
|
));
|
||||||
.setUpdateType(UpdateType.UPDATE);
|
return;
|
||||||
} else {
|
|
||||||
GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
team.setName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||||
|
.setColor(packet.getColor())
|
||||||
|
.setPrefix(MessageUtils.getTranslatedBedrockMessage(packet.getPrefix(), session.getClientData().getLanguageCode()))
|
||||||
|
.setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode()))
|
||||||
|
.setUpdateType(UpdateType.UPDATE);
|
||||||
break;
|
break;
|
||||||
case ADD_PLAYER:
|
case ADD_PLAYER:
|
||||||
if (team != null) {
|
if (team == null) {
|
||||||
team.addEntities(packet.getPlayers());
|
LOGGER.debug(LanguageUtils.getLocaleStringLog(
|
||||||
} else {
|
"geyser.network.translator.team.failed_not_registered",
|
||||||
GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
|
packet.getAction(), packet.getTeamName()
|
||||||
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
team.addEntities(packet.getPlayers());
|
||||||
break;
|
break;
|
||||||
case REMOVE_PLAYER:
|
case REMOVE_PLAYER:
|
||||||
if (team != null) {
|
if (team == null) {
|
||||||
team.removeEntities(packet.getPlayers());
|
LOGGER.debug(LanguageUtils.getLocaleStringLog(
|
||||||
} else {
|
"geyser.network.translator.team.failed_not_registered",
|
||||||
GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName()));
|
packet.getAction(), packet.getTeamName()
|
||||||
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
team.removeEntities(packet.getPlayers());
|
||||||
break;
|
break;
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
scoreboard.removeTeam(packet.getTeamName());
|
scoreboard.removeTeam(packet.getTeamName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
scoreboard.onUpdate();
|
|
||||||
|
// ScoreboardUpdater will handle it for us if the packets per second
|
||||||
|
// (for score and team packets) is higher then the first threshold
|
||||||
|
if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) {
|
||||||
|
scoreboard.onUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> toPlayerSet(String[] players) {
|
private Set<String> toPlayerSet(String[] players) {
|
||||||
return new ObjectOpenHashSet<>(Arrays.asList(players));
|
return new ObjectOpenHashSet<>(players);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,48 +25,58 @@
|
||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.scoreboard;
|
package org.geysermc.connector.network.translators.java.scoreboard;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction;
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.session.cache.WorldCache;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
import org.geysermc.connector.scoreboard.Objective;
|
import org.geysermc.connector.scoreboard.Objective;
|
||||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||||
|
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction;
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket;
|
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
@Translator(packet = ServerUpdateScorePacket.class)
|
@Translator(packet = ServerUpdateScorePacket.class)
|
||||||
public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScorePacket> {
|
public class JavaUpdateScoreTranslator extends PacketTranslator<ServerUpdateScorePacket> {
|
||||||
|
private final GeyserLogger logger;
|
||||||
|
|
||||||
|
public JavaUpdateScoreTranslator() {
|
||||||
|
logger = GeyserConnector.getInstance().getLogger();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerUpdateScorePacket packet, GeyserSession session) {
|
public void translate(ServerUpdateScorePacket packet, GeyserSession session) {
|
||||||
try {
|
WorldCache worldCache = session.getWorldCache();
|
||||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
Scoreboard scoreboard = worldCache.getScoreboard();
|
||||||
|
int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond();
|
||||||
|
|
||||||
Objective objective = scoreboard.getObjective(packet.getObjective());
|
Objective objective = scoreboard.getObjective(packet.getObjective());
|
||||||
if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) {
|
if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) {
|
||||||
GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.translator.score.failed_objective", packet.getObjective()));
|
logger.info(LanguageUtils.getLocaleStringLog("geyser.network.translator.score.failed_objective", packet.getObjective()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case ADD_OR_UPDATE:
|
case ADD_OR_UPDATE:
|
||||||
objective.setScore(packet.getEntry(), packet.getValue());
|
objective.setScore(packet.getEntry(), packet.getValue());
|
||||||
break;
|
break;
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
if (objective != null) {
|
if (objective != null) {
|
||||||
objective.resetScore(packet.getEntry());
|
objective.removeScore(packet.getEntry());
|
||||||
} else {
|
} else {
|
||||||
for (Objective objective1 : scoreboard.getObjectives().values()) {
|
for (Objective objective1 : scoreboard.getObjectives().values()) {
|
||||||
objective1.resetScore(packet.getEntry());
|
objective1.removeScore(packet.getEntry());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScoreboardUpdater will handle it for us if the packets per second
|
||||||
|
// (for score and team packets) is higher then the first threshold
|
||||||
|
if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) {
|
||||||
scoreboard.onUpdate();
|
scoreboard.onUpdate();
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,23 +29,23 @@ import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Objective {
|
public class Objective {
|
||||||
private Scoreboard scoreboard;
|
private final Scoreboard scoreboard;
|
||||||
private long id;
|
private final long id;
|
||||||
private boolean temp;
|
private boolean active = true;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
private UpdateType updateType = UpdateType.ADD;
|
||||||
private String objectiveName;
|
private String objectiveName;
|
||||||
private String displaySlot;
|
private String displaySlotName;
|
||||||
private String displayName = "unknown";
|
private String displayName = "unknown";
|
||||||
private int type = 0; // 0 = integer, 1 = heart
|
private int type = 0; // 0 = integer, 1 = heart
|
||||||
|
|
||||||
private Map<String, Score> scores = new HashMap<>();
|
private Map<String, Score> scores = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private Objective(Scoreboard scoreboard) {
|
private Objective(Scoreboard scoreboard) {
|
||||||
this.id = scoreboard.getNextId().getAndIncrement();
|
this.id = scoreboard.getNextId().getAndIncrement();
|
||||||
|
@ -54,23 +54,20 @@ public class Objective {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /!\ This method is made for temporary objectives until the real objective is received
|
* /!\ This method is made for temporary objectives until the real objective is received
|
||||||
* @param scoreboard the scoreboard
|
*
|
||||||
|
* @param scoreboard the scoreboard
|
||||||
* @param objectiveName the name of the objective
|
* @param objectiveName the name of the objective
|
||||||
*/
|
*/
|
||||||
public Objective(Scoreboard scoreboard, String objectiveName) {
|
public Objective(Scoreboard scoreboard, String objectiveName) {
|
||||||
this(scoreboard);
|
this(scoreboard);
|
||||||
this.objectiveName = objectiveName;
|
this.objectiveName = objectiveName;
|
||||||
this.temp = true;
|
this.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) {
|
public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) {
|
||||||
this(scoreboard, objectiveName, displaySlot.name().toLowerCase(), displayName, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Objective(Scoreboard scoreboard, String objectiveName, String displaySlot, String displayName, int type) {
|
|
||||||
this(scoreboard);
|
this(scoreboard);
|
||||||
this.objectiveName = objectiveName;
|
this.objectiveName = objectiveName;
|
||||||
this.displaySlot = displaySlot;
|
this.displaySlotName = translateDisplaySlot(displaySlot);
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
@ -87,21 +84,9 @@ public class Objective {
|
||||||
public void setScore(String id, int score) {
|
public void setScore(String id, int score) {
|
||||||
if (scores.containsKey(id)) {
|
if (scores.containsKey(id)) {
|
||||||
scores.get(id).setScore(score).setUpdateType(UpdateType.ADD);
|
scores.get(id).setScore(score).setUpdateType(UpdateType.ADD);
|
||||||
} else {
|
return;
|
||||||
registerScore(id, score);
|
|
||||||
}
|
}
|
||||||
}
|
registerScore(id, score);
|
||||||
|
|
||||||
public void setScoreText(String oldText, String newText) {
|
|
||||||
if (!scores.containsKey(oldText) || oldText.equals(newText)) return;
|
|
||||||
Score oldScore = scores.get(oldText);
|
|
||||||
|
|
||||||
Score newScore = new Score(this, newText)
|
|
||||||
.setScore(oldScore.getScore())
|
|
||||||
.setTeam(scoreboard.getTeamFor(newText));
|
|
||||||
|
|
||||||
scores.put(newText, newScore);
|
|
||||||
oldScore.setUpdateType(UpdateType.REMOVE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScore(String id) {
|
public int getScore(String id) {
|
||||||
|
@ -113,37 +98,61 @@ public class Objective {
|
||||||
|
|
||||||
public Score getScore(int line) {
|
public Score getScore(int line) {
|
||||||
for (Score score : scores.values()) {
|
for (Score score : scores.values()) {
|
||||||
if (score.getScore() == line) return score;
|
if (score.getScore() == line) {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetScore(String id) {
|
public void removeScore(String id) {
|
||||||
if (scores.containsKey(id)) {
|
if (scores.containsKey(id)) {
|
||||||
scores.get(id).setUpdateType(UpdateType.REMOVE);
|
scores.get(id).setUpdateType(UpdateType.REMOVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeScore(String id) {
|
/**
|
||||||
|
* Used internally to remove a score from the score map
|
||||||
|
*/
|
||||||
|
public void removeScore0(String id) {
|
||||||
scores.remove(id);
|
scores.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective setDisplayName(String displayName) {
|
public Objective setDisplayName(String displayName) {
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE;
|
if (updateType == UpdateType.NOTHING) {
|
||||||
|
updateType = UpdateType.UPDATE;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective setType(int type) {
|
public Objective setType(int type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE;
|
if (updateType == UpdateType.NOTHING) {
|
||||||
|
updateType = UpdateType.UPDATE;
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTemp(ScoreboardPosition displaySlot) {
|
public void setActive(ScoreboardPosition displaySlot) {
|
||||||
if (temp) {
|
if (!active) {
|
||||||
temp = false;
|
active = true;
|
||||||
this.displaySlot = displaySlot.name().toLowerCase();
|
displaySlotName = translateDisplaySlot(displaySlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removed() {
|
||||||
|
scores = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String translateDisplaySlot(ScoreboardPosition displaySlot) {
|
||||||
|
switch (displaySlot) {
|
||||||
|
case BELOW_NAME:
|
||||||
|
return "belowname";
|
||||||
|
case PLAYER_LIST:
|
||||||
|
return "list";
|
||||||
|
default:
|
||||||
|
return "sidebar";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,40 +25,63 @@
|
||||||
|
|
||||||
package org.geysermc.connector.scoreboard;
|
package org.geysermc.connector.scoreboard;
|
||||||
|
|
||||||
|
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Score {
|
public class Score {
|
||||||
private Objective objective;
|
private final Objective objective;
|
||||||
private long id;
|
private ScoreInfo cachedInfo;
|
||||||
|
private final long id;
|
||||||
|
|
||||||
|
@Setter
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
private UpdateType updateType = UpdateType.ADD;
|
||||||
private String name;
|
private final String name;
|
||||||
private Team team;
|
private Team team;
|
||||||
private int score;
|
private int score;
|
||||||
|
@Setter
|
||||||
private int oldScore = Integer.MIN_VALUE;
|
private int oldScore = Integer.MIN_VALUE;
|
||||||
|
|
||||||
public Score(Objective objective, String name) {
|
public Score(Objective objective, String name) {
|
||||||
this.id = objective.getScoreboard().getNextId().getAndIncrement();
|
this.id = objective.getScoreboard().getNextId().getAndIncrement();
|
||||||
this.objective = objective;
|
this.objective = objective;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
if (team != null && team.getUpdateType() != UpdateType.REMOVE) {
|
if (team != null) {
|
||||||
return team.getPrefix() + name + team.getSuffix();
|
return team.getPrefix() + name + team.getSuffix();
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Score setScore(int score) {
|
public Score setScore(int score) {
|
||||||
if (oldScore == Integer.MIN_VALUE) {
|
|
||||||
this.oldScore = score;
|
|
||||||
}
|
|
||||||
this.score = score;
|
this.score = score;
|
||||||
|
updateType = UpdateType.UPDATE;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Score setTeam(Team team) {
|
||||||
|
if (this.team != null && team != null) {
|
||||||
|
if (!this.team.equals(team)) {
|
||||||
|
this.team = team;
|
||||||
|
updateType = UpdateType.UPDATE;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// simplified from (this.team != null && team == null) || (this.team == null && team != null)
|
||||||
|
if (this.team != null || team != null) {
|
||||||
|
this.team = team;
|
||||||
|
updateType = UpdateType.UPDATE;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
cachedInfo = new ScoreInfo(id, objective.getObjectiveName(), score, getDisplayName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,73 +26,72 @@
|
||||||
package org.geysermc.connector.scoreboard;
|
package org.geysermc.connector.scoreboard;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
|
||||||
|
import com.nukkitx.protocol.bedrock.BedrockPacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||||
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket;
|
||||||
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
import com.nukkitx.protocol.bedrock.packet.SetScorePacket;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.GeyserLogger;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import static org.geysermc.connector.scoreboard.UpdateType.*;
|
import static org.geysermc.connector.scoreboard.UpdateType.*;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Scoreboard {
|
public class Scoreboard {
|
||||||
private GeyserSession session;
|
private final GeyserSession session;
|
||||||
private AtomicLong nextId = new AtomicLong(0);
|
private final GeyserLogger logger;
|
||||||
|
private final AtomicLong nextId = new AtomicLong(0);
|
||||||
|
|
||||||
private Map<String, Objective> objectives = new HashMap<>();
|
private final Map<String, Objective> objectives = new ConcurrentHashMap<>();
|
||||||
private Map<String, Team> teams = new HashMap<>();
|
private final Map<String, Team> teams = new HashMap<>();
|
||||||
|
|
||||||
|
private int lastScoreCount = 0;
|
||||||
|
|
||||||
public Scoreboard(GeyserSession session) {
|
public Scoreboard(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.logger = GeyserConnector.getInstance().getLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective registerNewObjective(String objectiveId, boolean temp) {
|
public Objective registerNewObjective(String objectiveId, boolean active) {
|
||||||
if (!temp || objectives.containsKey(objectiveId)) return objectives.get(objectiveId);
|
if (active || objectives.containsKey(objectiveId)) {
|
||||||
|
return objectives.get(objectiveId);
|
||||||
|
}
|
||||||
Objective objective = new Objective(this, objectiveId);
|
Objective objective = new Objective(this, objectiveId);
|
||||||
objectives.put(objectiveId, objective);
|
objectives.put(objectiveId, objective);
|
||||||
return objective;
|
return objective;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
||||||
Objective objective = null;
|
Objective objective = objectives.get(objectiveId);
|
||||||
if (objectives.containsKey(objectiveId)) {
|
if (objective != null) {
|
||||||
objective = objectives.get(objectiveId);
|
if (!objective.isActive()) {
|
||||||
if (objective.isTemp()) objective.removeTemp(displaySlot);
|
objective.setActive(displaySlot);
|
||||||
else {
|
return objective;
|
||||||
despawnObjective(objective);
|
|
||||||
objective = null;
|
|
||||||
}
|
}
|
||||||
|
despawnObjective(objective);
|
||||||
}
|
}
|
||||||
if (objective == null) {
|
|
||||||
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
||||||
objectives.put(objectiveId, objective);
|
objectives.put(objectiveId, objective);
|
||||||
}
|
|
||||||
return objective;
|
return objective;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Team registerNewTeam(String teamName, Set<String> players) {
|
public Team registerNewTeam(String teamName, Set<String> players) {
|
||||||
if (teams.containsKey(teamName)) {
|
Team team = teams.get(teamName);
|
||||||
session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName));
|
if (team != null) {
|
||||||
return getTeam(teamName);
|
logger.info(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName));
|
||||||
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
Team team = new Team(this, teamName).setEntities(players);
|
team = new Team(this, teamName).setEntities(players);
|
||||||
teams.put(teamName, team);
|
teams.put(teamName, team);
|
||||||
|
|
||||||
for (Objective objective : objectives.values()) {
|
|
||||||
for (Score score : objective.getScores().values()) {
|
|
||||||
if (players.contains(score.getName())) {
|
|
||||||
score.setTeam(team);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,102 +105,119 @@ public class Scoreboard {
|
||||||
|
|
||||||
public void unregisterObjective(String objectiveName) {
|
public void unregisterObjective(String objectiveName) {
|
||||||
Objective objective = getObjective(objectiveName);
|
Objective objective = getObjective(objectiveName);
|
||||||
if (objective != null) objective.setUpdateType(REMOVE);
|
if (objective != null) {
|
||||||
|
objective.setUpdateType(REMOVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTeam(String teamName) {
|
public void removeTeam(String teamName) {
|
||||||
Team remove = teams.remove(teamName);
|
Team remove = teams.remove(teamName);
|
||||||
if (remove != null) remove.setUpdateType(REMOVE);
|
if (remove != null) {
|
||||||
|
remove.setUpdateType(REMOVE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onUpdate() {
|
public void onUpdate() {
|
||||||
Set<Objective> changedObjectives = new ObjectOpenHashSet<>();
|
List<ScoreInfo> addScores = new ArrayList<>(getLastScoreCount());
|
||||||
List<ScoreInfo> addScores = new ArrayList<>();
|
List<ScoreInfo> removeScores = new ArrayList<>(getLastScoreCount());
|
||||||
List<ScoreInfo> removeScores = new ArrayList<>();
|
|
||||||
|
|
||||||
for (String objectiveId : new ArrayList<>(objectives.keySet())) {
|
for (Objective objective : objectives.values()) {
|
||||||
Objective objective = objectives.get(objectiveId);
|
if (!objective.isActive()) {
|
||||||
if (objective.isTemp()) {
|
logger.debug("Ignoring non-active Scoreboard Objective '"+ objective.getObjectiveName() +'\'');
|
||||||
session.getConnector().getLogger().debug("Ignoring temp Scoreboard Objective '"+ objectiveId +'\'');
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objective.getUpdateType() != NOTHING) changedObjectives.add(objective);
|
// hearts can't hold teams, so we treat them differently
|
||||||
|
if (objective.getType() == 1) {
|
||||||
|
for (Score score : objective.getScores().values()) {
|
||||||
|
if (score.getUpdateType() == NOTHING) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean update = score.getUpdateType() == UPDATE;
|
||||||
|
if (update) {
|
||||||
|
score.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score.getUpdateType() == ADD || update) {
|
||||||
|
addScores.add(score.getCachedInfo());
|
||||||
|
}
|
||||||
|
if (score.getUpdateType() == REMOVE || update) {
|
||||||
|
removeScores.add(score.getCachedInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
boolean globalUpdate = objective.getUpdateType() == UPDATE;
|
boolean globalUpdate = objective.getUpdateType() == UPDATE;
|
||||||
boolean globalAdd = objective.getUpdateType() == ADD || globalUpdate;
|
boolean globalAdd = objective.getUpdateType() == ADD;
|
||||||
boolean globalRemove = objective.getUpdateType() == REMOVE || globalUpdate;
|
boolean globalRemove = objective.getUpdateType() == REMOVE;
|
||||||
|
|
||||||
boolean hasUpdate = globalUpdate;
|
for (Score score : objective.getScores().values()) {
|
||||||
|
|
||||||
List<Score> handledScores = new ArrayList<>();
|
|
||||||
for (String identifier : new ObjectOpenHashSet<>(objective.getScores().keySet())) {
|
|
||||||
Score score = objective.getScores().get(identifier);
|
|
||||||
Team team = score.getTeam();
|
Team team = score.getTeam();
|
||||||
|
|
||||||
boolean inTeam = team != null && team.getEntities().contains(score.getName());
|
boolean add = globalAdd || globalUpdate;
|
||||||
|
boolean remove = globalRemove;
|
||||||
|
boolean teamChanged = false;
|
||||||
|
if (team != null) {
|
||||||
|
if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) {
|
||||||
|
score.setTeam(null);
|
||||||
|
teamChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
boolean teamAdd = team != null && (team.getUpdateType() == ADD || team.getUpdateType() == UPDATE);
|
teamChanged |= team.getUpdateType() == UPDATE;
|
||||||
boolean teamRemove = team != null && (team.getUpdateType() == REMOVE || team.getUpdateType() == UPDATE);
|
|
||||||
|
|
||||||
if (team != null && (team.getUpdateType() == REMOVE || !inTeam)) score.setTeam(null);
|
add |= team.getUpdateType() == ADD || team.getUpdateType() == UPDATE;
|
||||||
|
remove |= team.getUpdateType() == REMOVE;
|
||||||
boolean add = (hasUpdate || globalAdd || teamAdd || teamRemove || score.getUpdateType() == ADD || score.getUpdateType() == UPDATE) && (score.getUpdateType() != REMOVE);
|
|
||||||
boolean remove = hasUpdate || globalRemove || teamAdd || teamRemove || score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE;
|
|
||||||
|
|
||||||
boolean updated = false;
|
|
||||||
if (!hasUpdate) {
|
|
||||||
updated = hasUpdate = add;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updated) {
|
add |= score.getUpdateType() == ADD || score.getUpdateType() == UPDATE;
|
||||||
for (Score score1 : handledScores) {
|
remove |= score.getUpdateType() == REMOVE;
|
||||||
ScoreInfo scoreInfo = new ScoreInfo(score1.getId(), score1.getObjective().getObjectiveName(), score1.getScore(), score1.getDisplayName());
|
if (score.getUpdateType() == REMOVE) {
|
||||||
addScores.add(scoreInfo);
|
add = false;
|
||||||
removeScores.add(scoreInfo);
|
}
|
||||||
}
|
|
||||||
|
if (score.getUpdateType() == UPDATE || teamChanged) {
|
||||||
|
score.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add) {
|
if (add) {
|
||||||
addScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getScore(), score.getDisplayName()));
|
addScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
if (remove) {
|
if (remove) {
|
||||||
removeScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getOldScore(), score.getDisplayName()));
|
removeScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
|
// score is pending to be updated, so we use the current score as the old score
|
||||||
score.setOldScore(score.getScore());
|
score.setOldScore(score.getScore());
|
||||||
|
|
||||||
|
// score is pending to be removed, so we can remove it from the objective
|
||||||
if (score.getUpdateType() == REMOVE) {
|
if (score.getUpdateType() == REMOVE) {
|
||||||
objective.removeScore(score.getName());
|
objective.removeScore0(score.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add || remove) {
|
|
||||||
changedObjectives.add(objective);
|
|
||||||
} else { // stays the same like before
|
|
||||||
handledScores.add(score);
|
|
||||||
}
|
|
||||||
score.setUpdateType(NOTHING);
|
score.setUpdateType(NOTHING);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (Objective objective : changedObjectives) {
|
if (globalRemove || globalUpdate) {
|
||||||
boolean update = objective.getUpdateType() == NOTHING || objective.getUpdateType() == UPDATE;
|
|
||||||
if (objective.getUpdateType() == REMOVE || update) {
|
|
||||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
session.sendUpstreamPacket(removeObjectivePacket);
|
session.sendUpstreamPacket(removeObjectivePacket);
|
||||||
if (objective.getUpdateType() == REMOVE) {
|
if (objective.getUpdateType() == REMOVE) {
|
||||||
objectives.remove(objective.getObjectiveName()); // now we can deregister
|
objectives.remove(objective.getObjectiveName()); // now we can deregister
|
||||||
|
objective.removed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (objective.getUpdateType() == ADD || update) {
|
|
||||||
|
if (globalAdd || globalUpdate) {
|
||||||
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||||
displayObjectivePacket.setCriteria("dummy");
|
displayObjectivePacket.setCriteria("dummy");
|
||||||
displayObjectivePacket.setDisplaySlot(objective.getDisplaySlot());
|
displayObjectivePacket.setDisplaySlot(objective.getDisplaySlotName());
|
||||||
displayObjectivePacket.setSortOrder(1); // ??
|
displayObjectivePacket.setSortOrder(1); // ??
|
||||||
session.sendUpstreamPacket(displayObjectivePacket);
|
session.sendUpstreamPacket(displayObjectivePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
objective.setUpdateType(NOTHING);
|
objective.setUpdateType(NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +234,8 @@ public class Scoreboard {
|
||||||
setScorePacket.setInfos(addScores);
|
setScorePacket.setInfos(addScores);
|
||||||
session.sendUpstreamPacket(setScorePacket);
|
session.sendUpstreamPacket(setScorePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastScoreCount = addScores.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void despawnObjective(Objective objective) {
|
public void despawnObjective(Objective objective) {
|
||||||
|
@ -234,6 +252,8 @@ public class Scoreboard {
|
||||||
0, ""
|
0, ""
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objective.removed();
|
||||||
|
|
||||||
if (!toRemove.isEmpty()) {
|
if (!toRemove.isEmpty()) {
|
||||||
SetScorePacket setScorePacket = new SetScorePacket();
|
SetScorePacket setScorePacket = new SetScorePacket();
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* 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.scoreboard;
|
||||||
|
|
||||||
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||||
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
import org.geysermc.connector.network.session.cache.WorldCache;
|
||||||
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class ScoreboardUpdater extends Thread {
|
||||||
|
public static final int FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD;
|
||||||
|
public static final int SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD = 250;
|
||||||
|
|
||||||
|
private static final int FIRST_MILLIS_BETWEEN_UPDATES = 250; // 4 updates per second
|
||||||
|
private static final int SECOND_MILLIS_BETWEEN_UPDATES = 1000 * 3; // 1 update per 3 seconds
|
||||||
|
|
||||||
|
private static final boolean DEBUG_ENABLED;
|
||||||
|
|
||||||
|
private final WorldCache worldCache;
|
||||||
|
private final GeyserSession session;
|
||||||
|
|
||||||
|
private int millisBetweenUpdates = FIRST_MILLIS_BETWEEN_UPDATES;
|
||||||
|
private long lastUpdate = System.currentTimeMillis();
|
||||||
|
private long lastLog = -1;
|
||||||
|
|
||||||
|
private long lastPacketsPerSecondUpdate = System.currentTimeMillis();
|
||||||
|
private final AtomicInteger packetsPerSecond = new AtomicInteger(0);
|
||||||
|
private final AtomicInteger pendingPacketsPerSecond = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public ScoreboardUpdater(WorldCache worldCache) {
|
||||||
|
super("Scoreboard Updater");
|
||||||
|
this.worldCache = worldCache;
|
||||||
|
session = worldCache.getSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!session.isClosed()) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// reset score-packets per second every second
|
||||||
|
if (currentTime - lastPacketsPerSecondUpdate > 1000) {
|
||||||
|
lastPacketsPerSecondUpdate = currentTime;
|
||||||
|
packetsPerSecond.set(pendingPacketsPerSecond.get());
|
||||||
|
pendingPacketsPerSecond.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTime - lastUpdate > millisBetweenUpdates) {
|
||||||
|
lastUpdate = currentTime;
|
||||||
|
|
||||||
|
int pps = packetsPerSecond.get();
|
||||||
|
if (pps >= FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) {
|
||||||
|
boolean reachedSecondThreshold = pps >= SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD;
|
||||||
|
if (reachedSecondThreshold) {
|
||||||
|
millisBetweenUpdates = SECOND_MILLIS_BETWEEN_UPDATES;
|
||||||
|
} else {
|
||||||
|
millisBetweenUpdates = FIRST_MILLIS_BETWEEN_UPDATES;
|
||||||
|
}
|
||||||
|
|
||||||
|
worldCache.getScoreboard().onUpdate();
|
||||||
|
|
||||||
|
if (DEBUG_ENABLED && (currentTime - lastLog > 60000)) { // one minute
|
||||||
|
int threshold = reachedSecondThreshold ?
|
||||||
|
SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD :
|
||||||
|
FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD;
|
||||||
|
|
||||||
|
GeyserConnector.getInstance().getLogger().info(
|
||||||
|
LanguageUtils.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached.log", session.getName(), threshold, pps) +
|
||||||
|
LanguageUtils.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached", (millisBetweenUpdates / 1000.0))
|
||||||
|
);
|
||||||
|
|
||||||
|
lastLog = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPacketsPerSecond() {
|
||||||
|
return packetsPerSecond.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase the Scoreboard Packets Per Second and return the updated value
|
||||||
|
*/
|
||||||
|
public int incrementAndGetPacketsPerSecond() {
|
||||||
|
return pendingPacketsPerSecond.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
GeyserConfiguration config = GeyserConnector.getInstance().getConfig();
|
||||||
|
FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD = Math.min(config.getScoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD);
|
||||||
|
DEBUG_ENABLED = config.isDebugMode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,8 +35,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter @Setter
|
||||||
@Setter
|
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Team {
|
public class Team {
|
||||||
private final Scoreboard scoreboard;
|
private final Scoreboard scoreboard;
|
||||||
|
@ -44,6 +43,7 @@ public class Team {
|
||||||
|
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
private UpdateType updateType = UpdateType.ADD;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private String prefix;
|
private String prefix;
|
||||||
private TeamColor color;
|
private TeamColor color;
|
||||||
private String suffix;
|
private String suffix;
|
||||||
|
@ -57,8 +57,7 @@ public class Team {
|
||||||
public void addEntities(String... names) {
|
public void addEntities(String... names) {
|
||||||
List<String> added = new ArrayList<>();
|
List<String> added = new ArrayList<>();
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
if (!entities.contains(name)) {
|
if (entities.add(name)) {
|
||||||
entities.add(name);
|
|
||||||
added.add(name);
|
added.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,4 +77,35 @@ public class Team {
|
||||||
}
|
}
|
||||||
setUpdateType(UpdateType.UPDATE);
|
setUpdateType(UpdateType.UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasEntity(String name) {
|
||||||
|
return entities.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Team setPrefix(String prefix) {
|
||||||
|
// replace "null" to an empty string,
|
||||||
|
// we do this here to improve the performance of Score#getDisplayName
|
||||||
|
if (prefix.length() == 4 && "null".equals(prefix)) {
|
||||||
|
this.prefix = "";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this.prefix = prefix;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Team setSuffix(String suffix) {
|
||||||
|
// replace "null" to an empty string,
|
||||||
|
// we do this here to improve the performance of Score#getDisplayName
|
||||||
|
if (suffix.length() == 4 && "null".equals(suffix)) {
|
||||||
|
this.suffix = "";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
this.suffix = suffix;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id.hashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,12 @@ metrics:
|
||||||
|
|
||||||
# ADVANCED OPTIONS - DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING!
|
# ADVANCED OPTIONS - DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING!
|
||||||
|
|
||||||
|
# Geyser updates the Scoreboard after every Scoreboard packet, but when Geyser tries to handle
|
||||||
|
# a lot of scoreboard packets per second can cause serious lag.
|
||||||
|
# This option allows you to specify after how many Scoreboard packets per seconds
|
||||||
|
# the Scoreboard updates will be limited to four updates per second.
|
||||||
|
scoreboard-packet-threshold: 20
|
||||||
|
|
||||||
# Allow connections from ProxyPass and Waterdog.
|
# Allow connections from ProxyPass and Waterdog.
|
||||||
# See https://www.spigotmc.org/wiki/firewall-guide/ for assistance - use UDP instead of TCP.
|
# See https://www.spigotmc.org/wiki/firewall-guide/ for assistance - use UDP instead of TCP.
|
||||||
enable-proxy-connections: false
|
enable-proxy-connections: false
|
||||||
|
|
Loading…
Reference in a new issue