diff options
Diffstat (limited to 'paper-server/patches/unapplied/net/minecraft/server/dedicated')
5 files changed, 801 insertions, 0 deletions
diff --git a/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch new file mode 100644 index 0000000000..17d45a61ee --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedPlayerList.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/server/dedicated/DedicatedPlayerList.java ++++ b/net/minecraft/server/dedicated/DedicatedPlayerList.java +@@ -18,6 +18,11 @@ + this.setViewDistance(dedicatedServerProperties.viewDistance); + this.setSimulationDistance(dedicatedServerProperties.simulationDistance); + super.setUsingWhiteList(dedicatedServerProperties.whiteList.get()); ++ // Paper start - fix converting txt to json file; moved from constructor ++ } ++ @Override ++ public void loadAndSaveFiles() { ++ // Paper end - fix converting txt to json file + this.loadUserBanList(); + this.saveUserBanList(); + this.loadIpBanList(); diff --git a/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServer.java.patch b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServer.java.patch new file mode 100644 index 0000000000..0780484bbb --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -0,0 +1,475 @@ +--- a/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -54,20 +54,31 @@ + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.level.GameRules; + import net.minecraft.world.level.GameType; +-import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.entity.SkullBlockEntity; + import net.minecraft.world.level.storage.LevelStorageSource; + import org.slf4j.Logger; + ++// CraftBukkit start ++import net.minecraft.server.WorldLoader; ++import org.apache.logging.log4j.Level; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.io.IoBuilder; ++import org.bukkit.command.CommandSender; ++import org.bukkit.craftbukkit.util.TerminalCompletionHandler; ++import org.bukkit.craftbukkit.util.TerminalConsoleWriterThread; ++import org.bukkit.event.server.ServerCommandEvent; ++import org.bukkit.event.server.RemoteServerCommandEvent; ++// CraftBukkit end ++ + public class DedicatedServer extends MinecraftServer implements ServerInterface { + + static final Logger LOGGER = LogUtils.getLogger(); + private static final int CONVERSION_RETRY_DELAY_MS = 5000; + private static final int CONVERSION_RETRIES = 2; +- private final List<ConsoleInput> consoleInput = Collections.synchronizedList(Lists.newArrayList()); ++ private final java.util.Queue<ConsoleInput> serverCommandQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - Perf: use a proper queue + @Nullable + private QueryThreadGs4 queryThreadGs4; +- private final RconConsoleSource rconConsoleSource; ++ // private final RemoteControlCommandListener rconConsoleSource; // CraftBukkit - remove field + @Nullable + private RconThread rconThread; + public DedicatedServerSettings settings; +@@ -81,41 +92,117 @@ + private DebugSampleSubscriptionTracker debugSampleSubscriptionTracker; + public ServerLinks serverLinks; + +- public DedicatedServer(Thread serverThread, LevelStorageSource.LevelStorageAccess session, PackRepository dataPackManager, WorldStem saveLoader, DedicatedServerSettings propertiesLoader, DataFixer dataFixer, Services apiServices, ChunkProgressListenerFactory worldGenerationProgressListenerFactory) { +- super(serverThread, session, dataPackManager, saveLoader, Proxy.NO_PROXY, dataFixer, apiServices, worldGenerationProgressListenerFactory); +- this.settings = propertiesLoader; +- this.rconConsoleSource = new RconConsoleSource(this); +- this.serverTextFilter = ServerTextFilter.createFromConfig(propertiesLoader.getProperties()); +- this.serverLinks = DedicatedServer.createServerLinks(propertiesLoader); ++ // CraftBukkit start - Signature changed ++ public DedicatedServer(joptsimple.OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, DedicatedServerSettings dedicatedserversettings, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) { ++ super(options, worldLoader, thread, convertable_conversionsession, resourcepackrepository, worldstem, Proxy.NO_PROXY, datafixer, services, worldloadlistenerfactory); ++ // CraftBukkit end ++ this.settings = dedicatedserversettings; ++ // this.rconConsoleSource = new RemoteControlCommandListener(this); // CraftBukkit - remove field ++ this.serverTextFilter = ServerTextFilter.createFromConfig(dedicatedserversettings.getProperties()); ++ this.serverLinks = DedicatedServer.createServerLinks(dedicatedserversettings); + } + + @Override + public boolean initServer() throws IOException { + Thread thread = new Thread("Server console handler") { + public void run() { +- BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.Main.useConsole) { ++ return; ++ } ++ // Paper start - Use TerminalConsoleAppender ++ new com.destroystokyo.paper.console.PaperConsole(DedicatedServer.this).start(); ++ /* ++ jline.console.ConsoleReader bufferedreader = DedicatedServer.this.reader; + ++ // MC-33041, SPIGOT-5538: if System.in is not valid due to javaw, then return ++ try { ++ System.in.available(); ++ } catch (IOException ex) { ++ return; ++ } ++ // CraftBukkit end ++ + String s; + + try { +- while (!DedicatedServer.this.isStopped() && DedicatedServer.this.isRunning() && (s = bufferedreader.readLine()) != null) { +- DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack()); ++ // CraftBukkit start - JLine disabling compatibility ++ while (!DedicatedServer.this.isStopped() && DedicatedServer.this.isRunning()) { ++ if (org.bukkit.craftbukkit.Main.useJline) { ++ s = bufferedreader.readLine(">", null); ++ } else { ++ s = bufferedreader.readLine(); ++ } ++ ++ // SPIGOT-5220: Throttle if EOF (ctrl^d) or stdin is /dev/null ++ if (s == null) { ++ try { ++ Thread.sleep(50L); ++ } catch (InterruptedException ex) { ++ Thread.currentThread().interrupt(); ++ } ++ continue; ++ } ++ if (s.trim().length() > 0) { // Trim to filter lines which are just spaces ++ DedicatedServer.this.issueCommand(s, DedicatedServer.this.getServerCommandListener()); ++ } ++ // CraftBukkit end + } + } catch (IOException ioexception) { + DedicatedServer.LOGGER.error("Exception handling console input", ioexception); + } + ++ */ ++ // Paper end + } + }; + ++ // CraftBukkit start - TODO: handle command-line logging arguments ++ java.util.logging.Logger global = java.util.logging.Logger.getLogger(""); ++ global.setUseParentHandlers(false); ++ for (java.util.logging.Handler handler : global.getHandlers()) { ++ global.removeHandler(handler); ++ } ++ global.addHandler(new org.bukkit.craftbukkit.util.ForwardLogHandler()); ++ ++ // Paper start - Not needed with TerminalConsoleAppender ++ final org.apache.logging.log4j.Logger logger = LogManager.getRootLogger(); ++ /* ++ final org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger()); ++ for (org.apache.logging.log4j.core.Appender appender : logger.getAppenders().values()) { ++ if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) { ++ logger.removeAppender(appender); ++ } ++ } ++ ++ TerminalConsoleWriterThread writerThread = new TerminalConsoleWriterThread(System.out, this.reader); ++ this.reader.setCompletionHandler(new TerminalCompletionHandler(writerThread, this.reader.getCompletionHandler())); ++ writerThread.start(); ++ */ ++ // Paper end - Not needed with TerminalConsoleAppender ++ ++ System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream()); ++ System.setErr(IoBuilder.forLogger(logger).setLevel(Level.WARN).buildPrintStream()); ++ // CraftBukkit end ++ + thread.setDaemon(true); + thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER)); +- thread.start(); ++ // thread.start(); // Paper - Enhance console tab completions for brigadier commands; moved down + DedicatedServer.LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName()); + if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) { + DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\""); + } + ++ // Paper start - detect running as root ++ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) { ++ DedicatedServer.LOGGER.warn("****************************"); ++ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED."); ++ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS."); ++ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/"); ++ DedicatedServer.LOGGER.warn("****************************"); ++ } ++ // Paper end - detect running as root ++ + DedicatedServer.LOGGER.info("Loading properties"); + DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties(); + +@@ -126,14 +213,51 @@ + this.setPreventProxyConnections(dedicatedserverproperties.preventProxyConnections); + this.setLocalIp(dedicatedserverproperties.serverIp); + } ++ // Spigot start ++ this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); ++ org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings")); ++ org.spigotmc.SpigotConfig.registerCommands(); ++ // Spigot end ++ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. ++ // Paper start - initialize global and world-defaults configuration ++ this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); ++ this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); ++ // Paper end - initialize global and world-defaults configuration ++ this.server.spark.enableEarlyIfRequested(); // Paper - spark ++ // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save ++ if (this.convertOldUsers()) { ++ this.getProfileCache().save(false); // Paper ++ } ++ this.getPlayerList().loadAndSaveFiles(); // Must be after convertNames ++ // Paper end - fix converting txt to json file ++ org.spigotmc.WatchdogThread.doStart(org.spigotmc.SpigotConfig.timeoutTime, org.spigotmc.SpigotConfig.restartOnCrash); // Paper - start watchdog thread ++ thread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized ++ io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command ++ this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark ++ com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics ++ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now + + this.setPvpAllowed(dedicatedserverproperties.pvp); + this.setFlightAllowed(dedicatedserverproperties.allowFlight); + this.setMotd(dedicatedserverproperties.motd); + super.setPlayerIdleTimeout((Integer) dedicatedserverproperties.playerIdleTimeout.get()); + this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist); +- this.worldData.setGameType(dedicatedserverproperties.gamemode); ++ // this.worldData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading + DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode); ++ // Paper start - Unix domain socket support ++ java.net.SocketAddress bindAddress; ++ if (this.getLocalIp().startsWith("unix:")) { ++ if (!io.netty.channel.epoll.Epoll.isAvailable()) { ++ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.error("You are trying to use a Unix domain socket but you're not on a supported OS."); ++ return false; ++ } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && !org.spigotmc.SpigotConfig.bungee) { ++ DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.error("Unix domain sockets require IPs to be forwarded from a proxy."); ++ return false; ++ } ++ bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getLocalIp().substring("unix:".length())); ++ } else { + InetAddress inetaddress = null; + + if (!this.getLocalIp().isEmpty()) { +@@ -143,34 +267,55 @@ + if (this.getPort() < 0) { + this.setPort(dedicatedserverproperties.serverPort); + } ++ bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort()); ++ } ++ // Paper end - Unix domain socket support + + this.initializeKeyPair(); + DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); + + try { +- this.getConnection().startTcpServerListener(inetaddress, this.getPort()); ++ this.getConnection().bind(bindAddress); // Paper - Unix domain socket support + } catch (IOException ioexception) { + DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!"); + DedicatedServer.LOGGER.warn("The exception was: {}", ioexception.toString()); + DedicatedServer.LOGGER.warn("Perhaps a server is already running on that port?"); ++ if (true) throw new IllegalStateException("Failed to bind to port", ioexception); // Paper - Propagate failed to bind to port error + return false; + } + ++ // CraftBukkit start ++ // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // Spigot - moved up ++ this.server.loadPlugins(); ++ this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP); ++ // CraftBukkit end ++ ++ // Paper start - Add Velocity IP Forwarding Support ++ boolean usingProxy = org.spigotmc.SpigotConfig.bungee || io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled; ++ String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; ++ String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; ++ // Paper end - Add Velocity IP Forwarding Support + if (!this.usesAuthentication()) { + DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); +- DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); ++ // Spigot start ++ // Paper start - Add Velocity IP Forwarding Support ++ if (usingProxy) { ++ DedicatedServer.LOGGER.warn("Whilst this makes it possible to use " + proxyFlavor + ", unless access to your server is properly restricted, it also opens up the ability for hackers to connect with any username they choose."); ++ DedicatedServer.LOGGER.warn("Please see " + proxyLink + " for further information."); ++ // Paper end - Add Velocity IP Forwarding Support ++ } else { ++ DedicatedServer.LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose."); ++ } ++ // Spigot end + DedicatedServer.LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file."); + } + +- if (this.convertOldUsers()) { +- this.getProfileCache().save(); +- } + + if (!OldUsersConverter.serverReadyAfterUserconversion(this)) { + return false; + } else { +- this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); ++ // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up + this.debugSampleSubscriptionTracker = new DebugSampleSubscriptionTracker(this.getPlayerList()); + this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSampleSubscriptionTracker, RemoteDebugSampleType.TICK_TIME); + long i = Util.getNanos(); +@@ -178,13 +323,13 @@ + SkullBlockEntity.setup(this.services, this); + GameProfileCache.setUsesAuthentication(this.usesAuthentication()); + DedicatedServer.LOGGER.info("Preparing level \"{}\"", this.getLevelIdName()); +- this.loadLevel(); ++ this.loadLevel(this.storageSource.getLevelId()); // CraftBukkit + long j = Util.getNanos() - i; + String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D); + + DedicatedServer.LOGGER.info("Done ({})! For help, type \"help\"", s); + if (dedicatedserverproperties.announcePlayerAchievements != null) { +- ((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this); ++ ((GameRules.BooleanValue) this.getGameRules().getRule(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)).set(dedicatedserverproperties.announcePlayerAchievements, this.overworld()); // CraftBukkit - per-world + } + + if (dedicatedserverproperties.enableQuery) { +@@ -197,7 +342,7 @@ + this.rconThread = RconThread.create(this); + } + +- if (this.getMaxTickLength() > 0L) { ++ if (false && this.getMaxTickLength() > 0L) { // Spigot - disable + Thread thread1 = new Thread(new ServerWatchdog(this)); + + thread1.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(DedicatedServer.LOGGER)); +@@ -215,6 +360,12 @@ + } + } + ++ // Paper start ++ public java.io.File getPluginsFolder() { ++ return (java.io.File) this.options.valueOf("plugins"); ++ } ++ // Paper end ++ + @Override + public boolean isSpawningMonsters() { + return this.settings.getProperties().spawnMonsters && super.isSpawningMonsters(); +@@ -227,7 +378,7 @@ + + @Override + public void forceDifficulty() { +- this.setDifficulty(this.getProperties().difficulty, true); ++ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - per level difficulty; Don't overwrite level.dat's difficulty, keep current + } + + @Override +@@ -286,13 +437,14 @@ + } + + if (this.rconThread != null) { +- this.rconThread.stop(); ++ this.rconThread.stopNonBlocking(); // Paper - don't wait for remote connections + } + + if (this.queryThreadGs4 != null) { +- this.queryThreadGs4.stop(); ++ // this.remoteStatusListener.stop(); // Paper - don't wait for remote connections + } + ++ System.exit(0); // CraftBukkit + } + + @Override +@@ -302,19 +454,29 @@ + } + + @Override +- public boolean isLevelEnabled(Level world) { +- return world.dimension() == Level.NETHER ? this.getProperties().allowNether : true; ++ public boolean isLevelEnabled(net.minecraft.world.level.Level world) { ++ return world.dimension() == net.minecraft.world.level.Level.NETHER ? this.getProperties().allowNether : true; + } + + public void handleConsoleInput(String command, CommandSourceStack commandSource) { +- this.consoleInput.add(new ConsoleInput(command, commandSource)); ++ this.serverCommandQueue.add(new ConsoleInput(command, commandSource)); // Paper - Perf: use proper queue + } + + public void handleConsoleInputs() { +- while (!this.consoleInput.isEmpty()) { +- ConsoleInput servercommand = (ConsoleInput) this.consoleInput.remove(0); ++ // Paper start - Perf: use proper queue ++ ConsoleInput servercommand; ++ while ((servercommand = this.serverCommandQueue.poll()) != null) { ++ // Paper end - Perf: use proper queue + +- this.getCommands().performPrefixedCommand(servercommand.source, servercommand.msg); ++ // CraftBukkit start - ServerCommand for preprocessing ++ ServerCommandEvent event = new ServerCommandEvent(this.console, servercommand.msg); ++ this.server.getPluginManager().callEvent(event); ++ if (event.isCancelled()) continue; ++ servercommand = new ConsoleInput(event.getCommand(), servercommand.source); ++ ++ // this.getCommands().performPrefixedCommand(servercommand.source, servercommand.msg); // Called in dispatchServerCommand ++ this.server.dispatchServerCommand(this.console, servercommand); ++ // CraftBukkit end + } + + } +@@ -383,7 +545,7 @@ + + @Override + public boolean isUnderSpawnProtection(ServerLevel world, BlockPos pos, Player player) { +- if (world.dimension() != Level.OVERWORLD) { ++ if (world.dimension() != net.minecraft.world.level.Level.OVERWORLD) { + return false; + } else if (this.getPlayerList().getOps().isEmpty()) { + return false; +@@ -453,7 +615,11 @@ + public boolean enforceSecureProfile() { + DedicatedServerProperties dedicatedserverproperties = this.getProperties(); + +- return dedicatedserverproperties.enforceSecureProfile && dedicatedserverproperties.onlineMode && this.services.canValidateProfileKeys(); ++ // Paper start - Add setting for proxy online mode status ++ return dedicatedserverproperties.enforceSecureProfile ++ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ++ && this.services.canValidateProfileKeys(); ++ // Paper end - Add setting for proxy online mode status + } + + @Override +@@ -541,16 +707,52 @@ + + @Override + public String getPluginNames() { +- return ""; ++ // CraftBukkit start - Whole method ++ StringBuilder result = new StringBuilder(); ++ org.bukkit.plugin.Plugin[] plugins = this.server.getPluginManager().getPlugins(); ++ ++ result.append(this.server.getName()); ++ result.append(" on Bukkit "); ++ result.append(this.server.getBukkitVersion()); ++ ++ if (plugins.length > 0 && this.server.getQueryPlugins()) { ++ result.append(": "); ++ ++ for (int i = 0; i < plugins.length; i++) { ++ if (i > 0) { ++ result.append("; "); ++ } ++ ++ result.append(plugins[i].getDescription().getName()); ++ result.append(" "); ++ result.append(plugins[i].getDescription().getVersion().replaceAll(";", ",")); ++ } ++ } ++ ++ return result.toString(); ++ // CraftBukkit end + } + + @Override + public String runCommand(String command) { +- this.rconConsoleSource.prepareForCommand(); ++ // CraftBukkit start - fire RemoteServerCommandEvent ++ throw new UnsupportedOperationException("Not supported - remote source required."); ++ } ++ ++ public String runCommand(RconConsoleSource rconConsoleSource, String s) { ++ rconConsoleSource.prepareForCommand(); + this.executeBlocking(() -> { +- this.getCommands().performPrefixedCommand(this.rconConsoleSource.createCommandSourceStack(), command); ++ CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack(); ++ RemoteServerCommandEvent event = new RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); ++ this.server.getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return; ++ } ++ ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper); ++ this.server.dispatchServerCommand(event.getSender(), serverCommand); + }); +- return this.rconConsoleSource.getCommandResponse(); ++ return rconConsoleSource.getCommandResponse(); ++ // CraftBukkit end + } + + public void storeUsingWhiteList(boolean useWhitelist) { +@@ -660,4 +862,15 @@ + } + } + } ++ ++ // CraftBukkit start ++ public boolean isDebugging() { ++ return this.getProperties().debug; ++ } ++ ++ @Override ++ public CommandSender getBukkitSender(CommandSourceStack wrapper) { ++ return this.console; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch new file mode 100644 index 0000000000..2020814765 --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerProperties.java.patch @@ -0,0 +1,106 @@ +--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java ++++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java +@@ -43,11 +43,16 @@ + import net.minecraft.world.level.levelgen.presets.WorldPresets; + import org.slf4j.Logger; + ++// CraftBukkit start ++import joptsimple.OptionSet; ++// CraftBukkit end ++ + public class DedicatedServerProperties extends Settings<DedicatedServerProperties> { + + static final Logger LOGGER = LogUtils.getLogger(); + private static final Pattern SHA1 = Pattern.compile("^[a-fA-F0-9]{40}$"); + private static final Splitter COMMA_SPLITTER = Splitter.on(',').trimResults(); ++ public final boolean debug = this.get("debug", false); // CraftBukkit + public final boolean onlineMode = this.get("online-mode", true); + public final boolean preventProxyConnections = this.get("prevent-proxy-connections", false); + public final String serverIp = this.get("server-ip", ""); +@@ -100,13 +105,17 @@ + public final Settings<DedicatedServerProperties>.MutableValue<Boolean> whiteList; + public final boolean enforceSecureProfile; + public final boolean logIPs; +- public final int pauseWhenEmptySeconds; ++ public int pauseWhenEmptySeconds; + private final DedicatedServerProperties.WorldDimensionData worldDimensionData; + public final WorldOptions worldOptions; + public boolean acceptsTransfers; + +- public DedicatedServerProperties(Properties properties) { +- super(properties); ++ public final String rconIp; // Paper - Configurable rcon ip ++ ++ // CraftBukkit start ++ public DedicatedServerProperties(Properties properties, OptionSet optionset) { ++ super(properties, optionset); ++ // CraftBukkit end + this.difficulty = (Difficulty) this.get("difficulty", dispatchNumberOrString(Difficulty::byId, Difficulty::byName), Difficulty::getKey, Difficulty.EASY); + this.gamemode = (GameType) this.get("gamemode", dispatchNumberOrString(GameType::byId, GameType::byName), GameType::getName, GameType.SURVIVAL); + this.levelName = this.get("level-name", "world"); +@@ -137,7 +146,7 @@ + this.maxWorldSize = this.get("max-world-size", (integer) -> { + return Mth.clamp(integer, 1, 29999984); + }, 29999984); +- this.syncChunkWrites = this.get("sync-chunk-writes", true); ++ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - Hide sync chunk writes behind flag + this.regionFileComression = this.get("region-file-compression", "deflate"); + this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false); + this.enableStatus = this.get("enable-status", true); +@@ -151,7 +160,7 @@ + this.whiteList = this.getMutable("white-list", false); + this.enforceSecureProfile = this.get("enforce-secure-profile", true); + this.logIPs = this.get("log-ips", true); +- this.pauseWhenEmptySeconds = this.get("pause-when-empty-seconds", 60); ++ this.pauseWhenEmptySeconds = this.get("pause-when-empty-seconds", -1); // Paper - disable tick sleeping by default + this.acceptsTransfers = this.get("accepts-transfers", false); + String s = this.get("level-seed", ""); + boolean flag = this.get("generate-structures", true); +@@ -165,15 +174,21 @@ + }, WorldPresets.NORMAL.location().toString())); + this.serverResourcePackInfo = DedicatedServerProperties.getServerPackInfo(this.get("resource-pack-id", ""), this.get("resource-pack", ""), this.get("resource-pack-sha1", ""), this.getLegacyString("resource-pack-hash"), this.get("require-resource-pack", false), this.get("resource-pack-prompt", "")); + this.initialDataPackConfiguration = DedicatedServerProperties.getDatapackConfig(this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled()))); ++ // Paper start - Configurable rcon ip ++ final String rconIp = this.getStringRaw("rcon.ip"); ++ this.rconIp = rconIp == null ? this.serverIp : rconIp; ++ // Paper end - Configurable rcon ip + } + +- public static DedicatedServerProperties fromFile(Path path) { +- return new DedicatedServerProperties(loadFromFile(path)); ++ // CraftBukkit start ++ public static DedicatedServerProperties fromFile(Path path, OptionSet optionset) { ++ return new DedicatedServerProperties(loadFromFile(path), optionset); + } + + @Override +- protected DedicatedServerProperties reload(RegistryAccess registryManager, Properties properties) { +- return new DedicatedServerProperties(properties); ++ public DedicatedServerProperties reload(RegistryAccess iregistrycustom, Properties properties, OptionSet optionset) { ++ return new DedicatedServerProperties(properties, optionset); ++ // CraftBukkit end + } + + @Nullable +@@ -254,10 +269,10 @@ + }).orElseThrow(() -> { + return new IllegalStateException("Invalid datapack contents: can't find default preset"); + }); +- Optional optional = Optional.ofNullable(ResourceLocation.tryParse(this.levelType)).map((minecraftkey) -> { ++ Optional<ResourceKey<WorldPreset>> optional = Optional.ofNullable(ResourceLocation.tryParse(this.levelType)).map((minecraftkey) -> { // CraftBukkit - decompile error + return ResourceKey.create(Registries.WORLD_PRESET, minecraftkey); + }).or(() -> { +- return Optional.ofNullable((ResourceKey) DedicatedServerProperties.WorldDimensionData.LEGACY_PRESET_NAMES.get(this.levelType)); ++ return Optional.ofNullable(DedicatedServerProperties.WorldDimensionData.LEGACY_PRESET_NAMES.get(this.levelType)); // CraftBukkit - decompile error + }); + + Objects.requireNonNull(holderlookup); +@@ -269,7 +284,7 @@ + + if (holder.is(WorldPresets.FLAT)) { + RegistryOps<JsonElement> registryops = registries.createSerializationContext(JsonOps.INSTANCE); +- DataResult dataresult = FlatLevelGeneratorSettings.CODEC.parse(new Dynamic(registryops, this.generatorSettings())); ++ DataResult<FlatLevelGeneratorSettings> dataresult = FlatLevelGeneratorSettings.CODEC.parse(new Dynamic(registryops, this.generatorSettings())); // CraftBukkit - decompile error + Logger logger = DedicatedServerProperties.LOGGER; + + Objects.requireNonNull(logger); diff --git a/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch new file mode 100644 index 0000000000..0aaaffd34b --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/server/dedicated/DedicatedServerSettings.java.patch @@ -0,0 +1,27 @@ +--- a/net/minecraft/server/dedicated/DedicatedServerSettings.java ++++ b/net/minecraft/server/dedicated/DedicatedServerSettings.java +@@ -3,14 +3,21 @@ + import java.nio.file.Path; + import java.util.function.UnaryOperator; + ++// CraftBukkit start ++import java.io.File; ++import joptsimple.OptionSet; ++// CraftBukkit end ++ + public class DedicatedServerSettings { + + private final Path source; + private DedicatedServerProperties properties; + +- public DedicatedServerSettings(Path path) { +- this.source = path; +- this.properties = DedicatedServerProperties.fromFile(path); ++ // CraftBukkit start ++ public DedicatedServerSettings(OptionSet optionset) { ++ this.source = ((File) optionset.valueOf("config")).toPath(); ++ this.properties = DedicatedServerProperties.fromFile(this.source, optionset); ++ // CraftBukkit end + } + + public DedicatedServerProperties getProperties() { diff --git a/paper-server/patches/unapplied/net/minecraft/server/dedicated/Settings.java.patch b/paper-server/patches/unapplied/net/minecraft/server/dedicated/Settings.java.patch new file mode 100644 index 0000000000..300eeaa029 --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/server/dedicated/Settings.java.patch @@ -0,0 +1,179 @@ +--- a/net/minecraft/server/dedicated/Settings.java ++++ b/net/minecraft/server/dedicated/Settings.java +@@ -20,20 +20,41 @@ + import java.util.function.Supplier; + import java.util.function.UnaryOperator; + import javax.annotation.Nullable; +-import net.minecraft.core.RegistryAccess; + import org.slf4j.Logger; + ++import joptsimple.OptionSet; // CraftBukkit ++import net.minecraft.core.RegistryAccess; ++ + public abstract class Settings<T extends Settings<T>> { + + private static final Logger LOGGER = LogUtils.getLogger(); + public final Properties properties; ++ private static final boolean skipComments = Boolean.getBoolean("Paper.skipServerPropertiesComments"); // Paper - allow skipping server.properties comments ++ // CraftBukkit start ++ private OptionSet options = null; + +- public Settings(Properties properties) { ++ public Settings(Properties properties, final OptionSet options) { + this.properties = properties; ++ ++ this.options = options; + } + ++ private String getOverride(String name, String value) { ++ if ((this.options != null) && (this.options.has(name))) { ++ return String.valueOf(this.options.valueOf(name)); ++ } ++ ++ return value; ++ // CraftBukkit end ++ } ++ + public static Properties loadFromFile(Path path) { + try { ++ // CraftBukkit start - SPIGOT-7465, MC-264979: Don't load if file doesn't exist ++ if (!path.toFile().exists()) { ++ return new Properties(); ++ } ++ // CraftBukkit end + Properties properties; + Properties properties1; + +@@ -97,8 +118,53 @@ + + public void store(Path path) { + try { +- BufferedWriter bufferedwriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8); ++ // CraftBukkit start - Don't attempt writing to file if it's read only ++ if (path.toFile().exists() && !path.toFile().canWrite()) { ++ Settings.LOGGER.warn("Can not write to file {}, skipping.", path); // Paper - log message file is read-only ++ return; ++ } ++ // CraftBukkit end ++ // Paper start - allow skipping server.properties comments ++ java.io.OutputStream outputstream = Files.newOutputStream(path); ++ java.io.BufferedOutputStream bufferedOutputStream = !skipComments ? new java.io.BufferedOutputStream(outputstream) : new java.io.BufferedOutputStream(outputstream) { ++ private boolean isRightAfterNewline = true; // If last written char was newline ++ private boolean isComment = false; // Are we writing comment currently? ++ ++ @Override ++ public void write(@org.jetbrains.annotations.NotNull byte[] b) throws IOException { ++ this.write(b, 0, b.length); ++ } ++ ++ @Override ++ public void write(@org.jetbrains.annotations.NotNull byte[] bbuf, int off, int len) throws IOException { ++ int latest_offset = off; // The latest offset, updated when comment ends ++ for (int index = off; index < off + len; ++index ) { ++ byte c = bbuf[index]; ++ boolean isNewline = (c == '\n' || c == '\r'); ++ if (isNewline && this.isComment) { ++ // Comment has ended ++ this.isComment = false; ++ latest_offset = index+1; ++ } ++ if (c == '#' && this.isRightAfterNewline) { ++ this.isComment = true; ++ if (index != latest_offset) { ++ // We got some non-comment data earlier ++ super.write(bbuf, latest_offset, index-latest_offset); ++ } ++ } ++ this.isRightAfterNewline = isNewline; // Store for next iteration + ++ } ++ if (latest_offset < off+len && !this.isComment) { ++ // We have some unwritten data, that isn't part of a comment ++ super.write(bbuf, latest_offset, (off + len) - latest_offset); ++ } ++ } ++ }; ++ BufferedWriter bufferedwriter = new BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); ++ // Paper end - allow skipping server.properties comments ++ + try { + this.properties.store(bufferedwriter, "Minecraft server properties"); + } catch (Throwable throwable) { +@@ -125,7 +191,7 @@ + private static <V extends Number> Function<String, V> wrapNumberDeserializer(Function<String, V> parser) { + return (s) -> { + try { +- return (Number) parser.apply(s); ++ return (V) parser.apply(s); // CraftBukkit - decompile error + } catch (NumberFormatException numberformatexception) { + return null; + } +@@ -144,7 +210,7 @@ + + @Nullable + public String getStringRaw(String key) { +- return (String) this.properties.get(key); ++ return (String) this.getOverride(key, this.properties.getProperty(key)); // CraftBukkit + } + + @Nullable +@@ -160,10 +226,20 @@ + } + + protected <V> V get(String key, Function<String, V> parser, Function<V, String> stringifier, V fallback) { +- String s1 = this.getStringRaw(key); +- V v1 = MoreObjects.firstNonNull(s1 != null ? parser.apply(s1) : null, fallback); ++ // CraftBukkit start ++ try { ++ return this.get0(key, parser, stringifier, fallback); ++ } catch (Exception ex) { ++ throw new RuntimeException("Could not load invalidly configured property '" + key + "'", ex); ++ } ++ } + +- this.properties.put(key, stringifier.apply(v1)); ++ private <V> V get0(String s, Function<String, V> function, Function<V, String> function1, V v0) { ++ // CraftBukkit end ++ String s1 = this.getStringRaw(s); ++ V v1 = MoreObjects.firstNonNull(s1 != null ? function.apply(s1) : null, v0); ++ ++ this.properties.put(s, function1.apply(v1)); + return v1; + } + +@@ -172,7 +248,7 @@ + V v1 = MoreObjects.firstNonNull(s1 != null ? parser.apply(s1) : null, fallback); + + this.properties.put(key, stringifier.apply(v1)); +- return new Settings.MutableValue<>(key, v1, stringifier); ++ return new Settings.MutableValue(key, v1, stringifier); // CraftBukkit - decompile error + } + + protected <V> V get(String key, Function<String, V> parser, UnaryOperator<V> parsedTransformer, Function<V, String> stringifier, V fallback) { +@@ -236,7 +312,7 @@ + return properties; + } + +- protected abstract T reload(RegistryAccess registryManager, Properties properties); ++ protected abstract T reload(RegistryAccess iregistrycustom, Properties properties, OptionSet optionset); // CraftBukkit + + public class MutableValue<V> implements Supplier<V> { + +@@ -244,7 +320,7 @@ + private final V value; + private final Function<V, String> serializer; + +- MutableValue(final String s, final Object object, final Function function) { ++ MutableValue(final String s, final V object, final Function function) { // CraftBukkit - decompile error + this.key = s; + this.value = object; + this.serializer = function; +@@ -258,7 +334,7 @@ + Properties properties = Settings.this.cloneProperties(); + + properties.put(this.key, this.serializer.apply(value)); +- return Settings.this.reload(registryManager, properties); ++ return Settings.this.reload(registryManager, properties, Settings.this.options); // CraftBukkit + } + } + } |