3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-12-25 15:50:14 +01:00

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
Dieser Commit ist enthalten in:
Tim203 2020-08-28 17:47:52 +02:00 committet von GitHub
Ursprung 7cbfdcf521
Commit 1c84993853
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
29 geänderte Dateien mit 549 neuen und 616 gelöschten Zeilen

Datei anzeigen

@ -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;
} }
} }

Datei anzeigen

@ -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;
} }
} }

Datei anzeigen

@ -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);

Datei anzeigen

@ -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

Datei anzeigen

@ -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;
} }
} }

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

@ -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;
} }
} }

Datei anzeigen

@ -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());

Datei anzeigen

@ -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());
} }
} }

Datei anzeigen

@ -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();
} }

Datei anzeigen

@ -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());
} }
} }

Datei anzeigen

@ -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;
} }
} }

Datei anzeigen

@ -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;

Datei anzeigen

@ -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();
} }

Datei anzeigen

@ -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();

Datei anzeigen

@ -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;
} }

Datei anzeigen

@ -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());
} }
} }

Datei anzeigen

@ -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");

Datei anzeigen

@ -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) {

Datei anzeigen

@ -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
* *

Datei anzeigen

@ -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();
}
} }
} }

Datei anzeigen

@ -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);
} }
} }

Datei anzeigen

@ -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();
} }
} }
} }

Datei anzeigen

@ -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";
} }
} }
} }

Datei anzeigen

@ -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());
}
} }

Datei anzeigen

@ -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();

Datei anzeigen

@ -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();
}
}

Datei anzeigen

@ -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();
}
} }

Datei anzeigen

@ -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