Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-09 01:30:11 +01:00
New config used in core
Dieser Commit ist enthalten in:
Ursprung
db9b951352
Commit
29f8e294ad
@ -108,7 +108,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener {
|
||||
listenerInfo.isPingPassthrough(),
|
||||
listenerInfo.getQueryPort(),
|
||||
listenerInfo.isQueryEnabled(),
|
||||
bootstrap.getGeyserConfig().getRemote().isUseProxyProtocol() // If Geyser is expecting HAProxy, so should the Bungee end
|
||||
bootstrap.config().java().useProxyProtocol() // If Geyser is expecting HAProxy, so should the Bungee end
|
||||
);
|
||||
|
||||
// The field that stores all listeners in BungeeCord
|
||||
@ -142,7 +142,7 @@ public class GeyserBungeeInjector extends GeyserInjector implements Listener {
|
||||
}
|
||||
initChannel.invoke(channelInitializer, ch);
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression()) {
|
||||
if (bootstrap.config().asPluginConfig().orElseThrow().useDirectConnection()) {
|
||||
ch.pipeline().addAfter(PipelineUtils.PACKET_ENCODER, "geyser-compression-disabler",
|
||||
new GeyserBungeeCompressionDisabler());
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public final class GeyserBungeeUpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(final PostLoginEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final ProxiedPlayer player = event.getPlayer();
|
||||
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new BungeeCommandSource(player));
|
||||
|
@ -96,7 +96,7 @@ public class GeyserModInjector extends GeyserInjector {
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression()) {
|
||||
if (bootstrap.config().asPluginConfig().orElseThrow().disableCompression()) {
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserModCompressionDisabler());
|
||||
}
|
||||
}
|
||||
@ -125,7 +125,7 @@ public class GeyserModInjector extends GeyserInjector {
|
||||
childHandler = (ChannelInitializer<Channel>) childHandlerField.get(handler);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (bootstrap.getGeyserConfig().isDebugMode()) {
|
||||
if (bootstrap.config().debugMode()) {
|
||||
bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
|
||||
// If the LAN is opened, starts Geyser.
|
||||
GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
|
||||
instance.setServer((MinecraftServer) (Object) this);
|
||||
instance.getGeyserConfig().getRemote().setPort(port);
|
||||
instance.onGeyserEnable();
|
||||
// Ensure player locale has been loaded, in case it's different from Java system language
|
||||
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
|
||||
|
@ -122,7 +122,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
int index = ch.pipeline().names().indexOf("encoder");
|
||||
String baseName = index != -1 ? "encoder" : "outbound_config";
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
|
||||
if (bootstrap.config().asPluginConfig().orElseThrow().disableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
|
||||
ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
|
||||
}
|
||||
}
|
||||
@ -157,7 +157,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
}
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (bootstrap.getGeyserConfig().isDebugMode()) {
|
||||
if (bootstrap.config().debugMode()) {
|
||||
bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -176,8 +176,8 @@ public class GeyserSpigotInjector extends GeyserInjector {
|
||||
*/
|
||||
private void workAroundWeirdBug(GeyserBootstrap bootstrap) {
|
||||
MinecraftProtocol protocol = new MinecraftProtocol();
|
||||
LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().address(),
|
||||
bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress,
|
||||
LocalSession session = new LocalSession(bootstrap.config().java().address(),
|
||||
bootstrap.config().java().port(), this.serverSocketAddress,
|
||||
InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
|
||||
session.connect();
|
||||
session.disconnect("");
|
||||
|
@ -487,7 +487,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
|
||||
ConfigLoaderTemp.load(GeyserPluginConfig.class);
|
||||
ConfigLoaderTemp.load(new File(getDataFolder(), "config.yml"), GeyserPluginConfig.class);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
ex.printStackTrace();
|
||||
|
@ -38,7 +38,7 @@ public final class GeyserSpigotUpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(final PlayerJoinEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new SpigotCommandSource(player));
|
||||
|
@ -76,7 +76,7 @@ public final class GeyserPaperCommandListener implements Listener {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GeyserImpl.getInstance().getConfig().isUseDirectConnection()) {
|
||||
if (GeyserImpl.getInstance().config().asPluginConfig().orElseThrow().useDirectConnection()) {
|
||||
InetSocketAddress address = player.getAddress();
|
||||
if (address != null) {
|
||||
return address.getPort() != 0;
|
||||
|
@ -25,11 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.platform.standalone;
|
||||
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
|
||||
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
|
||||
import io.netty.util.ResourceLeakDetector;
|
||||
import lombok.Getter;
|
||||
import net.minecrell.terminalconsole.TerminalConsoleAppender;
|
||||
@ -44,16 +39,17 @@ import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
import org.geysermc.geyser.configuration.ConfigLoaderTemp;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserRemoteConfig;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.platform.standalone.gui.GeyserStandaloneGUI;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
import org.geysermc.geyser.util.LoopbackUtil;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -61,13 +57,13 @@ import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private GeyserCommandManager geyserCommandManager;
|
||||
private GeyserStandaloneConfiguration geyserConfig;
|
||||
private GeyserConfig geyserConfig;
|
||||
private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
|
||||
private IGeyserPingPassthrough geyserPingPassthrough;
|
||||
private GeyserStandaloneGUI gui;
|
||||
@ -78,15 +74,15 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
private GeyserImpl geyser;
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private static final Map<String, String> argsConfigKeys = new HashMap<>();
|
||||
private static final Map<NodePath, String> argsConfigKeys = new HashMap<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (System.getProperty("io.netty.leakDetection.level") == null) {
|
||||
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); // Can eat performance
|
||||
}
|
||||
|
||||
System.setProperty("bstats.relocatecheck", "false");
|
||||
|
||||
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
|
||||
// Set defaults
|
||||
boolean useGuiOpts = bootstrap.useGui;
|
||||
@ -94,8 +90,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
|
||||
GeyserLocale.init(bootstrap);
|
||||
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
|
||||
// Optionally, you can force the use of a GUI or no GUI by specifying args
|
||||
@ -127,34 +121,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
// Split the argument by an =
|
||||
String[] argParts = arg.substring(2).split("=");
|
||||
if (argParts.length == 2) {
|
||||
// Split the config key by . to allow for nested options
|
||||
String[] configKeyParts = argParts[0].split("\\.");
|
||||
|
||||
// Loop the possible config options to check the passed key is valid
|
||||
boolean found = false;
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop sub-section options to check the passed key is valid
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the found key to the stored list for later usage
|
||||
if (found) {
|
||||
argsConfigKeys.put(argParts[0], argParts[1]);
|
||||
break;
|
||||
}
|
||||
argsConfigKeys.put(NodePath.of(argParts[0].split("\\.")), argParts[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.err.println(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
|
||||
@ -192,18 +160,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
@Override
|
||||
public void onGeyserEnable() {
|
||||
try {
|
||||
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
|
||||
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
|
||||
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
|
||||
|
||||
ConfigLoaderTemp.load(GeyserRemoteConfig.class);
|
||||
|
||||
handleArgsConfigOptions();
|
||||
|
||||
if (this.geyserConfig.getRemote().address().equalsIgnoreCase("auto")) {
|
||||
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
|
||||
geyserConfig.getRemote().setAddress("127.0.0.1");
|
||||
}
|
||||
geyserConfig = ConfigLoaderTemp.load(new File(configFilename), GeyserRemoteConfig.class, this::handleArgsConfigOptions);
|
||||
} catch (IOException ex) {
|
||||
geyserLogger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
|
||||
if (gui == null) {
|
||||
@ -213,11 +170,10 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
return;
|
||||
}
|
||||
}
|
||||
geyserLogger.setDebug(geyserConfig.isDebugMode());
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
geyserLogger.setDebug(geyserConfig.debugMode());
|
||||
|
||||
// Allow libraries like Protocol to have their debug information passthrough
|
||||
log4jLogger.get().setLevel(geyserConfig.isDebugMode() ? Level.DEBUG : Level.INFO);
|
||||
log4jLogger.get().setLevel(geyserConfig.debugMode() ? Level.DEBUG : Level.INFO);
|
||||
|
||||
geyser = GeyserImpl.load(PlatformType.STANDALONE, this);
|
||||
|
||||
@ -266,8 +222,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeyserConfiguration getGeyserConfig() {
|
||||
return geyserConfig;
|
||||
public GeyserConfig config() {
|
||||
return this.geyserConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -318,100 +274,47 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link BeanPropertyDefinition}s for the given class
|
||||
*
|
||||
* @param clazz The class to get the definitions for
|
||||
* @return A list of {@link BeanPropertyDefinition} for the given class
|
||||
*/
|
||||
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
|
||||
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
|
||||
|
||||
// Introspect the given type
|
||||
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
|
||||
|
||||
// Find properties
|
||||
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
|
||||
|
||||
// Get the ignored properties
|
||||
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
|
||||
.findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig() ,beanDescription.getClassInfo()).getIgnored();
|
||||
|
||||
// Filter properties removing the ignored ones
|
||||
return properties.stream()
|
||||
.filter(property -> !ignoredProperties.contains(property.getName()))
|
||||
.collect(Collectors.toList());
|
||||
@Override
|
||||
public Path getFloodgateKeyPath() {
|
||||
return Path.of(geyserConfig.floodgateKeyFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a POJO property value on an object
|
||||
*
|
||||
* @param property The {@link BeanPropertyDefinition} to set
|
||||
* @param parentObject The object to alter
|
||||
* @param value The new value of the property
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // Required for enum usage
|
||||
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
|
||||
private static void setConfigOption(CommentedConfigurationNode node, Object value) throws SerializationException {
|
||||
Object parsedValue = value;
|
||||
|
||||
// Change the values type if needed
|
||||
if (int.class.equals(property.getRawPrimaryType())) {
|
||||
Class<?> clazz = node.raw().getClass();
|
||||
if (Integer.class == clazz) {
|
||||
parsedValue = Integer.valueOf((String) parsedValue);
|
||||
} else if (boolean.class.equals(property.getRawPrimaryType())) {
|
||||
} else if (Boolean.class == clazz) {
|
||||
parsedValue = Boolean.valueOf((String) parsedValue);
|
||||
} else if (Enum.class.isAssignableFrom(property.getRawPrimaryType())) {
|
||||
parsedValue = Enum.valueOf((Class<? extends Enum>) property.getRawPrimaryType(), ((String) parsedValue).toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
// Force the value to be set
|
||||
AnnotatedField field = property.getField();
|
||||
field.fixAccess(true);
|
||||
field.setValue(parentObject, parsedValue);
|
||||
node.set(parsedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
|
||||
* Update the loaded config with any values passed in the command line arguments
|
||||
*/
|
||||
private void handleArgsConfigOptions() {
|
||||
// Get the available properties from the class
|
||||
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
|
||||
private void handleArgsConfigOptions(CommentedConfigurationNode node) {
|
||||
for (Map.Entry<NodePath, String> configKey : argsConfigKeys.entrySet()) {
|
||||
NodePath path = configKey.getKey();
|
||||
CommentedConfigurationNode subNode = node.node(path);
|
||||
if (subNode.virtual()) {
|
||||
geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.unrecognised", path));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
|
||||
String[] configKeyParts = configKey.getKey().split("\\.");
|
||||
|
||||
// Loop over the properties looking for any matches against the stored one from the argument
|
||||
for (BeanPropertyDefinition property : availableProperties) {
|
||||
if (configKeyParts[0].equals(property.getName())) {
|
||||
if (configKeyParts.length > 1) {
|
||||
// Loop through the sub property if the first part matches
|
||||
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
|
||||
if (configKeyParts[1].equals(subProperty.getName())) {
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the sub property value on the config
|
||||
try {
|
||||
Object subConfig = property.getGetter().callOn(geyserConfig);
|
||||
setConfigOption(subProperty, subConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
|
||||
// Set the property value on the config
|
||||
try {
|
||||
setConfigOption(property, geyserConfig, configKey.getValue());
|
||||
} catch (Exception e) {
|
||||
geyserLogger.error("Failed to set config option: " + property.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
try {
|
||||
setConfigOption(subNode, configKey.getValue());
|
||||
geyserLogger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
|
||||
} catch (SerializationException e) {
|
||||
geyserLogger.error("Failed to set config option: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,15 @@ package org.geysermc.geyser.platform.velocity;
|
||||
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.WriteBufferWaterMark;
|
||||
import io.netty.channel.local.LocalAddress;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserPluginBootstrap;
|
||||
import org.geysermc.geyser.network.netty.GeyserInjector;
|
||||
import org.geysermc.geyser.network.netty.LocalServerChannelWrapper;
|
||||
|
||||
@ -47,7 +52,7 @@ public class GeyserVelocityInjector extends GeyserInjector {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception {
|
||||
protected void initializeLocalChannel0(GeyserPluginBootstrap bootstrap) throws Exception {
|
||||
Field cm = proxy.getClass().getDeclaredField("cm");
|
||||
cm.setAccessible(true);
|
||||
Object connectionManager = cm.get(proxy);
|
||||
@ -80,7 +85,7 @@ public class GeyserVelocityInjector extends GeyserInjector {
|
||||
protected void initChannel(@NonNull Channel ch) throws Exception {
|
||||
initChannel.invoke(channelInitializer, ch);
|
||||
|
||||
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserVelocityCompressionDisabler.ENABLED) {
|
||||
if (bootstrap.config().disableCompression() && GeyserVelocityCompressionDisabler.ENABLED) {
|
||||
ch.pipeline().addAfter("minecraft-encoder", "geyser-compression-disabler",
|
||||
new GeyserVelocityCompressionDisabler());
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public final class GeyserVelocityUpdateListener {
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerJoin(PostLoginEvent event) {
|
||||
if (GeyserImpl.getInstance().getConfig().isNotifyOnNewBedrockUpdate()) {
|
||||
if (GeyserImpl.getInstance().config().notifyOnNewBedrockUpdate()) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player.hasPermission(Constants.UPDATE_PERMISSION)) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(() -> new VelocityCommandSource(player));
|
||||
|
@ -73,6 +73,8 @@ dependencies {
|
||||
annotationProcessor(projects.ap)
|
||||
|
||||
api(libs.events)
|
||||
|
||||
api(libs.bstats)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
|
@ -47,6 +47,8 @@ public final class Constants {
|
||||
|
||||
public static final int CONFIG_VERSION = 5;
|
||||
|
||||
public static final int BSTATS_ID = 5273;
|
||||
|
||||
static {
|
||||
URI wsUri = null;
|
||||
try {
|
||||
@ -56,4 +58,4 @@ public final class Constants {
|
||||
}
|
||||
GLOBAL_API_WS_URI = wsUri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.geyser.level.GeyserWorldManager;
|
||||
@ -72,7 +73,16 @@ public interface GeyserBootstrap {
|
||||
*
|
||||
* @return The current GeyserConfiguration
|
||||
*/
|
||||
GeyserConfiguration getGeyserConfig();
|
||||
default GeyserConfiguration getGeyserConfig() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current GeyserConfig
|
||||
*
|
||||
* @return The current GeyserConfig
|
||||
*/
|
||||
GeyserConfig config();
|
||||
|
||||
/**
|
||||
* Returns the current GeyserLogger
|
||||
@ -189,4 +199,9 @@ public interface GeyserBootstrap {
|
||||
* Tests if Floodgate is installed, loads the Floodgate key if so, and returns the result of Floodgate installed.
|
||||
*/
|
||||
boolean testFloodgatePluginPresent();
|
||||
|
||||
/**
|
||||
* TEMPORARY - will be removed after The Merge:tm:.
|
||||
*/
|
||||
Path getFloodgateKeyPath();
|
||||
}
|
||||
|
@ -25,9 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
@ -39,6 +36,11 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bstats.MetricsBase;
|
||||
import org.bstats.charts.AdvancedPie;
|
||||
import org.bstats.charts.DrilldownPie;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bstats.charts.SingleLineChart;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@ -67,7 +69,7 @@ import org.geysermc.geyser.api.network.RemoteServer;
|
||||
import org.geysermc.geyser.api.util.MinecraftVersion;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommandManager;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.erosion.UnixSocketClientListener;
|
||||
import org.geysermc.geyser.event.GeyserEventBus;
|
||||
@ -91,10 +93,8 @@ import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.text.MinecraftLocale;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.AssetUtils;
|
||||
import org.geysermc.geyser.util.CooldownUtils;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
import org.geysermc.geyser.util.JsonUtils;
|
||||
import org.geysermc.geyser.util.Metrics;
|
||||
import org.geysermc.geyser.util.NewsHandler;
|
||||
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
import org.geysermc.geyser.util.WebUtils;
|
||||
@ -128,13 +128,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
public class GeyserImpl implements GeyserApi {
|
||||
public static final ObjectMapper JSON_MAPPER = new ObjectMapper()
|
||||
.enable(JsonParser.Feature.IGNORE_UNDEFINED)
|
||||
.enable(JsonParser.Feature.ALLOW_COMMENTS)
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
|
||||
.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
|
||||
|
||||
public static final Gson GSON = JsonUtils.createGson();
|
||||
|
||||
public static final String NAME = "Geyser";
|
||||
@ -180,7 +173,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
private final EventBus<EventRegistrar> eventBus;
|
||||
private final GeyserExtensionManager extensionManager;
|
||||
|
||||
private Metrics metrics;
|
||||
private MetricsBase metrics;
|
||||
|
||||
private PendingMicrosoftAuthentication pendingMicrosoftAuthentication;
|
||||
@Getter(AccessLevel.NONE)
|
||||
@ -269,7 +262,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
|
||||
startInstance();
|
||||
|
||||
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
||||
GeyserConfig config = bootstrap.config();
|
||||
|
||||
double completeTime = (System.currentTimeMillis() - startupTime) / 1000D;
|
||||
String message = GeyserLocale.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime));
|
||||
@ -277,11 +270,11 @@ public class GeyserImpl implements GeyserApi {
|
||||
logger.info(message);
|
||||
|
||||
if (platformType == PlatformType.STANDALONE) {
|
||||
if (config.getRemote().authType() != AuthType.FLOODGATE) {
|
||||
if (config.java().authType() != AuthType.FLOODGATE) {
|
||||
// If the auth-type is Floodgate, then this Geyser instance is probably owned by the Java server
|
||||
logger.warning(GeyserLocale.getLocaleStringLog("geyser.core.movement_warn"));
|
||||
}
|
||||
} else if (config.getRemote().authType() == AuthType.FLOODGATE) {
|
||||
} else if (config.java().authType() == AuthType.FLOODGATE) {
|
||||
VersionCheckUtils.checkForOutdatedFloodgate(logger);
|
||||
}
|
||||
|
||||
@ -296,7 +289,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
GeyserLocale.finalizeDefaultLocale(this);
|
||||
}
|
||||
GeyserLogger logger = bootstrap.getGeyserLogger();
|
||||
GeyserConfiguration config = bootstrap.getGeyserConfig();
|
||||
GeyserConfig config = bootstrap.config();
|
||||
|
||||
ScoreboardUpdater.init();
|
||||
|
||||
@ -314,31 +307,28 @@ public class GeyserImpl implements GeyserApi {
|
||||
|
||||
if (platformType != PlatformType.STANDALONE) {
|
||||
int javaPort = bootstrap.getServerPort();
|
||||
if (config.getRemote().address().equals("auto")) {
|
||||
config.setAutoconfiguredRemote(true);
|
||||
String serverAddress = bootstrap.getServerBindAddress();
|
||||
if (!serverAddress.isEmpty() && !"0.0.0.0".equals(serverAddress)) {
|
||||
config.getRemote().setAddress(serverAddress);
|
||||
} else {
|
||||
// Set the remote address to localhost since that is where we are always connecting
|
||||
try {
|
||||
config.getRemote().setAddress(InetAddress.getLocalHost().getHostAddress());
|
||||
} catch (UnknownHostException ex) {
|
||||
logger.debug("Unknown host when trying to find localhost.");
|
||||
if (config.isDebugMode()) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
config.getRemote().setAddress(InetAddress.getLoopbackAddress().getHostAddress());
|
||||
String serverAddress = bootstrap.getServerBindAddress();
|
||||
if (!serverAddress.isEmpty() && !"0.0.0.0".equals(serverAddress)) {
|
||||
config.java().address(serverAddress);
|
||||
} else {
|
||||
// Set the remote address to localhost since that is where we are always connecting
|
||||
try {
|
||||
config.java().address(InetAddress.getLocalHost().getHostAddress());
|
||||
} catch (UnknownHostException ex) {
|
||||
logger.debug("Unknown host when trying to find localhost.");
|
||||
if (config.debugMode()) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
config.java().address(InetAddress.getLoopbackAddress().getHostAddress());
|
||||
}
|
||||
if (javaPort != -1) {
|
||||
config.getRemote().setPort(javaPort);
|
||||
}
|
||||
}
|
||||
if (javaPort != -1 && config.asPluginConfig().isEmpty()) {
|
||||
config.java().port(javaPort);
|
||||
}
|
||||
|
||||
boolean forceMatchServerPort = "server".equals(pluginUdpPort);
|
||||
if ((config.getBedrock().isCloneRemotePort() || forceMatchServerPort) && javaPort != -1) {
|
||||
config.getBedrock().setPort(javaPort);
|
||||
if ((config.asPluginConfig().map(pluginConfig -> pluginConfig.bedrock().cloneRemotePort()).orElse(false) || forceMatchServerPort) && javaPort != -1) {
|
||||
config.bedrock().port(javaPort);
|
||||
if (forceMatchServerPort) {
|
||||
if (geyserUdpPort.isEmpty()) {
|
||||
logger.info("Port set from system generic property to match Java server.");
|
||||
@ -352,15 +342,15 @@ public class GeyserImpl implements GeyserApi {
|
||||
if ("server".equals(pluginUdpAddress)) {
|
||||
String address = bootstrap.getServerBindAddress();
|
||||
if (!address.isEmpty()) {
|
||||
config.getBedrock().setAddress(address);
|
||||
config.bedrock().address(address);
|
||||
}
|
||||
} else if (!pluginUdpAddress.isEmpty()) {
|
||||
config.getBedrock().setAddress(pluginUdpAddress);
|
||||
config.bedrock().address(pluginUdpAddress);
|
||||
}
|
||||
|
||||
if (!portPropertyApplied && !pluginUdpPort.isEmpty()) {
|
||||
int port = Integer.parseInt(pluginUdpPort);
|
||||
config.getBedrock().setPort(port);
|
||||
config.bedrock().port(port);
|
||||
if (geyserUdpPort.isEmpty()) {
|
||||
logger.info("Port set from generic system property: " + port);
|
||||
} else {
|
||||
@ -378,42 +368,44 @@ public class GeyserImpl implements GeyserApi {
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.error(String.format("Invalid broadcast port: %s! Defaulting to configured port.", broadcastPort + " (" + e.getMessage() + ")"));
|
||||
parsedPort = config.getBedrock().port();
|
||||
parsedPort = config.bedrock().port();
|
||||
}
|
||||
config.getBedrock().setBroadcastPort(parsedPort);
|
||||
config.bedrock().broadcastPort(parsedPort);
|
||||
logger.info("Broadcast port set from system property: " + parsedPort);
|
||||
}
|
||||
|
||||
if (platformType != PlatformType.VIAPROXY) {
|
||||
boolean floodgatePresent = bootstrap.testFloodgatePluginPresent();
|
||||
if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
|
||||
if (config.java().authType() == AuthType.FLOODGATE && !floodgatePresent) {
|
||||
logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
|
||||
+ GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
|
||||
return;
|
||||
} else if (config.isAutoconfiguredRemote() && floodgatePresent) {
|
||||
} else if (floodgatePresent) {
|
||||
// Floodgate installed means that the user wants Floodgate authentication
|
||||
logger.debug("Auto-setting to Floodgate authentication.");
|
||||
config.getRemote().setAuthType(AuthType.FLOODGATE);
|
||||
config.java().authType(AuthType.FLOODGATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String remoteAddress = config.getRemote().address();
|
||||
// Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry.
|
||||
if (!remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) {
|
||||
String[] record = WebUtils.findSrvRecord(this, remoteAddress);
|
||||
if (record != null) {
|
||||
int remotePort = Integer.parseInt(record[2]);
|
||||
config.getRemote().setAddress(remoteAddress = record[3]);
|
||||
config.getRemote().setPort(remotePort);
|
||||
logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\"");
|
||||
if (config.asPluginConfig().isEmpty()) {
|
||||
String remoteAddress = config.java().address();
|
||||
// Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry.
|
||||
if (!remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) {
|
||||
String[] record = WebUtils.findSrvRecord(this, remoteAddress);
|
||||
if (record != null) {
|
||||
int remotePort = Integer.parseInt(record[2]);
|
||||
config.java().address(remoteAddress = record[3]);
|
||||
config.java().port(remotePort);
|
||||
logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves
|
||||
TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false;
|
||||
|
||||
pendingMicrosoftAuthentication = new PendingMicrosoftAuthentication(config.getPendingAuthenticationTimeout());
|
||||
pendingMicrosoftAuthentication = new PendingMicrosoftAuthentication(config.pendingAuthenticationTimeout());
|
||||
|
||||
this.newsHandler = new NewsHandler(BRANCH, this.buildNumber());
|
||||
|
||||
@ -425,8 +417,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
logger.debug("Epoll is not available; Erosion's Unix socket handling will not work.");
|
||||
}
|
||||
|
||||
CooldownUtils.setDefaultShowCooldown(config.getShowCooldown());
|
||||
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||
DimensionUtils.changeBedrockNetherId(config.aboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
|
||||
|
||||
Integer bedrockThreadCount = Integer.getInteger("Geyser.BedrockNetworkThreads");
|
||||
if (bedrockThreadCount == null) {
|
||||
@ -436,14 +427,14 @@ public class GeyserImpl implements GeyserApi {
|
||||
|
||||
if (shouldStartListener) {
|
||||
this.geyserServer = new GeyserServer(this, bedrockThreadCount);
|
||||
this.geyserServer.bind(new InetSocketAddress(config.getBedrock().address(), config.getBedrock().port()))
|
||||
this.geyserServer.bind(new InetSocketAddress(config.bedrock().address(), config.bedrock().port()))
|
||||
.whenComplete((avoid, throwable) -> {
|
||||
if (throwable == null) {
|
||||
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().address(),
|
||||
String.valueOf(config.getBedrock().port())));
|
||||
logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.bedrock().address(),
|
||||
String.valueOf(config.bedrock().port())));
|
||||
} else {
|
||||
String address = config.getBedrock().address();
|
||||
int port = config.getBedrock().port();
|
||||
String address = config.bedrock().address();
|
||||
int port = config.bedrock().port();
|
||||
logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port)));
|
||||
if (!"0.0.0.0".equals(address)) {
|
||||
logger.info(Component.text("Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0", NamedTextColor.GREEN));
|
||||
@ -453,9 +444,9 @@ public class GeyserImpl implements GeyserApi {
|
||||
}).join();
|
||||
}
|
||||
|
||||
if (config.getRemote().authType() == AuthType.FLOODGATE) {
|
||||
if (config.java().authType() == AuthType.FLOODGATE) {
|
||||
try {
|
||||
Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath());
|
||||
Key key = new AesKeyProducer().produceFrom(bootstrap.getFloodgateKeyPath());
|
||||
cipher = new AesCipher(new Base64Topping());
|
||||
cipher.init(key);
|
||||
logger.debug("Loaded Floodgate key!");
|
||||
@ -467,15 +458,39 @@ public class GeyserImpl implements GeyserApi {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.getMetrics().isEnabled()) {
|
||||
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
|
||||
metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size));
|
||||
if (config.metrics().enabled()) {
|
||||
metrics = new MetricsBase(
|
||||
"server-implementation",
|
||||
config.metrics().uuid().toString(),
|
||||
Constants.BSTATS_ID,
|
||||
true, // Already checked above.
|
||||
builder -> {
|
||||
// OS specific data
|
||||
String osName = System.getProperty("os.name");
|
||||
String osArch = System.getProperty("os.arch");
|
||||
String osVersion = System.getProperty("os.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
builder.appendField("osName", osName);
|
||||
builder.appendField("osArch", osArch);
|
||||
builder.appendField("osVersion", osVersion);
|
||||
builder.appendField("coreCount", coreCount);
|
||||
},
|
||||
builder -> {},
|
||||
null,
|
||||
() -> true,
|
||||
logger::error,
|
||||
logger::info,
|
||||
config.debugMode(),
|
||||
config.debugMode(),
|
||||
config.debugMode());
|
||||
metrics.addCustomChart(new SingleLineChart("players", sessionManager::size));
|
||||
// Prevent unwanted words best we can
|
||||
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().authType().toString().toLowerCase(Locale.ROOT)));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::platformName));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
|
||||
metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserImpl.VERSION));
|
||||
metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> {
|
||||
metrics.addCustomChart(new SimplePie("authMode", () -> config.java().authType().toString().toLowerCase(Locale.ROOT)));
|
||||
metrics.addCustomChart(new SimplePie("platform", platformType::platformName));
|
||||
metrics.addCustomChart(new SimplePie("defaultLocale", GeyserLocale::getDefaultLocale));
|
||||
metrics.addCustomChart(new SimplePie("version", () -> GeyserImpl.VERSION));
|
||||
metrics.addCustomChart(new AdvancedPie("playerPlatform", () -> {
|
||||
Map<String, Integer> valueMap = new HashMap<>();
|
||||
for (GeyserSession session : sessionManager.getAllSessions()) {
|
||||
if (session == null) continue;
|
||||
@ -489,7 +504,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
}
|
||||
return valueMap;
|
||||
}));
|
||||
metrics.addCustomChart(new Metrics.AdvancedPie("playerVersion", () -> {
|
||||
metrics.addCustomChart(new AdvancedPie("playerVersion", () -> {
|
||||
Map<String, Integer> valueMap = new HashMap<>();
|
||||
for (GeyserSession session : sessionManager.getAllSessions()) {
|
||||
if (session == null) continue;
|
||||
@ -511,7 +526,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
platformMap.put(platformType.platformName(), 1);
|
||||
versionMap.put(minecraftVersion, platformMap);
|
||||
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("minecraftServerVersion", () -> {
|
||||
metrics.addCustomChart(new DrilldownPie("minecraftServerVersion", () -> {
|
||||
// By the end, we should return, for example:
|
||||
// 1.16.5 => (Spigot, 1)
|
||||
return versionMap;
|
||||
@ -520,7 +535,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
|
||||
// The following code can be attributed to the PaperMC project
|
||||
// https://github.com/PaperMC/Paper/blob/master/Spigot-Server-Patches/0005-Paper-Metrics.patch#L614
|
||||
metrics.addCustomChart(new Metrics.DrilldownPie("javaVersion", () -> {
|
||||
metrics.addCustomChart(new DrilldownPie("javaVersion", () -> {
|
||||
Map<String, Map<String, Integer>> map = new HashMap<>();
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
Map<String, Integer> entry = new HashMap<>();
|
||||
@ -555,7 +570,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
metrics = null;
|
||||
}
|
||||
|
||||
if (config.getRemote().authType() == AuthType.ONLINE) {
|
||||
if (config.java().authType() == AuthType.ONLINE) {
|
||||
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
|
||||
savedRefreshTokens = new ConcurrentHashMap<>();
|
||||
|
||||
@ -570,7 +585,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
logger.error("Cannot load saved user tokens!", e);
|
||||
}
|
||||
if (refreshTokenFile != null) {
|
||||
List<String> validUsers = config.getSavedUserLogins();
|
||||
List<String> validUsers = config.savedUserLogins();
|
||||
boolean doWrite = false;
|
||||
for (Map.Entry<String, String> entry : refreshTokenFile.entrySet()) {
|
||||
String user = entry.getKey();
|
||||
@ -598,7 +613,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
this.eventBus.fire(new GeyserPostInitializeEvent(this.extensionManager, this.eventBus));
|
||||
}
|
||||
|
||||
if (config.isNotifyOnNewBedrockUpdate()) {
|
||||
if (config.notifyOnNewBedrockUpdate()) {
|
||||
VersionCheckUtils.checkForGeyserUpdate(this::getLogger);
|
||||
}
|
||||
}
|
||||
@ -750,13 +765,13 @@ public class GeyserImpl implements GeyserApi {
|
||||
|
||||
@NonNull
|
||||
public RemoteServer defaultRemoteServer() {
|
||||
return getConfig().getRemote();
|
||||
return config().java();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public BedrockListener bedrockListener() {
|
||||
return getConfig().getBedrock();
|
||||
return config().bedrock();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -830,8 +845,8 @@ public class GeyserImpl implements GeyserApi {
|
||||
return bootstrap.getGeyserLogger();
|
||||
}
|
||||
|
||||
public GeyserConfiguration getConfig() {
|
||||
return bootstrap.getGeyserConfig();
|
||||
public GeyserConfig config() {
|
||||
return bootstrap.config();
|
||||
}
|
||||
|
||||
public WorldManager getWorldManager() {
|
||||
@ -844,7 +859,7 @@ public class GeyserImpl implements GeyserApi {
|
||||
}
|
||||
|
||||
public void saveRefreshToken(@NonNull String bedrockName, @NonNull String refreshToken) {
|
||||
if (!getConfig().getSavedUserLogins().contains(bedrockName)) {
|
||||
if (!config().savedUserLogins().contains(bedrockName)) {
|
||||
// Do not save this login
|
||||
return;
|
||||
}
|
||||
|
36
core/src/main/java/org/geysermc/geyser/GeyserPluginBootstrap.java
Normale Datei
36
core/src/main/java/org/geysermc/geyser/GeyserPluginBootstrap.java
Normale Datei
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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.geyser;
|
||||
|
||||
import org.geysermc.geyser.configuration.GeyserPluginConfig;
|
||||
|
||||
/**
|
||||
* Used in any instance where Geyser is directly attached to a server instance of some sort.
|
||||
*/
|
||||
public interface GeyserPluginBootstrap extends GeyserBootstrap {
|
||||
@Override
|
||||
GeyserPluginConfig config();
|
||||
}
|
@ -32,7 +32,7 @@ import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.LoopbackUtil;
|
||||
@ -86,7 +86,7 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
port = geyser.getConfig().getBedrock().broadcastPort();
|
||||
port = geyser.config().bedrock().broadcastPort();
|
||||
}
|
||||
String ip = fullAddress[0];
|
||||
|
||||
@ -114,41 +114,41 @@ public class ConnectionTestCommand extends GeyserCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
GeyserConfiguration config = geyser.getConfig();
|
||||
GeyserConfig config = geyser.config();
|
||||
|
||||
// Issue: do the ports not line up? We only check this if players don't override the broadcast port - if they do, they (hopefully) know what they're doing
|
||||
if (config.getBedrock().broadcastPort() == config.getBedrock().port()) {
|
||||
if (port != config.getBedrock().port()) {
|
||||
if (config.bedrock().broadcastPort() == config.bedrock().port()) {
|
||||
if (port != config.bedrock().port()) {
|
||||
if (fullAddress.length == 2) {
|
||||
sender.sendMessage("The port you are testing with (" + port + ") is not the same as you set in your Geyser configuration ("
|
||||
+ config.getBedrock().port() + ")");
|
||||
+ config.bedrock().port() + ")");
|
||||
sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `port` in the config.");
|
||||
if (config.getBedrock().isCloneRemotePort()) {
|
||||
if (config.asPluginConfig().map(pluginConfig -> pluginConfig.bedrock().cloneRemotePort()).orElse(false)) {
|
||||
sender.sendMessage("You have `clone-remote-port` enabled. This option ignores the `bedrock` `port` in the config, and uses the Java server port instead.");
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage("You did not specify the port to check (add it with \":<port>\"), " +
|
||||
"and the default port 19132 does not match the port in your Geyser configuration ("
|
||||
+ config.getBedrock().port() + ")!");
|
||||
+ config.bedrock().port() + ")!");
|
||||
sender.sendMessage("Re-run the command with that port, or change the port in the config under `bedrock` `port`.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (config.getBedrock().broadcastPort() != port) {
|
||||
if (config.bedrock().broadcastPort() != port) {
|
||||
sender.sendMessage("The port you are testing with (" + port + ") is not the same as the broadcast port set in your Geyser configuration ("
|
||||
+ config.getBedrock().broadcastPort() + "). ");
|
||||
+ config.bedrock().broadcastPort() + "). ");
|
||||
sender.sendMessage("You ONLY need to change the broadcast port if clients connects with a port different from the port Geyser is running on.");
|
||||
sender.sendMessage("Re-run the command with the port in the config, or change the `bedrock` `broadcast-port` in the config.");
|
||||
}
|
||||
}
|
||||
|
||||
// Issue: is the `bedrock` `address` in the config different?
|
||||
if (!config.getBedrock().address().equals("0.0.0.0")) {
|
||||
if (!config.bedrock().address().equals("0.0.0.0")) {
|
||||
sender.sendMessage("The address specified in `bedrock` `address` is not \"0.0.0.0\" - this may cause issues unless this is deliberate and intentional.");
|
||||
}
|
||||
|
||||
// Issue: did someone turn on enable-proxy-protocol, and they didn't mean it?
|
||||
if (config.getBedrock().isEnableProxyProtocol()) {
|
||||
if (config.bedrock().enableProxyProtocol()) {
|
||||
sender.sendMessage("You have the `enable-proxy-protocol` setting enabled. " +
|
||||
"Unless you're deliberately using additional software that REQUIRES this setting, you may not need it enabled.");
|
||||
}
|
||||
|
@ -25,13 +25,14 @@
|
||||
|
||||
package org.geysermc.geyser.command.defaults;
|
||||
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommand;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.dump.DumpInfo;
|
||||
@ -49,7 +50,6 @@ import java.util.List;
|
||||
public class DumpCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserImpl geyser;
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String DUMP_URL = "https://dump.geysermc.org/";
|
||||
|
||||
public DumpCommand(GeyserImpl geyser, String name, String description, String permission) {
|
||||
@ -81,18 +81,13 @@ public class DumpCommand extends GeyserCommand {
|
||||
|
||||
AsteriskSerializer.showSensitive = showSensitive;
|
||||
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collecting", sender.locale()));
|
||||
String dumpData;
|
||||
try {
|
||||
if (offlineDump) {
|
||||
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
|
||||
// Make arrays easier to read
|
||||
prettyPrinter.indentArraysWith(new DefaultIndenter(" ", "\n"));
|
||||
dumpData = MAPPER.writer(prettyPrinter).writeValueAsString(new DumpInfo(addLog));
|
||||
} else {
|
||||
dumpData = MAPPER.writeValueAsString(new DumpInfo(addLog));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
dumpData = gson.toJson(new DumpInfo(addLog));
|
||||
} catch (JsonSyntaxException e) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.locale()));
|
||||
geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
|
||||
return;
|
||||
@ -118,10 +113,10 @@ public class DumpCommand extends GeyserCommand {
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.uploading", sender.locale()));
|
||||
|
||||
String response;
|
||||
JsonNode responseNode;
|
||||
JsonObject responseNode;
|
||||
try {
|
||||
response = WebUtils.post(DUMP_URL + "documents", dumpData);
|
||||
responseNode = MAPPER.readTree(response);
|
||||
responseNode = (JsonObject) new JsonParser().parse(response);
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.locale()));
|
||||
geyser.getLogger().error(GeyserLocale.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
|
||||
@ -129,11 +124,11 @@ public class DumpCommand extends GeyserCommand {
|
||||
}
|
||||
|
||||
if (!responseNode.has("key")) {
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.locale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
|
||||
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.locale()) + ": " + (responseNode.has("message") ? responseNode.get("message").getAsString() : response));
|
||||
return;
|
||||
}
|
||||
|
||||
uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
|
||||
uploadedDumpUrl = DUMP_URL + responseNode.get("key").getAsString();
|
||||
}
|
||||
|
||||
sender.sendMessage(GeyserLocale.getPlayerLocaleString("geyser.commands.dump.message", sender.locale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
|
||||
|
@ -25,18 +25,21 @@
|
||||
|
||||
package org.geysermc.geyser.configuration;
|
||||
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.interfaces.InterfaceDefaultOptions;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ConfigLoaderTemp {
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
import static org.spongepowered.configurate.transformation.TransformAction.remove;
|
||||
import static org.spongepowered.configurate.transformation.TransformAction.rename;
|
||||
|
||||
public final class ConfigLoaderTemp {
|
||||
private static final String HEADER = """
|
||||
--------------------------------
|
||||
Geyser Configuration File
|
||||
@ -51,35 +54,81 @@ public class ConfigLoaderTemp {
|
||||
In most cases, especially with server hosting providers, further hosting-specific configuration is required.
|
||||
--------------------------------""";
|
||||
|
||||
public static <T extends GeyserConfig> T load(Class<T> configClass) throws IOException {
|
||||
var loader = YamlConfigurationLoader.builder()
|
||||
.file(new File("newconfig.yml"))
|
||||
.defaultOptions(options -> InterfaceDefaultOptions.addTo(options.header(HEADER)))
|
||||
.build();
|
||||
ConfigurationNode node = loader.load();
|
||||
// temp fix for node.virtual() being broken
|
||||
var virtual = !Files.exists(Path.of("newconfig.yml"));
|
||||
public static <T extends GeyserConfig> T load(File file, Class<T> configClass) throws IOException {
|
||||
return load(file, configClass, null);
|
||||
}
|
||||
|
||||
// TODO needed or else Configurate breaks
|
||||
public static <T extends GeyserConfig> T load(File file, Class<T> configClass, @Nullable Consumer<CommentedConfigurationNode> transformer) throws IOException {
|
||||
var loader = YamlConfigurationLoader.builder()
|
||||
.file(file)
|
||||
.defaultOptions(options -> InterfaceDefaultOptions.addTo(options
|
||||
.header(HEADER)
|
||||
.serializers(builder -> builder.register(new LowercaseEnumSerializer()))))
|
||||
.build();
|
||||
var node = loader.load();
|
||||
// temp fix for node.virtual() being broken
|
||||
boolean virtual = file.exists();
|
||||
|
||||
// Note for Tim? Needed or else Configurate breaks.
|
||||
var migrations = ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("config-version")
|
||||
// Pre-Configurate
|
||||
.addVersion(5, ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path("legacyPingPassthrough"), (path, value) -> {
|
||||
// Invert value
|
||||
value.set(Boolean.FALSE.equals(value.get(boolean.class)));
|
||||
return new Object[]{"integratedPingPassthrough"};
|
||||
})
|
||||
.addAction(NodePath.path("remote"), (path, value) ->
|
||||
new Object[]{"java"})
|
||||
.build())
|
||||
.addAction(path("legacy-ping-passthrough"), configClass == GeyserRemoteConfig.class ? remove() : (path, value) -> {
|
||||
// Invert value
|
||||
value.set(!value.getBoolean());
|
||||
return new Object[]{"integrated-ping-passthrough"};
|
||||
})
|
||||
.addAction(path("remote"), rename("java"))
|
||||
.addAction(path("floodgate-key-file"), (path, value) -> {
|
||||
// Elimate any legacy config values
|
||||
if ("public-key.pem".equals(value.getString())) {
|
||||
value.set("key.pem");
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.addAction(path("default-locale"), (path, value) -> {
|
||||
if (value.getString() == null) {
|
||||
value.set("system");
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.addAction(path("show-cooldown"), (path, value) -> {
|
||||
String s = value.getString();
|
||||
if (s != null) {
|
||||
switch (s) {
|
||||
case "true" -> value.set("title");
|
||||
case "false" -> value.set("disabled");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.addAction(path("bedrock", "motd1"), rename("primary-motd"))
|
||||
.addAction(path("bedrock", "motd2"), rename("secondary-motd"))
|
||||
// Legacy config values
|
||||
.addAction(path("emote-offhand-workaround"), remove())
|
||||
.addAction(path("allow-third-party-capes"), remove())
|
||||
.addAction(path("allow-third-party-ears"), remove())
|
||||
.addAction(path("general-thread-pool"), remove())
|
||||
.addAction(path("cache-chunks"), remove())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
int currentVersion = migrations.version(node);
|
||||
migrations.apply(node);
|
||||
int newVersion = migrations.version(node);
|
||||
|
||||
T config = node.get(configClass);
|
||||
System.out.println(config);
|
||||
|
||||
loader.save(node);
|
||||
if (virtual || currentVersion != newVersion) {
|
||||
loader.save(node);
|
||||
}
|
||||
|
||||
if (transformer != null) {
|
||||
// Do not let the transformer change the node.
|
||||
transformer.accept(node);
|
||||
config = node.get(configClass);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.api.network.BedrockListener;
|
||||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.util.CooldownUtils;
|
||||
import org.spongepowered.configurate.interfaces.meta.Exclude;
|
||||
import org.spongepowered.configurate.interfaces.meta.defaults.DefaultBoolean;
|
||||
import org.spongepowered.configurate.interfaces.meta.defaults.DefaultNumeric;
|
||||
@ -39,8 +40,9 @@ import org.spongepowered.configurate.interfaces.meta.range.NumericRange;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@ConfigSerializable
|
||||
@ -49,7 +51,9 @@ public interface GeyserConfig {
|
||||
|
||||
JavaConfig java();
|
||||
|
||||
Path floodgateKeyPath();
|
||||
// Cannot be type File yet because we want to hide it in plugin instances.
|
||||
@DefaultString("key.pem")
|
||||
String floodgateKeyFile();
|
||||
|
||||
@Comment("""
|
||||
For online mode authentication type only.
|
||||
@ -108,8 +112,9 @@ public interface GeyserConfig {
|
||||
https://cdn.discordapp.com/attachments/613170125696270357/957075682230419466/Screenshot_from_2022-03-25_20-35-08.png
|
||||
This can be disabled by going into Bedrock settings under the accessibility tab and setting "Text Background Opacity" to 0
|
||||
This setting can be set to "title", "actionbar" or "false\"""")
|
||||
@DefaultString("title")
|
||||
String showCooldown();
|
||||
default CooldownUtils.CooldownType showCooldown() {
|
||||
return CooldownUtils.CooldownType.TITLE;
|
||||
}
|
||||
|
||||
@Comment("Controls if coordinates are shown to players.")
|
||||
@DefaultBoolean(true)
|
||||
@ -118,9 +123,9 @@ public interface GeyserConfig {
|
||||
@Comment("Whether Bedrock players are blocked from performing their scaffolding-style bridging.")
|
||||
boolean disableBedrockScaffolding();
|
||||
|
||||
//@DefaultString("disabled")
|
||||
EmoteOffhandWorkaroundOption emoteOffhandWorkaround();
|
||||
|
||||
@Comment("The default locale if we don't have the one the client requested. If set to \"system\", the system's language will be used.")
|
||||
@NonNull
|
||||
@DefaultString("system")
|
||||
String defaultLocale();
|
||||
|
||||
@Comment("""
|
||||
@ -207,13 +212,15 @@ public interface GeyserConfig {
|
||||
@Override
|
||||
@Comment("The port that will listen for connections")
|
||||
@DefaultNumeric(19132)
|
||||
@NumericRange(from = 0, to = 65535)
|
||||
int port();
|
||||
|
||||
@Override
|
||||
@Comment("""
|
||||
The port to broadcast to Bedrock clients with the MOTD that they should use to connect to the server.
|
||||
DO NOT uncomment and change this unless Geyser runs on a different internal port than the one that is used to connect.""")
|
||||
DO NOT change this unless Geyser runs on a different internal port than the one that is used to connect.""")
|
||||
@DefaultNumeric(19132)
|
||||
@NumericRange(from = 0, to = 65535)
|
||||
int broadcastPort();
|
||||
|
||||
void address(String address);
|
||||
@ -223,13 +230,21 @@ public interface GeyserConfig {
|
||||
void broadcastPort(int broadcastPort);
|
||||
|
||||
@Override
|
||||
@Comment("""
|
||||
The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients. This is irrelevant if "passthrough-motd" is set to true.
|
||||
If either of these are empty, the respective string will default to "Geyser\"""")
|
||||
@DefaultString("Geyser")
|
||||
String primaryMotd();
|
||||
|
||||
@Override
|
||||
@DefaultString("Another Geyser server.") // TODO migrate or change name
|
||||
@DefaultString("Another Geyser server.")
|
||||
String secondaryMotd();
|
||||
|
||||
@Override
|
||||
@Comment("The Server Name that will be sent to Minecraft: Bedrock Edition clients. This is visible in both the pause menu and the settings menu.")
|
||||
@DefaultString("Geyser")
|
||||
String serverName();
|
||||
|
||||
@Comment("""
|
||||
How much to compress network traffic to the Bedrock client. The higher the number, the more CPU usage used, but
|
||||
the smaller the bandwidth used. Does not have any effect below -1 or above 9. Set to -1 to disable.""")
|
||||
@ -237,6 +252,9 @@ public interface GeyserConfig {
|
||||
@NumericRange(from = -1, to = 9)
|
||||
int compressionLevel();
|
||||
|
||||
@Comment("""
|
||||
Whether to enable PROXY protocol or not for clients. You DO NOT WANT this feature unless you run UDP reverse proxy
|
||||
in front of your Geyser instance.""")
|
||||
@DefaultBoolean
|
||||
boolean enableProxyProtocol();
|
||||
|
||||
@ -245,13 +263,9 @@ public interface GeyserConfig {
|
||||
should really only be used when you are not able to use a proper firewall (usually true with shared hosting providers etc.).
|
||||
Keeping this list empty means there is no IP address whitelist.
|
||||
IP addresses, subnets, and links to plain text files are supported.""")
|
||||
List<String> proxyProtocolWhitelistedIPs();
|
||||
|
||||
// /**
|
||||
// * @return Unmodifiable list of {@link CIDRMatcher}s from {@link #proxyProtocolWhitelistedIPs()}
|
||||
// */
|
||||
// @Exclude
|
||||
// List<CIDRMatcher> whitelistedIPsMatchers();
|
||||
default List<String> proxyProtocolWhitelistedIps() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
@ -270,6 +284,8 @@ public interface GeyserConfig {
|
||||
return AuthType.ONLINE;
|
||||
}
|
||||
|
||||
void authType(AuthType authType);
|
||||
|
||||
@Comment("""
|
||||
Whether to enable PROXY protocol or not while connecting to the server.
|
||||
This is useful only when:
|
||||
@ -297,17 +313,16 @@ public interface GeyserConfig {
|
||||
default boolean resolveSrv() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void authType(AuthType authType);
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
interface MetricsInfo {
|
||||
|
||||
@Comment("If metrics should be enabled")
|
||||
@DefaultBoolean(true)
|
||||
boolean enabled();
|
||||
|
||||
default UUID uniqueId() { //TODO rename?
|
||||
@Comment("UUID of server. Don't change!")
|
||||
default UUID uuid() { //TODO rename?
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
}
|
||||
@ -333,7 +348,15 @@ public interface GeyserConfig {
|
||||
int mtu();
|
||||
|
||||
@Comment("Do not change!")
|
||||
default int version() {
|
||||
default int configVersion() {
|
||||
return Constants.CONFIG_VERSION;
|
||||
}
|
||||
|
||||
@Exclude
|
||||
default Optional<GeyserPluginConfig> asPluginConfig() {
|
||||
if (this instanceof GeyserPluginConfig config) {
|
||||
return Optional.of(config);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ import org.spongepowered.configurate.interfaces.meta.defaults.DefaultBoolean;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ConfigSerializable
|
||||
public interface GeyserPluginConfig extends GeyserConfig {
|
||||
@Override
|
||||
@ -89,6 +91,10 @@ public interface GeyserPluginConfig extends GeyserConfig {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Hidden
|
||||
String floodgateKeyFile();
|
||||
|
||||
@Comment("""
|
||||
Use server API methods to determine the Java server's MOTD and ping passthrough.
|
||||
There is no need to disable this unless your MOTD or player count does not appear properly.""")
|
||||
|
@ -25,10 +25,9 @@
|
||||
|
||||
package org.geysermc.geyser.configuration;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.spongepowered.configurate.interfaces.meta.defaults.DefaultNumeric;
|
||||
import org.spongepowered.configurate.interfaces.meta.defaults.DefaultString;
|
||||
import org.spongepowered.configurate.interfaces.meta.range.NumericRange;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
|
||||
@ -37,12 +36,17 @@ import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
*/
|
||||
@ConfigSerializable
|
||||
public interface GeyserRemoteConfig extends GeyserConfig {
|
||||
// @Override // For config placement
|
||||
// BedrockConfig bedrock();
|
||||
|
||||
@Override
|
||||
RemoteConfig java();
|
||||
|
||||
@Override
|
||||
@Comment("""
|
||||
Floodgate uses encryption to ensure use from authorized sources.
|
||||
This should point to the public key generated by Floodgate (BungeeCord, Spigot or Velocity)
|
||||
You can ignore this when not using Floodgate.
|
||||
If you're using a plugin version of Floodgate on the same server, the key will automatically be picked up from Floodgate.""")
|
||||
String floodgateKeyFile();
|
||||
|
||||
@ConfigSerializable
|
||||
interface RemoteConfig extends JavaConfig {
|
||||
@Override
|
||||
@ -53,13 +57,9 @@ public interface GeyserRemoteConfig extends GeyserConfig {
|
||||
@Override
|
||||
@Comment("The port of the Java Edition server.")
|
||||
@DefaultNumeric(25565)
|
||||
@NumericRange(from = 0, to = 65535)
|
||||
int port();
|
||||
|
||||
@Override // For config placement
|
||||
default @NonNull AuthType authType() {
|
||||
return JavaConfig.super.authType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Comment("""
|
||||
Forward the hostname that the Bedrock client used to connect over to the Java server
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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.geyser.configuration;
|
||||
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.Scalars;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Ensures enum values are written to lowercase. {@link Scalars#ENUM} will read enum values
|
||||
* in any case.
|
||||
*/
|
||||
final class LowercaseEnumSerializer extends ScalarSerializer<Enum<?>> {
|
||||
LowercaseEnumSerializer() {
|
||||
super(new TypeToken<Enum<?>>() {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum<?> deserialize(Type type, Object obj) throws SerializationException {
|
||||
return Scalars.ENUM.deserialize(type, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(Enum<?> item, Predicate<Class<?>> typeSupported) {
|
||||
return item.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
@ -25,13 +25,12 @@
|
||||
|
||||
package org.geysermc.geyser.dump;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
@ -41,7 +40,7 @@ import org.geysermc.floodgate.util.FloodgateInfoHolder;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.GeyserApi;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||
@ -57,12 +56,16 @@ import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class DumpInfo {
|
||||
@JsonIgnore
|
||||
private static final long MEGABYTE = 1024L * 1024L;
|
||||
|
||||
private final DumpInfo.VersionInfo versionInfo;
|
||||
@ -71,7 +74,7 @@ public class DumpInfo {
|
||||
private final Locale systemLocale;
|
||||
private final String systemEncoding;
|
||||
private final GitInfo gitInfo;
|
||||
private final GeyserConfiguration config;
|
||||
private final GeyserConfig config;
|
||||
private final Floodgate floodgate;
|
||||
private final Object2IntMap<DeviceOs> userPlatforms;
|
||||
private final int connectionAttempts;
|
||||
@ -92,7 +95,7 @@ public class DumpInfo {
|
||||
|
||||
this.gitInfo = new GitInfo(GeyserImpl.BUILD_NUMBER, GeyserImpl.COMMIT.substring(0, 7), GeyserImpl.COMMIT, GeyserImpl.BRANCH, GeyserImpl.REPOSITORY);
|
||||
|
||||
this.config = GeyserImpl.getInstance().getConfig();
|
||||
this.config = GeyserImpl.getInstance().config();
|
||||
this.floodgate = new Floodgate();
|
||||
|
||||
String md5Hash = "unknown";
|
||||
@ -108,7 +111,7 @@ public class DumpInfo {
|
||||
//noinspection UnstableApiUsage
|
||||
sha256Hash = byteSource.hash(Hashing.sha256()).toString();
|
||||
} catch (Exception e) {
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -280,7 +283,7 @@ public class DumpInfo {
|
||||
public record ExtensionInfo(boolean enabled, String name, String version, String apiVersion, String main, List<String> authors) {
|
||||
}
|
||||
|
||||
public record GitInfo(String buildNumber, @JsonProperty("git.commit.id.abbrev") String commitHashAbbrev, @JsonProperty("git.commit.id") String commitHash,
|
||||
@JsonProperty("git.branch") String branchName, @JsonProperty("git.remote.origin.url") String originUrl) {
|
||||
public record GitInfo(String buildNumber, @SerializedName("git.commit.id.abbrev") String commitHashAbbrev, @SerializedName("git.commit.id") String commitHash,
|
||||
@SerializedName("git.branch") String branchName, @SerializedName("git.remote.origin.url") String originUrl) {
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public record EntityDefinition<T extends Entity>(EntityFactory<T> factory, Entit
|
||||
|
||||
if (translator.acceptedType() != metadata.getType()) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Metadata ID " + metadata.getId() + " was received with type " + metadata.getType() + " but we expected " + translator.acceptedType() + " for " + entity.getDefinition().entityType());
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
GeyserImpl.getInstance().getLogger().debug(metadata.toString());
|
||||
}
|
||||
return;
|
||||
|
@ -185,7 +185,7 @@ public class Entity implements GeyserEntity {
|
||||
|
||||
flagsDirty = false;
|
||||
|
||||
if (session.getGeyser().getConfig().isDebugMode() && PRINT_ENTITY_SPAWN_DEBUG) {
|
||||
if (session.getGeyser().config().debugMode() && PRINT_ENTITY_SPAWN_DEBUG) {
|
||||
EntityType type = definition.entityType();
|
||||
String name = type != null ? type.name() : getClass().getSimpleName();
|
||||
session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
|
||||
|
@ -342,7 +342,7 @@ public final class ClickPlan {
|
||||
} else if (action.click.actionType == ContainerActionType.MOVE_TO_HOTBAR_SLOT) {
|
||||
stateIdIncrements = 1;
|
||||
} else {
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
session.getGeyser().getLogger().debug("Not sure how to handle state ID hack in crafting table: " + plan);
|
||||
}
|
||||
stateIdIncrements = 1;
|
||||
|
@ -90,7 +90,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
super(geyser, session);
|
||||
|
||||
ZlibCompression compression = new ZlibCompression(Zlib.RAW);
|
||||
compression.setLevel(this.geyser.getConfig().getBedrock().getCompressionLevel());
|
||||
compression.setLevel(this.geyser.config().bedrock().compressionLevel());
|
||||
this.compressionStrategy = new SimpleCompressionStrategy(compression);
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(),
|
||||
"", header.uuid().toString(), false, false));
|
||||
}
|
||||
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
|
||||
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().config().forceResourcePacks());
|
||||
session.sendUpstreamPacket(resourcePacksInfo);
|
||||
|
||||
GeyserLocale.loadGeyserLocale(session.locale());
|
||||
@ -222,7 +222,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
|
||||
switch (packet.getStatus()) {
|
||||
case COMPLETED:
|
||||
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
|
||||
if (geyser.config().java().authType() != AuthType.ONLINE) {
|
||||
session.authenticate(session.getAuthData().name());
|
||||
} else if (!couldLoginUserByName(session.getAuthData().name())) {
|
||||
// We must spawn the white world
|
||||
@ -247,7 +247,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.uuid().toString(), header.version().toString(), ""));
|
||||
}
|
||||
|
||||
if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
if (GeyserImpl.getInstance().config().addNonBedrockItems()) {
|
||||
// Allow custom items to work
|
||||
stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true));
|
||||
}
|
||||
@ -273,7 +273,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
}
|
||||
|
||||
private boolean couldLoginUserByName(String bedrockUsername) {
|
||||
if (geyser.getConfig().getSavedUserLogins().contains(bedrockUsername)) {
|
||||
if (geyser.config().savedUserLogins().contains(bedrockUsername)) {
|
||||
String refreshToken = geyser.refreshTokenFor(bedrockUsername);
|
||||
if (refreshToken != null) {
|
||||
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name()));
|
||||
|
@ -27,7 +27,7 @@ package org.geysermc.geyser.network.netty;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.geyser.GeyserBootstrap;
|
||||
import org.geysermc.geyser.GeyserPluginBootstrap;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
|
||||
@ -49,8 +49,8 @@ public abstract class GeyserInjector {
|
||||
/**
|
||||
* @param bootstrap the bootstrap of the Geyser instance.
|
||||
*/
|
||||
public void initializeLocalChannel(GeyserBootstrap bootstrap) {
|
||||
if (!bootstrap.getGeyserConfig().isUseDirectConnection()) {
|
||||
public void initializeLocalChannel(GeyserPluginBootstrap bootstrap) {
|
||||
if (!bootstrap.config().useDirectConnection()) {
|
||||
bootstrap.getGeyserLogger().debug("Disabling direct injection!");
|
||||
return;
|
||||
}
|
||||
@ -71,9 +71,9 @@ public abstract class GeyserInjector {
|
||||
}
|
||||
|
||||
/**
|
||||
* The method to implement that is called by {@link #initializeLocalChannel(GeyserBootstrap)} wrapped around a try/catch.
|
||||
* The method to implement that is called by {@link #initializeLocalChannel(GeyserPluginBootstrap)} wrapped around a try/catch.
|
||||
*/
|
||||
protected abstract void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception;
|
||||
protected abstract void initializeLocalChannel0(GeyserPluginBootstrap bootstrap) throws Exception;
|
||||
|
||||
public void shutdown() {
|
||||
if (localChannel != null && localChannel.channel().isOpen()) {
|
||||
|
@ -53,7 +53,7 @@ import org.cloudburstmc.protocol.bedrock.BedrockPong;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.event.connection.ConnectionRequestEvent;
|
||||
import org.geysermc.geyser.command.defaults.ConnectionTestCommand;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.event.type.GeyserBedrockPingEventImpl;
|
||||
import org.geysermc.geyser.network.CIDRMatcher;
|
||||
import org.geysermc.geyser.network.GameProtocol;
|
||||
@ -66,14 +66,18 @@ import org.geysermc.geyser.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.geyser.skin.SkinProvider;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.WebUtils;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT;
|
||||
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_PACKET_LIMIT;
|
||||
@ -135,7 +139,7 @@ public final class GeyserServer {
|
||||
this.listenCount = 1;
|
||||
}
|
||||
|
||||
if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
||||
if (this.geyser.config().bedrock().enableProxyProtocol()) {
|
||||
this.proxiedAddresses = ExpiringMap.builder()
|
||||
.expiration(30 + 1, TimeUnit.MINUTES)
|
||||
.expirationPolicy(ExpirationPolicy.ACCESSED).build();
|
||||
@ -144,11 +148,11 @@ public final class GeyserServer {
|
||||
}
|
||||
|
||||
// It's set to 0 only if no system property or manual config value was set
|
||||
if (geyser.getConfig().getBedrock().broadcastPort() == 0) {
|
||||
geyser.getConfig().getBedrock().setBroadcastPort(geyser.getConfig().getBedrock().port());
|
||||
if (geyser.config().bedrock().broadcastPort() == 0) {
|
||||
geyser.config().bedrock().broadcastPort(geyser.config().bedrock().port());
|
||||
}
|
||||
|
||||
this.broadcastPort = geyser.getConfig().getBedrock().broadcastPort();
|
||||
this.broadcastPort = geyser.config().bedrock().broadcastPort();
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> bind(InetSocketAddress address) {
|
||||
@ -170,12 +174,12 @@ public final class GeyserServer {
|
||||
.addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this));
|
||||
|
||||
// Add proxy handler
|
||||
boolean isProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol();
|
||||
boolean isProxyProtocol = this.geyser.config().bedrock().enableProxyProtocol();
|
||||
if (isProxyProtocol) {
|
||||
channel.pipeline().addFirst("proxy-protocol-decoder", new ProxyServerHandler());
|
||||
}
|
||||
|
||||
boolean isWhitelistedProxyProtocol = isProxyProtocol && !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty();
|
||||
boolean isWhitelistedProxyProtocol = isProxyProtocol && !this.geyser.config().bedrock().proxyProtocolWhitelistedIps().isEmpty();
|
||||
if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) {
|
||||
// We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter
|
||||
channel.pipeline().remove(RakServerRateLimiter.NAME);
|
||||
@ -205,7 +209,7 @@ public final class GeyserServer {
|
||||
}
|
||||
|
||||
private ServerBootstrap createBootstrap() {
|
||||
if (this.geyser.getConfig().isDebugMode()) {
|
||||
if (this.geyser.config().debugMode()) {
|
||||
this.geyser.getLogger().debug("EventLoop type: " + TRANSPORT.datagramChannel());
|
||||
if (TRANSPORT.datagramChannel() == NioDatagramChannel.class) {
|
||||
if (System.getProperties().contains("disableNativeEventLoop")) {
|
||||
@ -220,7 +224,7 @@ public final class GeyserServer {
|
||||
|
||||
GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser);
|
||||
playerGroup = serverInitializer.getEventLoopGroup();
|
||||
this.geyser.getLogger().debug("Setting MTU to " + this.geyser.getConfig().getMtu());
|
||||
this.geyser.getLogger().debug("Setting MTU to " + this.geyser.config().mtu());
|
||||
|
||||
int rakPacketLimit = positivePropOrDefault("Geyser.RakPacketLimit", DEFAULT_PACKET_LIMIT);
|
||||
this.geyser.getLogger().debug("Setting RakNet packet limit to " + rakPacketLimit);
|
||||
@ -235,7 +239,7 @@ public final class GeyserServer {
|
||||
.channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel()))
|
||||
.group(group, childGroup)
|
||||
.option(RakChannelOption.RAK_HANDLE_PING, true)
|
||||
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu())
|
||||
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.config().mtu())
|
||||
.option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit)
|
||||
.option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit)
|
||||
.option(RakChannelOption.RAK_SEND_COOKIE, rakSendCookie)
|
||||
@ -243,10 +247,10 @@ public final class GeyserServer {
|
||||
}
|
||||
|
||||
public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) {
|
||||
List<String> allowedProxyIPs = geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs();
|
||||
if (geyser.getConfig().getBedrock().isEnableProxyProtocol() && !allowedProxyIPs.isEmpty()) {
|
||||
List<String> allowedProxyIPs = geyser.config().bedrock().proxyProtocolWhitelistedIps();
|
||||
if (geyser.config().bedrock().enableProxyProtocol() && !allowedProxyIPs.isEmpty()) {
|
||||
boolean isWhitelistedIP = false;
|
||||
for (CIDRMatcher matcher : geyser.getConfig().getBedrock().getWhitelistedIPsMatchers()) {
|
||||
for (CIDRMatcher matcher : getWhitelistedIPsMatchers()) {
|
||||
if (matcher.matches(inetSocketAddress.getAddress())) {
|
||||
isWhitelistedIP = true;
|
||||
break;
|
||||
@ -260,8 +264,8 @@ public final class GeyserServer {
|
||||
}
|
||||
|
||||
String ip;
|
||||
if (geyser.getConfig().isLogPlayerIpAddresses()) {
|
||||
if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
||||
if (geyser.config().logPlayerIpAddresses()) {
|
||||
if (geyser.config().bedrock().enableProxyProtocol()) {
|
||||
ip = this.proxiedAddresses.getOrDefault(inetSocketAddress, inetSocketAddress).toString();
|
||||
} else {
|
||||
ip = inetSocketAddress.toString();
|
||||
@ -287,10 +291,10 @@ public final class GeyserServer {
|
||||
}
|
||||
|
||||
public BedrockPong onQuery(Channel channel, InetSocketAddress inetSocketAddress) {
|
||||
if (geyser.getConfig().isDebugMode() && PRINT_DEBUG_PINGS) {
|
||||
if (geyser.config().debugMode() && PRINT_DEBUG_PINGS) {
|
||||
String ip;
|
||||
if (geyser.getConfig().isLogPlayerIpAddresses()) {
|
||||
if (geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
||||
if (geyser.config().logPlayerIpAddresses()) {
|
||||
if (geyser.config().bedrock().enableProxyProtocol()) {
|
||||
ip = this.proxiedAddresses.getOrDefault(inetSocketAddress, inetSocketAddress).toString();
|
||||
} else {
|
||||
ip = inetSocketAddress.toString();
|
||||
@ -301,10 +305,10 @@ public final class GeyserServer {
|
||||
geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.pinged", ip));
|
||||
}
|
||||
|
||||
GeyserConfiguration config = geyser.getConfig();
|
||||
GeyserConfig config = geyser.config();
|
||||
|
||||
GeyserPingInfo pingInfo = null;
|
||||
if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) {
|
||||
if (config.passthroughMotd() || config.passthroughPlayerCounts()) {
|
||||
IGeyserPingPassthrough pingPassthrough = geyser.getBootstrap().getGeyserPingPassthrough();
|
||||
if (pingPassthrough != null) {
|
||||
pingInfo = pingPassthrough.getPingInformation(inetSocketAddress);
|
||||
@ -321,25 +325,25 @@ public final class GeyserServer {
|
||||
.ipv6Port(this.broadcastPort)
|
||||
.serverId(channel.config().getOption(RakChannelOption.RAK_GUID));
|
||||
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
|
||||
if (config.passthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
|
||||
String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n");
|
||||
String mainMotd = (motd.length > 0) ? motd[0] : config.getBedrock().primaryMotd(); // First line of the motd.
|
||||
String subMotd = (motd.length > 1) ? motd[1] : config.getBedrock().secondaryMotd(); // Second line of the motd if present, otherwise default.
|
||||
String mainMotd = (motd.length > 0) ? motd[0] : config.bedrock().primaryMotd(); // First line of the motd.
|
||||
String subMotd = (motd.length > 1) ? motd[1] : config.bedrock().secondaryMotd(); // Second line of the motd if present, otherwise default.
|
||||
|
||||
pong.motd(mainMotd.trim());
|
||||
pong.subMotd(subMotd.trim()); // Trimmed to shift it to the left, prevents the universe from collapsing on us just because we went 2 characters over the text box's limit.
|
||||
} else {
|
||||
pong.motd(config.getBedrock().primaryMotd());
|
||||
pong.subMotd(config.getBedrock().secondaryMotd());
|
||||
pong.motd(config.bedrock().primaryMotd());
|
||||
pong.subMotd(config.bedrock().secondaryMotd());
|
||||
}
|
||||
|
||||
// Placed here to prevent overriding values set in the ping event.
|
||||
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
if (config.passthroughPlayerCounts() && pingInfo != null) {
|
||||
pong.playerCount(pingInfo.getPlayers().getOnline());
|
||||
pong.maximumPlayerCount(pingInfo.getPlayers().getMax());
|
||||
} else {
|
||||
pong.playerCount(geyser.getSessionManager().getSessions().size());
|
||||
pong.maximumPlayerCount(config.getMaxPlayers());
|
||||
pong.maximumPlayerCount(config.maxPlayers());
|
||||
}
|
||||
|
||||
this.geyser.eventBus().fire(new GeyserBedrockPingEventImpl(pong, inetSocketAddress));
|
||||
@ -390,6 +394,35 @@ public final class GeyserServer {
|
||||
return pong;
|
||||
}
|
||||
|
||||
private List<CIDRMatcher> whitelistedIPsMatchers = null;
|
||||
|
||||
/**
|
||||
* @return Unmodifiable list of {@link CIDRMatcher}s from {@link GeyserConfig.BedrockConfig#proxyProtocolWhitelistedIps()}
|
||||
*/
|
||||
public List<CIDRMatcher> getWhitelistedIPsMatchers() {
|
||||
// Effective Java, Third Edition; Item 83: Use lazy initialization judiciously
|
||||
List<CIDRMatcher> matchers = this.whitelistedIPsMatchers;
|
||||
if (matchers == null) {
|
||||
synchronized (this) {
|
||||
// Check if proxyProtocolWhitelistedIPs contains URLs we need to fetch and parse by line
|
||||
List<String> whitelistedCIDRs = new ArrayList<>();
|
||||
for (String ip: geyser.config().bedrock().proxyProtocolWhitelistedIps()) {
|
||||
if (!ip.startsWith("http")) {
|
||||
whitelistedCIDRs.add(ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
WebUtils.getLineStream(ip).forEach(whitelistedCIDRs::add);
|
||||
}
|
||||
|
||||
this.whitelistedIPsMatchers = matchers = whitelistedCIDRs.stream()
|
||||
.map(CIDRMatcher::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(matchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the throwable from the given supplier, or the throwable caught while calling the supplier.
|
||||
*/
|
||||
|
@ -78,7 +78,7 @@ public class SkullResourcePackManager {
|
||||
|
||||
Path packPath = cachePath.resolve("player_skulls.mcpack");
|
||||
File packFile = packPath.toFile();
|
||||
if (BlockRegistries.CUSTOM_SKULLS.get().isEmpty() || !GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
if (BlockRegistries.CUSTOM_SKULLS.get().isEmpty() || !GeyserImpl.getInstance().config().addNonBedrockItems()) {
|
||||
packFile.delete(); // No need to keep resource pack
|
||||
return null;
|
||||
}
|
||||
@ -161,7 +161,7 @@ public class SkullResourcePackManager {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unable to clean up skull skin cache.");
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -65,10 +65,10 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
||||
* @return GeyserPingPassthrough, or null if not initialized
|
||||
*/
|
||||
public static @Nullable IGeyserPingPassthrough init(GeyserImpl geyser) {
|
||||
if (geyser.getConfig().isPassthroughMotd() || geyser.getConfig().isPassthroughPlayerCounts()) {
|
||||
if (geyser.config().passthroughMotd() || geyser.config().passthroughPlayerCounts()) {
|
||||
GeyserLegacyPingPassthrough pingPassthrough = new GeyserLegacyPingPassthrough(geyser);
|
||||
// Ensure delay is not zero
|
||||
int interval = (geyser.getConfig().getPingPassthroughInterval() == 0) ? 1 : geyser.getConfig().getPingPassthroughInterval();
|
||||
int interval = (geyser.config().pingPassthroughInterval() == 0) ? 1 : geyser.config().pingPassthroughInterval();
|
||||
geyser.getLogger().debug("Scheduling ping passthrough at an interval of " + interval + " second(s).");
|
||||
geyser.getScheduledThread().scheduleAtFixedRate(pingPassthrough, 1, interval, TimeUnit.SECONDS);
|
||||
return pingPassthrough;
|
||||
@ -84,8 +84,8 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
||||
@Override
|
||||
public void run() {
|
||||
try (Socket socket = new Socket()) {
|
||||
String address = geyser.getConfig().getRemote().address();
|
||||
int port = geyser.getConfig().getRemote().port();
|
||||
String address = geyser.config().java().address();
|
||||
int port = geyser.config().java().port();
|
||||
InetSocketAddress endpoint = new InetSocketAddress(address, port);
|
||||
socket.connect(endpoint, 5000);
|
||||
|
||||
@ -102,7 +102,7 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
||||
byte[] buffer;
|
||||
|
||||
try (DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream())) {
|
||||
if (geyser.getConfig().getRemote().isUseProxyProtocol()) {
|
||||
if (geyser.config().java().useProxyProtocol()) {
|
||||
// HAProxy support
|
||||
// Based on https://github.com/netty/netty/blob/d8ad931488f6b942dabe28ecd6c399b4438da0a8/codec-haproxy/src/main/java/io/netty/handler/codec/haproxy/HAProxyMessageEncoder.java#L78
|
||||
dataOutputStream.write(HAPROXY_BINARY_PREFIX);
|
||||
|
@ -70,7 +70,7 @@ public class PacketTranslatorRegistry<T> extends AbstractMappedRegistry<Class<?
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
if (!IGNORED_PACKETS.contains(clazz)) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class CustomBlockRegistryPopulator {
|
||||
* @param stage the stage to populate
|
||||
*/
|
||||
public static void populate(Stage stage) {
|
||||
if (!GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
if (!GeyserImpl.getInstance().config().addNonBedrockItems()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class CustomSkullRegistryPopulator {
|
||||
SkullResourcePackManager.SKULL_SKINS.clear(); // Remove skins after reloading
|
||||
BlockRegistries.CUSTOM_SKULLS.set(Object2ObjectMaps.emptyMap());
|
||||
|
||||
if (!GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
if (!GeyserImpl.getInstance().config().addNonBedrockItems()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -65,7 +65,6 @@ public class CustomSkullRegistryPopulator {
|
||||
Path skullConfigPath = bootstrap.getConfigFolder().resolve("custom-skulls.yml");
|
||||
File skullConfigFile = FileUtils.fileOrCopiedFromResource(skullConfigPath.toFile(), "custom-skulls.yml", Function.identity(), bootstrap);
|
||||
skullConfig = FileUtils.loadConfigNew(skullConfigFile, GeyserCustomSkullConfiguration.class);
|
||||
System.out.println(skullConfig);
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), e);
|
||||
return;
|
||||
|
@ -129,7 +129,7 @@ public class ItemRegistryPopulator {
|
||||
throw new AssertionError("Unable to load Bedrock item components", e);
|
||||
}
|
||||
|
||||
boolean customItemsAllowed = GeyserImpl.getInstance().getConfig().isAddNonBedrockItems();
|
||||
boolean customItemsAllowed = GeyserImpl.getInstance().config().addNonBedrockItems();
|
||||
|
||||
// List values here is important compared to HashSet - we need to preserve the order of what's given to us
|
||||
// (as of 1.19.2 Java) to replicate some edge cases in Java predicate behavior where it checks from the bottom
|
||||
|
@ -28,7 +28,7 @@ package org.geysermc.geyser.scoreboard;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.configuration.GeyserConfig;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.WorldCache;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
@ -46,9 +46,9 @@ public final class ScoreboardUpdater extends Thread {
|
||||
private static final boolean DEBUG_ENABLED;
|
||||
|
||||
static {
|
||||
GeyserConfiguration config = GeyserImpl.getInstance().getConfig();
|
||||
FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD = Math.min(config.getScoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD);
|
||||
DEBUG_ENABLED = config.isDebugMode();
|
||||
GeyserConfig config = GeyserImpl.getInstance().config();
|
||||
FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD = Math.min(config.scoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD);
|
||||
DEBUG_ENABLED = config.debugMode();
|
||||
}
|
||||
|
||||
private final GeyserImpl geyser = GeyserImpl.getInstance();
|
||||
|
@ -46,17 +46,52 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.common.value.qual.IntRange;
|
||||
import org.cloudburstmc.math.vector.*;
|
||||
import org.cloudburstmc.math.vector.Vector2f;
|
||||
import org.cloudburstmc.math.vector.Vector2i;
|
||||
import org.cloudburstmc.math.vector.Vector3d;
|
||||
import org.cloudburstmc.math.vector.Vector3f;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons;
|
||||
import org.cloudburstmc.protocol.bedrock.BedrockServerSession;
|
||||
import org.cloudburstmc.protocol.bedrock.data.*;
|
||||
import org.cloudburstmc.protocol.bedrock.data.Ability;
|
||||
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
|
||||
import org.cloudburstmc.protocol.bedrock.data.AuthoritativeMovementMode;
|
||||
import org.cloudburstmc.protocol.bedrock.data.ChatRestrictionLevel;
|
||||
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.GamePublishSetting;
|
||||
import org.cloudburstmc.protocol.bedrock.data.GameRuleData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.GameType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
|
||||
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
|
||||
import org.cloudburstmc.protocol.bedrock.data.SpawnBiomeType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.*;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AvailableEntityIdentifiersPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BiomeDefinitionListPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CameraPresetsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.StartGamePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SyncEntityPropertyPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TransferPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAbilitiesPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAdventureSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateClientInputLocksPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateSoftEnumPacket;
|
||||
import org.cloudburstmc.protocol.common.DefinitionRegistry;
|
||||
import org.cloudburstmc.protocol.common.util.OptionalBoolean;
|
||||
import org.geysermc.api.util.BedrockPlatform;
|
||||
@ -80,7 +115,6 @@ import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.GeyserEntityData;
|
||||
@ -107,7 +141,22 @@ import org.geysermc.geyser.registry.type.BlockMappings;
|
||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||
import org.geysermc.geyser.session.auth.AuthData;
|
||||
import org.geysermc.geyser.session.auth.BedrockClientData;
|
||||
import org.geysermc.geyser.session.cache.*;
|
||||
import org.geysermc.geyser.session.cache.AdvancementsCache;
|
||||
import org.geysermc.geyser.session.cache.BookEditCache;
|
||||
import org.geysermc.geyser.session.cache.ChunkCache;
|
||||
import org.geysermc.geyser.session.cache.EntityCache;
|
||||
import org.geysermc.geyser.session.cache.EntityEffectCache;
|
||||
import org.geysermc.geyser.session.cache.FormCache;
|
||||
import org.geysermc.geyser.session.cache.LodestoneCache;
|
||||
import org.geysermc.geyser.session.cache.PistonCache;
|
||||
import org.geysermc.geyser.session.cache.PreferencesCache;
|
||||
import org.geysermc.geyser.session.cache.RegistryCache;
|
||||
import org.geysermc.geyser.session.cache.SkullCache;
|
||||
import org.geysermc.geyser.session.cache.StructureBlockCache;
|
||||
import org.geysermc.geyser.session.cache.TagCache;
|
||||
import org.geysermc.geyser.session.cache.TeleportCache;
|
||||
import org.geysermc.geyser.session.cache.WorldBorder;
|
||||
import org.geysermc.geyser.session.cache.WorldCache;
|
||||
import org.geysermc.geyser.skin.FloodgateSkinUploader;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.text.MinecraftLocale;
|
||||
@ -119,7 +168,11 @@ import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
||||
import org.geysermc.mcprotocollib.network.BuiltinFlags;
|
||||
import org.geysermc.mcprotocollib.network.Session;
|
||||
import org.geysermc.mcprotocollib.network.event.session.*;
|
||||
import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent;
|
||||
import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent;
|
||||
import org.geysermc.mcprotocollib.network.event.session.PacketErrorEvent;
|
||||
import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent;
|
||||
import org.geysermc.mcprotocollib.network.event.session.SessionAdapter;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
|
||||
@ -154,7 +207,16 @@ import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@ -600,12 +662,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
this.spawned = false;
|
||||
this.loggedIn = false;
|
||||
|
||||
if (geyser.getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
this.emotes = new HashSet<>();
|
||||
geyser.getSessionManager().getSessions().values().forEach(player -> this.emotes.addAll(player.getEmotes()));
|
||||
} else {
|
||||
this.emotes = null;
|
||||
}
|
||||
this.emotes = new HashSet<>();
|
||||
geyser.getSessionManager().getSessions().values().forEach(player -> this.emotes.addAll(player.getEmotes()));
|
||||
|
||||
this.remoteServer = geyser.defaultRemoteServer();
|
||||
}
|
||||
@ -618,7 +676,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
sentSpawnPacket = true;
|
||||
syncEntityProperties();
|
||||
|
||||
if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
if (GeyserImpl.getInstance().config().addNonBedrockItems()) {
|
||||
ItemComponentPacket componentPacket = new ItemComponentPacket();
|
||||
componentPacket.getItems().addAll(itemMappings.getComponentItemData());
|
||||
upstream.sendPacket(componentPacket);
|
||||
@ -870,11 +928,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
// Disable automatic creation of a new TcpClientSession when transferring - we don't use that functionality.
|
||||
this.downstream.getSession().setFlag(MinecraftConstants.FOLLOW_TRANSFERS, false);
|
||||
|
||||
if (geyser.getConfig().getRemote().isUseProxyProtocol()) {
|
||||
if (geyser.config().java().useProxyProtocol()) {
|
||||
downstream.setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true);
|
||||
downstream.setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress());
|
||||
}
|
||||
if (geyser.getConfig().isForwardPlayerPing()) {
|
||||
if (geyser.config().forwardPlayerPing()) {
|
||||
// Let Geyser handle sending the keep alive
|
||||
downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
|
||||
}
|
||||
@ -943,7 +1001,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
ClientIntentionPacket intentionPacket = event.getPacket();
|
||||
|
||||
String address;
|
||||
if (geyser.getConfig().getRemote().isForwardHost()) {
|
||||
if (geyser.config().java().forwardHostname()) {
|
||||
address = clientData.getServerAddress().split(":")[0];
|
||||
} else {
|
||||
address = intentionPacket.getHostname();
|
||||
@ -1035,7 +1093,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().error("An exception occurred: ", cause);
|
||||
}
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -1058,7 +1116,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
@Override
|
||||
public void packetError(PacketErrorEvent event) {
|
||||
geyser.getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.downstream_error", event.getCause().getMessage()));
|
||||
if (geyser.getConfig().isDebugMode())
|
||||
if (geyser.config().debugMode())
|
||||
event.getCause().printStackTrace();
|
||||
event.setSuppress(true);
|
||||
}
|
||||
@ -1090,7 +1148,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
} else {
|
||||
// Downstream's disconnect will fire an event that prints a log message
|
||||
// Otherwise, we print a message here
|
||||
String address = geyser.getConfig().isLogPlayerIpAddresses() ? upstream.getAddress().getAddress().toString() : "<IP address withheld>";
|
||||
String address = geyser.config().logPlayerIpAddresses() ? upstream.getAddress().getAddress().toString() : "<IP address withheld>";
|
||||
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, reason));
|
||||
}
|
||||
|
||||
@ -1482,7 +1540,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
||||
startGamePacket.setDifficulty(1);
|
||||
startGamePacket.setDefaultSpawn(Vector3i.ZERO);
|
||||
startGamePacket.setAchievementsDisabled(!geyser.getConfig().isXboxAchievementsEnabled());
|
||||
startGamePacket.setAchievementsDisabled(!geyser.config().xboxAchievementsEnabled());
|
||||
startGamePacket.setCurrentTick(-1);
|
||||
startGamePacket.setEduEditionOffers(0);
|
||||
startGamePacket.setEduFeaturesEnabled(false);
|
||||
@ -1492,7 +1550,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
startGamePacket.setBroadcastingToLan(true);
|
||||
startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC);
|
||||
startGamePacket.setCommandsEnabled(!geyser.getConfig().isXboxAchievementsEnabled());
|
||||
startGamePacket.setCommandsEnabled(!geyser.config().xboxAchievementsEnabled());
|
||||
startGamePacket.setTexturePacksRequired(false);
|
||||
startGamePacket.setBonusChestEnabled(false);
|
||||
startGamePacket.setStartingWithMap(false);
|
||||
@ -1510,7 +1568,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
startGamePacket.setEducationProductionId("");
|
||||
startGamePacket.setForceExperimentalGameplay(OptionalBoolean.empty());
|
||||
|
||||
String serverName = geyser.getConfig().getBedrock().serverName();
|
||||
String serverName = geyser.config().bedrock().serverName();
|
||||
startGamePacket.setLevelId(serverName);
|
||||
startGamePacket.setLevelName(serverName);
|
||||
|
||||
@ -1634,7 +1692,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
public void sendDownstreamPacket(Packet packet, ProtocolState intendedState) {
|
||||
// protocol can be null when we're not yet logged in (online auth)
|
||||
if (protocol == null) {
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
geyser.getLogger().debug("Tried to send downstream packet with no downstream session!");
|
||||
Thread.dumpStack();
|
||||
}
|
||||
@ -1660,7 +1718,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
if (channel == null) {
|
||||
// Channel is only null before the connection has initialized
|
||||
geyser.getLogger().warning("Tried to send a packet to the Java server too early!");
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
Thread.dumpStack();
|
||||
}
|
||||
return;
|
||||
@ -2051,7 +2109,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
|
||||
private void softEnumPacket(String name, SoftEnumUpdateType type, String enums) {
|
||||
// There is no need to send command enums if command suggestions are disabled
|
||||
if (!this.geyser.getConfig().isCommandSuggestions()) {
|
||||
if (!this.geyser.config().commandSuggestions()) {
|
||||
return;
|
||||
}
|
||||
UpdateSoftEnumPacket packet = new UpdateSoftEnumPacket();
|
||||
|
@ -25,93 +25,97 @@
|
||||
|
||||
package org.geysermc.geyser.session.auth;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.floodgate.util.DeviceOs;
|
||||
import org.geysermc.floodgate.util.InputMode;
|
||||
import org.geysermc.floodgate.util.UiProfile;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Getter
|
||||
public final class BedrockClientData {
|
||||
@JsonProperty(value = "GameVersion")
|
||||
@SerializedName(value = "GameVersion")
|
||||
private String gameVersion;
|
||||
@JsonProperty(value = "ServerAddress")
|
||||
@SerializedName(value = "ServerAddress")
|
||||
private String serverAddress;
|
||||
@JsonProperty(value = "ThirdPartyName")
|
||||
@SerializedName(value = "ThirdPartyName")
|
||||
private String username;
|
||||
@JsonProperty(value = "LanguageCode")
|
||||
@SerializedName(value = "LanguageCode")
|
||||
private String languageCode;
|
||||
|
||||
@JsonProperty(value = "SkinId")
|
||||
@SerializedName(value = "SkinId")
|
||||
private String skinId;
|
||||
@JsonProperty(value = "SkinData")
|
||||
@SerializedName(value = "SkinData")
|
||||
private String skinData;
|
||||
@JsonProperty(value = "SkinImageHeight")
|
||||
@SerializedName(value = "SkinImageHeight")
|
||||
private int skinImageHeight;
|
||||
@JsonProperty(value = "SkinImageWidth")
|
||||
@SerializedName(value = "SkinImageWidth")
|
||||
private int skinImageWidth;
|
||||
@JsonProperty(value = "CapeId")
|
||||
@SerializedName(value = "CapeId")
|
||||
private String capeId;
|
||||
@JsonProperty(value = "CapeData")
|
||||
@SerializedName(value = "CapeData")
|
||||
@JsonAdapter(value = StringToByteDeserializer.class)
|
||||
private byte[] capeData;
|
||||
@JsonProperty(value = "CapeImageHeight")
|
||||
@SerializedName(value = "CapeImageHeight")
|
||||
private int capeImageHeight;
|
||||
@JsonProperty(value = "CapeImageWidth")
|
||||
@SerializedName(value = "CapeImageWidth")
|
||||
private int capeImageWidth;
|
||||
@JsonProperty(value = "CapeOnClassicSkin")
|
||||
@SerializedName(value = "CapeOnClassicSkin")
|
||||
private boolean capeOnClassicSkin;
|
||||
@JsonProperty(value = "SkinResourcePatch")
|
||||
@SerializedName(value = "SkinResourcePatch")
|
||||
private String geometryName;
|
||||
@JsonProperty(value = "SkinGeometryData")
|
||||
@SerializedName(value = "SkinGeometryData")
|
||||
private String geometryData;
|
||||
@JsonProperty(value = "PersonaSkin")
|
||||
@SerializedName(value = "PersonaSkin")
|
||||
private boolean personaSkin;
|
||||
@JsonProperty(value = "PremiumSkin")
|
||||
@SerializedName(value = "PremiumSkin")
|
||||
private boolean premiumSkin;
|
||||
|
||||
@JsonProperty(value = "DeviceId")
|
||||
@SerializedName(value = "DeviceId")
|
||||
private String deviceId;
|
||||
@JsonProperty(value = "DeviceModel")
|
||||
@SerializedName(value = "DeviceModel")
|
||||
private String deviceModel;
|
||||
@JsonProperty(value = "DeviceOS")
|
||||
@SerializedName(value = "DeviceOS")
|
||||
private DeviceOs deviceOs;
|
||||
@JsonProperty(value = "UIProfile")
|
||||
@SerializedName(value = "UIProfile")
|
||||
private UiProfile uiProfile;
|
||||
@JsonProperty(value = "GuiScale")
|
||||
@SerializedName(value = "GuiScale")
|
||||
private int guiScale;
|
||||
@JsonProperty(value = "CurrentInputMode")
|
||||
@SerializedName(value = "CurrentInputMode")
|
||||
private InputMode currentInputMode;
|
||||
@JsonProperty(value = "DefaultInputMode")
|
||||
@SerializedName(value = "DefaultInputMode")
|
||||
private InputMode defaultInputMode;
|
||||
@JsonProperty("PlatformOnlineId")
|
||||
@SerializedName("PlatformOnlineId")
|
||||
private String platformOnlineId;
|
||||
@JsonProperty(value = "PlatformOfflineId")
|
||||
@SerializedName(value = "PlatformOfflineId")
|
||||
private String platformOfflineId;
|
||||
@JsonProperty(value = "SelfSignedId")
|
||||
@SerializedName(value = "SelfSignedId")
|
||||
private UUID selfSignedId;
|
||||
@JsonProperty(value = "ClientRandomId")
|
||||
@SerializedName(value = "ClientRandomId")
|
||||
private long clientRandomId;
|
||||
|
||||
@JsonProperty(value = "ArmSize")
|
||||
@SerializedName(value = "ArmSize")
|
||||
private String armSize;
|
||||
@JsonProperty(value = "SkinAnimationData")
|
||||
@SerializedName(value = "SkinAnimationData")
|
||||
private String skinAnimationData;
|
||||
@JsonProperty(value = "SkinColor")
|
||||
@SerializedName(value = "SkinColor")
|
||||
private String skinColor;
|
||||
@JsonProperty(value = "ThirdPartyNameOnly")
|
||||
@SerializedName(value = "ThirdPartyNameOnly")
|
||||
private boolean thirdPartyNameOnly;
|
||||
@JsonProperty(value = "PlayFabId")
|
||||
@SerializedName(value = "PlayFabId")
|
||||
private String playFabId;
|
||||
|
||||
@JsonIgnore
|
||||
@Setter
|
||||
private String originalString = null;
|
||||
private transient String originalString = null;
|
||||
|
||||
public DeviceOs getDeviceOs() {
|
||||
return deviceOs != null ? deviceOs : DeviceOs.UNKNOWN;
|
||||
@ -128,4 +132,11 @@ public final class BedrockClientData {
|
||||
public UiProfile getUiProfile() {
|
||||
return uiProfile != null ? uiProfile : UiProfile.CLASSIC;
|
||||
}
|
||||
|
||||
private static final class StringToByteDeserializer implements JsonDeserializer<byte[]> {
|
||||
@Override
|
||||
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return json.getAsString().getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,15 +54,16 @@ public class PreferencesCache {
|
||||
private boolean prefersCustomSkulls;
|
||||
|
||||
/**
|
||||
* Which CooldownType the client prefers. Initially set to {@link CooldownUtils#getDefaultShowCooldown()}.
|
||||
* Which CooldownType the client prefers. Initially set to the config default.
|
||||
*/
|
||||
@Setter
|
||||
private CooldownUtils.CooldownType cooldownPreference = CooldownUtils.getDefaultShowCooldown();
|
||||
private CooldownUtils.CooldownType cooldownPreference;
|
||||
|
||||
public PreferencesCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
||||
prefersCustomSkulls = session.getGeyser().getConfig().isAllowCustomSkulls();
|
||||
prefersCustomSkulls = session.getGeyser().config().allowCustomSkulls();
|
||||
cooldownPreference = session.getGeyser().config().showCooldown();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +75,7 @@ public class PreferencesCache {
|
||||
* {@link GeyserConfiguration#isShowCoordinates()} is disabled
|
||||
*/
|
||||
public void updateShowCoordinates() {
|
||||
allowShowCoordinates = !session.isReducedDebugInfo() && session.getGeyser().getConfig().isShowCoordinates();
|
||||
allowShowCoordinates = !session.isReducedDebugInfo() && session.getGeyser().config().showCoordinates();
|
||||
session.sendGameRule("showcoordinates", allowShowCoordinates && prefersShowCoordinates);
|
||||
}
|
||||
|
||||
@ -82,6 +83,6 @@ public class PreferencesCache {
|
||||
* @return true if the session prefers custom skulls, and the config allows them.
|
||||
*/
|
||||
public boolean showCustomSkulls() {
|
||||
return prefersCustomSkulls && session.getGeyser().getConfig().isAllowCustomSkulls();
|
||||
return prefersCustomSkulls && session.getGeyser().config().allowCustomSkulls();
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +74,11 @@ public class SkullCache {
|
||||
|
||||
public SkullCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
this.maxVisibleSkulls = session.getGeyser().getConfig().getMaxVisibleCustomSkulls();
|
||||
this.maxVisibleSkulls = session.getGeyser().config().maxVisibleCustomSkulls();
|
||||
this.cullingEnabled = this.maxVisibleSkulls != -1;
|
||||
|
||||
// Normal skulls are not rendered beyond 64 blocks
|
||||
int distance = Math.min(session.getGeyser().getConfig().getCustomSkullRenderDistance(), 64);
|
||||
int distance = Math.min(session.getGeyser().config().customSkullRenderDistance(), 64);
|
||||
this.skullRenderDistanceSquared = distance * distance;
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class SkullCache {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
session.getGeyser().getLogger().debug("Player skull with invalid Skin tag: " + position + " Textures: " + texturesProperty);
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,9 @@
|
||||
|
||||
package org.geysermc.geyser.skin;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.floodgate.pluginmessage.PluginMessageChannels;
|
||||
import org.geysermc.floodgate.util.WebsocketEventType;
|
||||
@ -37,6 +35,7 @@ import org.geysermc.geyser.Constants;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.JsonUtils;
|
||||
import org.geysermc.geyser.util.PluginMessageUtils;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
@ -52,7 +51,6 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class FloodgateSkinUploader {
|
||||
private final ObjectMapper JACKSON = new ObjectMapper();
|
||||
private final List<String> skinQueue = new ArrayList<>();
|
||||
|
||||
private final GeyserLogger logger;
|
||||
@ -79,15 +77,14 @@ public final class FloodgateSkinUploader {
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
// The reason why I don't like Jackson
|
||||
try {
|
||||
JsonNode node = JACKSON.readTree(message);
|
||||
JsonObject node = JsonUtils.parseJson(message);
|
||||
if (node.has("error")) {
|
||||
logger.error("Got an error: " + node.get("error").asText());
|
||||
logger.error("Got an error: " + node.get("error").getAsString());
|
||||
return;
|
||||
}
|
||||
|
||||
int typeId = node.get("event_id").asInt();
|
||||
int typeId = node.get("event_id").getAsInt();
|
||||
WebsocketEventType type = WebsocketEventType.fromId(typeId);
|
||||
if (type == null) {
|
||||
logger.warning(String.format(
|
||||
@ -98,11 +95,11 @@ public final class FloodgateSkinUploader {
|
||||
|
||||
switch (type) {
|
||||
case SUBSCRIBER_CREATED:
|
||||
id = node.get("id").asInt();
|
||||
verifyCode = node.get("verify_code").asText();
|
||||
id = node.get("id").getAsInt();
|
||||
verifyCode = node.get("verify_code").getAsString();
|
||||
break;
|
||||
case SUBSCRIBER_COUNT:
|
||||
subscribersCount = node.get("subscribers_count").asInt();
|
||||
subscribersCount = node.get("subscribers_count").getAsInt();
|
||||
break;
|
||||
case SKIN_UPLOADED:
|
||||
// if Geyser is the only subscriber we have send it to the server manually
|
||||
@ -111,19 +108,19 @@ public final class FloodgateSkinUploader {
|
||||
break;
|
||||
}
|
||||
|
||||
String xuid = node.get("xuid").asText();
|
||||
String xuid = node.get("xuid").getAsString();
|
||||
GeyserSession session = geyser.connectionByXuid(xuid);
|
||||
|
||||
if (session != null) {
|
||||
if (!node.get("success").asBoolean()) {
|
||||
if (!node.get("success").getAsBoolean()) {
|
||||
logger.info("Failed to upload skin for " + session.bedrockUsername());
|
||||
return;
|
||||
}
|
||||
|
||||
JsonNode data = node.get("data");
|
||||
JsonObject data = node.getAsJsonObject("data");
|
||||
|
||||
String value = data.get("value").asText();
|
||||
String signature = data.get("signature").asText();
|
||||
String value = data.get("value").getAsString();
|
||||
String signature = data.get("signature").getAsString();
|
||||
|
||||
byte[] bytes = (value + '\0' + signature)
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
@ -131,8 +128,8 @@ public final class FloodgateSkinUploader {
|
||||
}
|
||||
break;
|
||||
case LOG_MESSAGE:
|
||||
String logMessage = node.get("message").asText();
|
||||
switch (node.get("priority").asInt()) {
|
||||
String logMessage = node.get("message").getAsString();
|
||||
switch (node.get("priority").getAsInt()) {
|
||||
case -1 -> logger.debug("Got a message from skin uploader: " + logMessage);
|
||||
case 0 -> logger.info("Got a message from skin uploader: " + logMessage);
|
||||
case 1 -> logger.error("Got a message from skin uploader: " + logMessage);
|
||||
@ -150,20 +147,19 @@ public final class FloodgateSkinUploader {
|
||||
@Override
|
||||
public void onClose(int code, String reason, boolean remote) {
|
||||
if (reason != null && !reason.isEmpty()) {
|
||||
// The reason why I don't like Jackson
|
||||
try {
|
||||
JsonNode node = JACKSON.readTree(reason);
|
||||
JsonObject node = JsonUtils.parseJson(reason);
|
||||
// info means that the uploader itself did nothing wrong
|
||||
if (node.has("info")) {
|
||||
String info = node.get("info").asText();
|
||||
String info = node.get("info").getAsString();
|
||||
logger.debug("Got disconnected from the skin uploader: " + info);
|
||||
}
|
||||
// error means that the uploader did something wrong
|
||||
if (node.has("error")) {
|
||||
String error = node.get("error").asText();
|
||||
String error = node.get("error").getAsString();
|
||||
logger.info("Got disconnected from the skin uploader: " + error);
|
||||
}
|
||||
} catch (JsonProcessingException ignored) {
|
||||
} catch (JsonSyntaxException ignored) {
|
||||
// ignore invalid json
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while handling onClose", e);
|
||||
@ -195,20 +191,13 @@ public final class FloodgateSkinUploader {
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectNode node = JACKSON.createObjectNode();
|
||||
ArrayNode chainDataNode = JACKSON.createArrayNode();
|
||||
JsonObject node = new JsonObject();
|
||||
JsonArray chainDataNode = new JsonArray();
|
||||
chainData.forEach(chainDataNode::add);
|
||||
node.set("chain_data", chainDataNode);
|
||||
node.put("client_data", clientData);
|
||||
node.add("chain_data", chainDataNode);
|
||||
node.addProperty("client_data", clientData);
|
||||
|
||||
// The reason why I don't like Jackson
|
||||
String jsonString;
|
||||
try {
|
||||
jsonString = JACKSON.writeValueAsString(node);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to upload skin", e);
|
||||
return;
|
||||
}
|
||||
String jsonString = node.toString();
|
||||
|
||||
if (client.isOpen()) {
|
||||
client.send(jsonString);
|
||||
@ -241,4 +230,4 @@ public final class FloodgateSkinUploader {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
|
||||
package org.geysermc.geyser.skin;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
@ -43,6 +44,7 @@ import org.geysermc.geyser.entity.type.player.SkullPlayerEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.auth.BedrockClientData;
|
||||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.util.JsonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -194,7 +196,7 @@ public class SkinManager {
|
||||
|
||||
public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientData clientData) {
|
||||
GeyserImpl geyser = GeyserImpl.getInstance();
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.skin.bedrock.register", playerEntity.getUsername(), playerEntity.getUuid()));
|
||||
}
|
||||
|
||||
@ -208,7 +210,7 @@ public class SkinManager {
|
||||
if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) {
|
||||
SkinProvider.storeBedrockSkin(playerEntity.getUuid(), clientData.getSkinId(), skinBytes);
|
||||
SkinProvider.storeBedrockGeometry(playerEntity.getUuid(), geometryNameBytes, geometryBytes);
|
||||
} else if (geyser.getConfig().isDebugMode()) {
|
||||
} else if (geyser.config().debugMode()) {
|
||||
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.skin.bedrock.fail", playerEntity.getUsername()));
|
||||
geyser.getLogger().debug("The size of '" + playerEntity.getUsername() + "' skin is: " + clientData.getSkinImageWidth() + "x" + clientData.getSkinImageHeight());
|
||||
}
|
||||
@ -246,7 +248,7 @@ public class SkinManager {
|
||||
return loadFromJson(skinDataValue);
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for tag " + tag);
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
@ -274,7 +276,7 @@ public class SkinManager {
|
||||
} else {
|
||||
GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + entity.getUsername() + " with Value: " + texturesProperty);
|
||||
}
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ -282,30 +284,25 @@ public class SkinManager {
|
||||
}
|
||||
|
||||
public static @Nullable GameProfileData loadFromJson(String encodedJson) throws IOException, IllegalArgumentException {
|
||||
// TODO use GameProfile method.
|
||||
JsonNode skinObject;
|
||||
JsonObject skinObject;
|
||||
try {
|
||||
skinObject = GeyserImpl.JSON_MAPPER.readTree(new String(Base64.getDecoder().decode(encodedJson), StandardCharsets.UTF_8));
|
||||
skinObject = JsonUtils.parseJson(new String(Base64.getDecoder().decode(encodedJson), StandardCharsets.UTF_8));
|
||||
} catch (IllegalArgumentException e) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Invalid base64 encoded skin entry: " + encodedJson);
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonNode textures = skinObject.get("textures");
|
||||
|
||||
if (textures == null) {
|
||||
if (!(skinObject.get("textures") instanceof JsonObject textures)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonNode skinTexture = textures.get("SKIN");
|
||||
if (skinTexture == null) {
|
||||
if (!(textures.get("SKIN") instanceof JsonObject skinTexture)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String skinUrl;
|
||||
JsonNode skinUrlNode = skinTexture.get("url");
|
||||
if (skinUrlNode != null && skinUrlNode.isTextual()) {
|
||||
skinUrl = skinUrlNode.asText().replace("http://", "https://");
|
||||
if (skinTexture.get("url") instanceof JsonPrimitive skinUrlNode && skinUrlNode.isString()) {
|
||||
skinUrl = skinUrlNode.getAsString().replace("http://", "https://");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -322,11 +319,9 @@ public class SkinManager {
|
||||
boolean isAlex = skinTexture.has("metadata");
|
||||
|
||||
String capeUrl = null;
|
||||
JsonNode capeTexture = textures.get("CAPE");
|
||||
if (capeTexture != null) {
|
||||
JsonNode capeUrlNode = capeTexture.get("url");
|
||||
if (capeUrlNode != null && capeUrlNode.isTextual()) {
|
||||
capeUrl = capeUrlNode.asText().replace("http://", "https://");
|
||||
if (textures.get("CAPE") instanceof JsonObject capeTexture) {
|
||||
if (capeTexture.get("url") instanceof JsonPrimitive capeUrlNode && capeUrlNode.isString()) {
|
||||
capeUrl = capeUrlNode.getAsString().replace("http://", "https://");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,11 +126,6 @@ public class SkinProvider {
|
||||
WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull);
|
||||
String wearingCustomSkullSlim = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json"), StandardCharsets.UTF_8);
|
||||
WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim);
|
||||
|
||||
GeyserImpl geyser = GeyserImpl.getInstance();
|
||||
if (geyser.getConfig().isAllowThirdPartyEars() || geyser.getConfig().isAllowThirdPartyCapes()) {
|
||||
geyser.getLogger().warning("Third-party ears/capes have been removed from Geyser, if you still wish to have this functionality please use the extension: https://github.com/GeyserMC/ThirdPartyCosmetics");
|
||||
}
|
||||
}
|
||||
|
||||
public static ExecutorService getExecutorService() {
|
||||
@ -149,7 +144,7 @@ public class SkinProvider {
|
||||
|
||||
public static void registerCacheImageTask(GeyserImpl geyser) {
|
||||
// Schedule Daily Image Expiry if we are caching them
|
||||
if (geyser.getConfig().getCacheImages() > 0) {
|
||||
if (geyser.config().cacheImages() > 0) {
|
||||
geyser.getScheduledThread().scheduleAtFixedRate(() -> {
|
||||
File cacheFolder = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").toFile();
|
||||
if (!cacheFolder.exists()) {
|
||||
@ -157,7 +152,7 @@ public class SkinProvider {
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
final long expireTime = ((long) GeyserImpl.getInstance().getConfig().getCacheImages()) * ((long)1000 * 60 * 60 * 24);
|
||||
final long expireTime = ((long) GeyserImpl.getInstance().config().cacheImages()) * ((long)1000 * 60 * 60 * 24);
|
||||
for (File imageFile : Objects.requireNonNull(cacheFolder.listFiles())) {
|
||||
if (imageFile.lastModified() < System.currentTimeMillis() - expireTime) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
@ -188,7 +183,7 @@ public class SkinProvider {
|
||||
Cape cape = null;
|
||||
SkinGeometry geometry = SkinGeometry.WIDE;
|
||||
|
||||
if (GeyserImpl.getInstance().getConfig().getRemote().authType() != AuthType.ONLINE) {
|
||||
if (GeyserImpl.getInstance().config().java().authType() != AuthType.ONLINE) {
|
||||
// Let's see if this player is a Bedrock player, and if so, let's pull their skin.
|
||||
GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid);
|
||||
if (session != null) {
|
||||
@ -427,7 +422,7 @@ public class SkinProvider {
|
||||
GeyserImpl.getInstance().getLogger().debug("Downloaded " + imageUrl);
|
||||
|
||||
// Write to cache if we are allowed
|
||||
if (GeyserImpl.getInstance().getConfig().getCacheImages() > 0) {
|
||||
if (GeyserImpl.getInstance().config().cacheImages() > 0) {
|
||||
imageFile.getParentFile().mkdirs();
|
||||
try {
|
||||
ImageIO.write(image, "png", imageFile);
|
||||
@ -496,7 +491,7 @@ public class SkinProvider {
|
||||
return properties.get(0).getAsJsonObject().get("value").getAsString();
|
||||
} catch (Exception e) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Unable to request textures for " + uuid);
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
@ -515,7 +510,6 @@ public class SkinProvider {
|
||||
try {
|
||||
// Offline skin, or no present UUID
|
||||
JsonObject node = WebUtils.getJson("https://api.mojang.com/users/profiles/minecraft/" + username);
|
||||
System.out.println(node);
|
||||
JsonElement id = node.get("id");
|
||||
if (id == null) {
|
||||
GeyserImpl.getInstance().getLogger().debug("No UUID found in Mojang response for " + username);
|
||||
@ -523,7 +517,7 @@ public class SkinProvider {
|
||||
}
|
||||
return id.getAsString();
|
||||
} catch (Exception e) {
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
@ -80,8 +80,8 @@ public class GeyserLocale {
|
||||
* Finalize the default locale, now that we know what the default locale should be.
|
||||
*/
|
||||
public static void finalizeDefaultLocale(GeyserImpl geyser) {
|
||||
String newDefaultLocale = geyser.getConfig().getDefaultLocale();
|
||||
if (newDefaultLocale == null) {
|
||||
String newDefaultLocale = geyser.config().defaultLocale();
|
||||
if ("system".equals(newDefaultLocale)) {
|
||||
// We want to use the system locale which is already loaded
|
||||
return;
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ public abstract class InventoryTranslator {
|
||||
case PLACE: {
|
||||
TransferItemStackRequestAction transferAction = (TransferItemStackRequestAction) action;
|
||||
if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) {
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
session.getGeyser().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.bedrockUsername());
|
||||
dumpStackRequestDetails(session, inventory, transferAction.getSource(), transferAction.getDestination());
|
||||
}
|
||||
@ -312,7 +312,7 @@ public abstract class InventoryTranslator {
|
||||
ItemStackRequestSlotData destination = swapAction.getDestination();
|
||||
|
||||
if (!(checkNetId(session, inventory, source) && checkNetId(session, inventory, destination))) {
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
session.getGeyser().getLogger().error("DEBUG: About to reject SWAP request made by " + session.bedrockUsername());
|
||||
dumpStackRequestDetails(session, inventory, source, destination);
|
||||
}
|
||||
@ -807,7 +807,7 @@ public abstract class InventoryTranslator {
|
||||
* as bad (false).
|
||||
*/
|
||||
protected static ItemStackResponse rejectRequest(ItemStackRequest request, boolean throwError) {
|
||||
if (throwError && GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (throwError && GeyserImpl.getInstance().config().debugMode()) {
|
||||
new Throwable("DEBUGGING: ItemStackRequest rejected " + request.toString()).printStackTrace();
|
||||
}
|
||||
return new ItemStackResponse(ItemStackResponseStatus.ERROR, request.getRequestId(), Collections.emptyList());
|
||||
@ -952,4 +952,4 @@ public abstract class InventoryTranslator {
|
||||
TRANSFER,
|
||||
DONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
||||
return skull.getBlockDefinition();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
session.getGeyser().getLogger().debug("Failed to acquire textures for custom skull: " + blockPosition + " " + javaNbt);
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
|
||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
@ -36,10 +35,6 @@ public class BedrockEmoteListTranslator extends PacketTranslator<EmoteListPacket
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, EmoteListPacket packet) {
|
||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.refreshEmotes(packet.getPieceIds());
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
final Vector3i packetBlockPosition = packet.getBlockPosition();
|
||||
Vector3i blockPos = BlockUtils.getBlockPosition(packetBlockPosition, packet.getBlockFace());
|
||||
|
||||
if (session.getGeyser().getConfig().isDisableBedrockScaffolding()) {
|
||||
if (session.getGeyser().config().disableBedrockScaffolding()) {
|
||||
float yaw = session.getPlayerEntity().getYaw();
|
||||
boolean isGodBridging = switch (packet.getBlockFace()) {
|
||||
case 2 -> yaw <= -135f || yaw > 135f;
|
||||
@ -696,4 +696,4 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
||||
}, 150, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public class BedrockNetworkStackLatencyTranslator extends PacketTranslator<Netwo
|
||||
public void translate(GeyserSession session, NetworkStackLatencyPacket packet) {
|
||||
// negative timestamps are used as hack to fix the url image loading bug
|
||||
if (packet.getTimestamp() >= 0) {
|
||||
if (session.getGeyser().getConfig().isForwardPlayerPing()) {
|
||||
if (session.getGeyser().config().forwardPlayerPing()) {
|
||||
// use our cached value because
|
||||
// a) bedrock can be inaccurate with the value returned
|
||||
// b) playstation replies with a different magnitude than other platforms
|
||||
|
@ -45,7 +45,7 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat
|
||||
|
||||
if (session.remoteServer().authType() == AuthType.ONLINE) {
|
||||
if (!session.isLoggedIn()) {
|
||||
if (session.getGeyser().getConfig().getSavedUserLogins().contains(session.bedrockUsername())) {
|
||||
if (session.getGeyser().config().savedUserLogins().contains(session.bedrockUsername())) {
|
||||
if (session.getGeyser().refreshTokenFor(session.bedrockUsername()) == null) {
|
||||
LoginEncryptionUtils.buildAndShowConsentWindow(session);
|
||||
} else {
|
||||
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmotePacket;
|
||||
import org.geysermc.geyser.api.event.bedrock.ClientEmoteEvent;
|
||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.geyser.entity.type.Entity;
|
||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
@ -39,15 +38,6 @@ public class BedrockEmoteTranslator extends PacketTranslator<EmotePacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, EmotePacket packet) {
|
||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) {
|
||||
// Activate the workaround - we should trigger the offhand now
|
||||
session.requestOffhandSwap();
|
||||
|
||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For the future: could have a method that exposes which players will see the emote
|
||||
ClientEmoteEvent event = new ClientEmoteEvent(session, packet.getEmoteId());
|
||||
session.getGeyser().eventBus().fire(event);
|
||||
|
@ -113,7 +113,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundCommandsPacket packet) {
|
||||
// Don't send command suggestions if they are disabled
|
||||
if (!session.getGeyser().getConfig().isCommandSuggestions()) {
|
||||
if (!session.getGeyser().config().commandSuggestions()) {
|
||||
session.getGeyser().getLogger().debug("Not sending translated command suggestions as they are disabled.");
|
||||
|
||||
// Send an empty packet so Bedrock doesn't override /help with its own, built-in help command.
|
||||
|
@ -39,7 +39,7 @@ public class JavaKeepAliveTranslator extends PacketTranslator<ClientboundKeepAli
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundKeepAlivePacket packet) {
|
||||
if (!session.getGeyser().getConfig().isForwardPlayerPing()) {
|
||||
if (!session.getGeyser().config().forwardPlayerPing()) {
|
||||
return;
|
||||
}
|
||||
// We use this once the client replies (see BedrockNetworkStackLatencyTranslator)
|
||||
|
@ -132,7 +132,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
||||
case STONECUTTING -> {
|
||||
StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData();
|
||||
if (stoneCuttingData.getIngredient().getOptions().length == 0) {
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
if (GeyserImpl.getInstance().config().debugMode()) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " +
|
||||
recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier());
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class JavaSetEntityDataTranslator extends PacketTranslator<ClientboundSet
|
||||
EntityDefinition<?> definition = entity.getDefinition();
|
||||
for (EntityMetadata<?, ?> metadata : packet.getMetadata()) {
|
||||
if (metadata.getId() >= definition.translators().size()) {
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
// Minecraft client just ignores these
|
||||
session.getGeyser().getLogger().warning("Metadata ID " + metadata.getId() + " is out of bounds of known entity metadata size " + definition.translators().size() + " for entity type " + entity.getDefinition().entityType());
|
||||
session.getGeyser().getLogger().debug(metadata.toString());
|
||||
|
@ -91,7 +91,7 @@ public class JavaPlayerPositionTranslator extends PacketTranslator<ClientboundPl
|
||||
|
||||
ChunkUtils.updateChunkPosition(session, pos.toInt());
|
||||
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
session.getGeyser().getLogger().debug("Spawned player at " + packet.getX() + " " + packet.getY() + " " + packet.getZ());
|
||||
}
|
||||
return;
|
||||
|
@ -357,7 +357,7 @@ public class MessageTranslator {
|
||||
textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.locale()));
|
||||
} else {
|
||||
session.getGeyser().getLogger().debug("Likely illegal chat type detection found.");
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
if (session.getGeyser().config().debugMode()) {
|
||||
Thread.dumpStack();
|
||||
}
|
||||
textPacket.setMessage(MessageTranslator.convertMessage(message, session.locale()));
|
||||
|
@ -38,22 +38,12 @@ import java.util.concurrent.TimeUnit;
|
||||
* Much of the work here is from the wonderful folks from <a href="https://github.com/ViaVersion/ViaRewind">ViaRewind</a>
|
||||
*/
|
||||
public class CooldownUtils {
|
||||
private static CooldownType DEFAULT_SHOW_COOLDOWN;
|
||||
|
||||
public static void setDefaultShowCooldown(String showCooldown) {
|
||||
DEFAULT_SHOW_COOLDOWN = CooldownType.getByName(showCooldown);
|
||||
}
|
||||
|
||||
public static CooldownType getDefaultShowCooldown() {
|
||||
return DEFAULT_SHOW_COOLDOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts sending the fake cooldown to the Bedrock client. If the cooldown is not disabled, the sent type is the cooldownPreference in {@link PreferencesCache}
|
||||
* @param session GeyserSession
|
||||
*/
|
||||
public static void sendCooldown(GeyserSession session) {
|
||||
if (DEFAULT_SHOW_COOLDOWN == CooldownType.DISABLED) return;
|
||||
if (session.getGeyser().config().showCooldown() == CooldownType.DISABLED) return;
|
||||
CooldownType sessionPreference = session.getPreferencesCache().getCooldownPreference();
|
||||
if (sessionPreference == CooldownType.DISABLED) return;
|
||||
|
||||
@ -161,10 +151,6 @@ public class CooldownUtils {
|
||||
* @return The converted CooldownType
|
||||
*/
|
||||
public static CooldownType getByName(String name) {
|
||||
if (name.equalsIgnoreCase("true")) { // Backwards config compatibility
|
||||
return CooldownType.TITLE;
|
||||
}
|
||||
|
||||
for (CooldownType type : VALUES) {
|
||||
if (type.name().equalsIgnoreCase(name)) {
|
||||
return type;
|
||||
|
@ -179,7 +179,7 @@ public class InventoryUtils {
|
||||
}
|
||||
|
||||
public static boolean canStack(GeyserItemStack item1, GeyserItemStack item2) {
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode())
|
||||
if (GeyserImpl.getInstance().config().debugMode())
|
||||
canStackDebug(item1, item2);
|
||||
if (item1.isEmpty() || item2.isEmpty())
|
||||
return false;
|
||||
@ -231,7 +231,7 @@ public class InventoryUtils {
|
||||
|
||||
private static ItemDefinition getUnusableSpaceBlockDefinition(int protocolVersion) {
|
||||
ItemMappings mappings = Registries.ITEMS.forVersion(protocolVersion);
|
||||
String unusableSpaceBlock = GeyserImpl.getInstance().getConfig().getUnusableSpaceBlock();
|
||||
String unusableSpaceBlock = GeyserImpl.getInstance().config().unusableSpaceBlock();
|
||||
ItemDefinition itemDefinition = mappings.getDefinition(unusableSpaceBlock);
|
||||
|
||||
if (itemDefinition == null) {
|
||||
|
@ -48,6 +48,10 @@ public final class JsonUtils {
|
||||
return (JsonObject) new JsonParser().parse(new InputStreamReader(stream));
|
||||
}
|
||||
|
||||
public static JsonObject parseJson(String s) {
|
||||
return (JsonObject) new JsonParser().parse(s);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(InputStream stream, Type type) {
|
||||
return GeyserImpl.GSON.fromJson(new InputStreamReader(stream), type);
|
||||
}
|
||||
|
@ -25,9 +25,6 @@
|
||||
|
||||
package org.geysermc.geyser.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket;
|
||||
@ -53,8 +50,6 @@ import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class LoginEncryptionUtils {
|
||||
private static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
|
||||
private static boolean HAS_SENT_ENCRYPTION_MESSAGE = false;
|
||||
|
||||
public static void encryptPlayerConnection(GeyserSession session, LoginPacket loginPacket) {
|
||||
@ -69,7 +64,7 @@ public class LoginEncryptionUtils {
|
||||
|
||||
geyser.getLogger().debug(String.format("Is player data signed? %s", result.signed()));
|
||||
|
||||
if (!result.signed() && !session.getGeyser().getConfig().isEnableProxyConnections()) {
|
||||
if (!result.signed() && !session.getGeyser().config().enableProxyConnections()) {
|
||||
session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.remote.invalid_xbox_account"));
|
||||
return;
|
||||
}
|
||||
@ -85,8 +80,7 @@ public class LoginEncryptionUtils {
|
||||
throw new IllegalStateException("Client data isn't signed by the given chain data");
|
||||
}
|
||||
|
||||
JsonNode clientDataJson = JSON_MAPPER.readTree(clientDataPayload);
|
||||
BedrockClientData data = JSON_MAPPER.convertValue(clientDataJson, BedrockClientData.class);
|
||||
BedrockClientData data = JsonUtils.fromJson(clientDataPayload, BedrockClientData.class);
|
||||
data.setOriginalString(clientData);
|
||||
session.setClientData(data);
|
||||
|
||||
@ -94,7 +88,7 @@ public class LoginEncryptionUtils {
|
||||
startEncryptionHandshake(session, identityPublicKey);
|
||||
} catch (Throwable e) {
|
||||
// An error can be thrown on older Java 8 versions about an invalid key
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -213,7 +207,7 @@ public class LoginEncryptionUtils {
|
||||
.append("\n%xbox.signin.enterCode\n")
|
||||
.append(ChatColor.GREEN)
|
||||
.append(msCode.user_code);
|
||||
int timeout = session.getGeyser().getConfig().getPendingAuthenticationTimeout();
|
||||
int timeout = session.getGeyser().config().pendingAuthenticationTimeout();
|
||||
if (timeout != 0) {
|
||||
message.append("\n\n")
|
||||
.append(ChatColor.RESET)
|
||||
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2022 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.geyser.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* bStats collects some data for plugin authors.
|
||||
* <p>
|
||||
* Check out <a href="https://bStats.org/">bStats</a> to learn more about bStats!
|
||||
*/
|
||||
public class Metrics {
|
||||
|
||||
// The version of this bStats class
|
||||
public static final int B_STATS_VERSION = 1;
|
||||
|
||||
// The url to which the data is sent
|
||||
private static final String URL = "https://bStats.org/submitData/server-implementation";
|
||||
|
||||
// Should failed requests be logged?
|
||||
private static boolean logFailedRequests = false;
|
||||
|
||||
// The logger for the failed requests
|
||||
private static Logger logger = Logger.getLogger("bStats");
|
||||
|
||||
// The name of the server software
|
||||
private final String name;
|
||||
|
||||
// The uuid of the server
|
||||
private final String serverUUID;
|
||||
|
||||
// A list with all custom charts
|
||||
private final List<CustomChart> charts = new ArrayList<>();
|
||||
|
||||
private final static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private final GeyserImpl geyser;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param geyser The Geyser instance
|
||||
* @param name The name of the server software.
|
||||
* @param serverUUID The uuid of the server.
|
||||
* @param logFailedRequests Whether failed requests should be logged or not.
|
||||
* @param logger The logger for the failed requests.
|
||||
*/
|
||||
public Metrics(GeyserImpl geyser, String name, String serverUUID, boolean logFailedRequests, Logger logger) {
|
||||
this.geyser = geyser;
|
||||
this.name = name;
|
||||
this.serverUUID = serverUUID;
|
||||
Metrics.logFailedRequests = logFailedRequests;
|
||||
Metrics.logger = logger;
|
||||
|
||||
// Start submitting the data
|
||||
startSubmitting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
if (chart == null) {
|
||||
throw new IllegalArgumentException("Chart cannot be null!");
|
||||
}
|
||||
charts.add(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Scheduler which submits our data every 30 minutes.
|
||||
*/
|
||||
private void startSubmitting() {
|
||||
geyser.getScheduledThread().scheduleAtFixedRate(this::submitData, 1, 30, TimeUnit.MINUTES);
|
||||
// Submit the data every 30 minutes, first time after 1 minutes to give other plugins enough time to start
|
||||
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||
// WARNING: Just don't do it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin specific data.
|
||||
*
|
||||
* @return The plugin specific data.
|
||||
*/
|
||||
private ObjectNode getPluginData() {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
|
||||
data.put("pluginName", name); // Append the name of the server software
|
||||
data.put("pluginVersion", GeyserImpl.VERSION); // Append the name of the server software
|
||||
|
||||
ArrayNode customCharts = mapper.createArrayNode();
|
||||
for (CustomChart customChart : charts) {
|
||||
// Add the data of the custom charts
|
||||
JsonNode chart = customChart.getRequestJsonNode();
|
||||
if (chart == null) { // If the chart is null, we skip it
|
||||
continue;
|
||||
}
|
||||
customCharts.add(chart);
|
||||
}
|
||||
data.set("customCharts", customCharts);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server specific data.
|
||||
*
|
||||
* @return The server specific data.
|
||||
*/
|
||||
private ObjectNode getServerData() {
|
||||
// OS specific data
|
||||
String osName = System.getProperty("os.name");
|
||||
String osArch = System.getProperty("os.arch");
|
||||
String osVersion = System.getProperty("os.version");
|
||||
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
|
||||
data.put("serverUUID", serverUUID);
|
||||
|
||||
data.put("osName", osName);
|
||||
data.put("osArch", osArch);
|
||||
data.put("osVersion", osVersion);
|
||||
data.put("coreCount", coreCount);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the data and sends it afterwards.
|
||||
*/
|
||||
private void submitData() {
|
||||
final ObjectNode data = getServerData();
|
||||
|
||||
ArrayNode pluginData = mapper.createArrayNode();
|
||||
pluginData.add(getPluginData());
|
||||
data.putPOJO("plugins", pluginData);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// We are still in the Thread of the timer, so nothing get blocked :)
|
||||
sendData(data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logFailedRequests) {
|
||||
logger.log(Level.WARNING, "Could not submit stats of " + name, e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data to the bStats server.
|
||||
*
|
||||
* @param data The data to send.
|
||||
* @throws Exception If the request failed.
|
||||
*/
|
||||
private static void sendData(ObjectNode data) throws Exception {
|
||||
if (data == null) {
|
||||
throw new IllegalArgumentException("Data cannot be null!");
|
||||
}
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
|
||||
// Add headers
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||
|
||||
// Send data
|
||||
connection.setDoOutput(true);
|
||||
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
|
||||
outputStream.write(compressedData);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
connection.getInputStream().close(); // We don't care about the response - Just send our data :)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given String.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped String.
|
||||
* @throws IOException If the compression failed.
|
||||
*/
|
||||
private static byte @NonNull [] compress(final @NonNull String str) throws IOException {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
gzip.close();
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom chart.
|
||||
*/
|
||||
public static abstract class CustomChart {
|
||||
|
||||
// The id of the chart
|
||||
final String chartId;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
*/
|
||||
CustomChart(String chartId) {
|
||||
if (chartId == null || chartId.isEmpty()) {
|
||||
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
private @Nullable ObjectNode getRequestJsonNode() {
|
||||
ObjectNode chart = new ObjectMapper().createObjectNode();
|
||||
chart.put("chartId", chartId);
|
||||
try {
|
||||
ObjectNode data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
chart.putPOJO("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logFailedRequests) {
|
||||
logger.log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return chart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected abstract ObjectNode getChartData() throws Exception;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom simple pie.
|
||||
*/
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ObjectNode getChartData() throws Exception {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.put("value", value);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom advanced pie.
|
||||
*/
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ObjectNode getChartData() throws Exception {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
ObjectNode values = mapper.createObjectNode();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
continue; // Skip this invalid
|
||||
}
|
||||
allSkipped = false;
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.putPOJO("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom drilldown pie.
|
||||
*/
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ObjectNode getChartData() throws Exception {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
ObjectNode values = mapper.createObjectNode();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
ObjectNode value = mapper.createObjectNode();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
value.put(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
values.putPOJO(entryValues.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.putPOJO("values", values);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom single line chart.
|
||||
*/
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ObjectNode getChartData() throws Exception {
|
||||
ObjectNode data = mapper.createObjectNode();
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
data.put("value", value);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -51,8 +51,8 @@ public class SettingsUtils {
|
||||
|
||||
// Let's store these to avoid issues
|
||||
boolean showCoordinates = session.getPreferencesCache().isAllowShowCoordinates();
|
||||
boolean cooldownShown = CooldownUtils.getDefaultShowCooldown() != CooldownUtils.CooldownType.DISABLED;
|
||||
boolean customSkulls = session.getGeyser().getConfig().isAllowCustomSkulls();
|
||||
boolean cooldownShown = session.getGeyser().config().showCooldown() != CooldownUtils.CooldownType.DISABLED;
|
||||
boolean customSkulls = session.getGeyser().config().allowCustomSkulls();
|
||||
|
||||
// Only show the client title if any of the client settings are available
|
||||
boolean showClientSettings = showCoordinates || cooldownShown || customSkulls;
|
||||
|
@ -199,7 +199,7 @@ public class WebUtils {
|
||||
return ((String) attr.get(0)).split(" ");
|
||||
}
|
||||
} catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes
|
||||
if (geyser.getConfig().isDebugMode()) {
|
||||
if (geyser.config().debugMode()) {
|
||||
geyser.getLogger().debug("Exception while trying to find an SRV record for the remote host.");
|
||||
ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
[versions]
|
||||
base-api = "1.0.0-SNAPSHOT"
|
||||
bstats = "3.0.2"
|
||||
cumulus = "1.1.2"
|
||||
configurate = "4.2.0-GeyserMC-SNAPSHOT"
|
||||
erosion = "1.1-20240515.191456-1"
|
||||
@ -130,6 +131,8 @@ protocol-connection = { group = "org.cloudburstmc.protocol", name = "bedrock-con
|
||||
|
||||
math = { group = "org.cloudburstmc.math", name = "immutable", version = "2.0" }
|
||||
|
||||
bstats = { group = "org.bstats", name = "bstats-base", version.ref = "bstats"}
|
||||
|
||||
# plugins
|
||||
indra = { group = "net.kyori", name = "indra-common", version.ref = "indra" }
|
||||
shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" }
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren