From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Sun, 22 Oct 2023 09:35:07 -0300 Subject: [PATCH] SparklyPaper config files diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index dd56c8e041116ef3602a9f89c998c8208ab89b51..b7c39d2e93abbc5f988271d738490de68ce50b3b 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -238,6 +238,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface 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 + // SparklyPaper start + try { + net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((java.io.File) options.valueOf("sparklypaper-settings")); + } catch (Exception e) { + DedicatedServer.LOGGER.error("Unable to load server configuration", e); + return false; + } + net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this); + // SparklyPaper end com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now this.setPvpAllowed(dedicatedserverproperties.pvp); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index e2a0487089eb5a7bdc1433e4c75f69d8e9f9d5f9..d6c5c6090b455475098fe799d69389b3a137eb36 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -173,6 +173,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // Paper end - add paper world config public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray + public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper public final co.aikar.timings.WorldTimingsHandler timings; // Paper public static BlockPos lastPhysicsProblem; // Spigot private org.spigotmc.TickLimiter entityLimiter; @@ -687,6 +688,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config + this.sparklyPaperConfig = net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getWorldSettings(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // SparklyPaper this.generator = gen; this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); diff --git a/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java b/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..bc0ec96f91f7c9ab9f9a865a50f69707fab8fd27 --- /dev/null +++ b/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java @@ -0,0 +1,65 @@ +package net.sparklypower.sparklypaper.commands; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class SparklyPaperCommand extends Command { + public SparklyPaperCommand(String name) { + super(name); + this.description = "SparklyPaper related commands"; + this.usageMessage = "/sparklypaper [reload | version]"; + this.setPermission("bukkit.command.sparklypaper"); + } + + @Override + public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { + if (args.length == 1) { + return Stream.of("reload", "version") + .filter(arg -> arg.startsWith(args[0].toLowerCase())) + .collect(Collectors.toList()); + } + return Collections.emptyList(); + } + + @Override + public boolean execute(CommandSender sender, String commandLabel, String[] args) { + if (!testPermission(sender)) return true; + + if (args.length != 1) { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } + + if (args[0].equalsIgnoreCase("reload")) { + Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues."); + Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server."); + + MinecraftServer console = MinecraftServer.getServer(); + SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings")); + for (ServerLevel level : console.getAllLevels()) { + level.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(level.serverLevelData.getLevelName()); + } + console.server.reloadCount++; + + Command.broadcastCommandMessage(sender, ChatColor.GREEN + "SparklyPaper config reload complete."); + } else if (args[0].equalsIgnoreCase("version")) { + Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version"); + if (verCmd != null) { + return verCmd.execute(sender, commandLabel, new String[0]); + } + } + + return true; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 1b36e94617d4e777c419660936460d5cf8a4b3e8..cfd75fdc75866a70008837b4b0e2e6a3bad3da16 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -111,6 +111,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.level.validation.ContentValidationException; import net.minecraft.world.phys.Vec3; +import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils; import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -1070,6 +1071,7 @@ public final class CraftServer implements Server { org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot this.console.paperConfigurations.reloadConfigs(this.console); + net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings")); // SparklyPaper for (ServerLevel world : this.console.getAllLevels()) { // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) @@ -1085,6 +1087,7 @@ public final class CraftServer implements Server { } } world.spigotConfig.init(); // Spigot + world.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(world.serverLevelData.getLevelName()); // SparklyPaper } Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper @@ -1102,6 +1105,7 @@ public final class CraftServer implements Server { org.spigotmc.SpigotConfig.registerCommands(); // Spigot io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper this.spark.registerCommandBeforePlugins(this); // Paper - spark + net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this.console); // SparklyPaper this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java index c1e88c31910e96ef07cece05046c0b55e708b52d..913249209d9c22ad4d111b49d1d1eeeab163b13a 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java @@ -176,6 +176,14 @@ public class Main { .describedAs("Jar file"); // Paper end + // SparklyPaper Start + acceptsAll(asList("sparklypaper", "sparklypaper-settings"), "File for SparklyPaper settings") + .withRequiredArg() + .ofType(File.class) + .defaultsTo(new File("sparklypaper.yml")) + .describedAs("Yml file"); + // SparklyPaper end + // Paper start acceptsAll(asList("server-name"), "Name of the server") .withRequiredArg() diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt b/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt new file mode 100644 index 0000000000000000000000000000000000000000..614e64ce6bf5bb7fab5758250927a0d3949d0917 --- /dev/null +++ b/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt @@ -0,0 +1,22 @@ +package net.sparklypower.sparklypaper + +import net.minecraft.server.MinecraftServer +import net.sparklypower.sparklypaper.commands.SparklyPaperCommand +import org.bukkit.command.Command +import org.checkerframework.checker.nullness.qual.NonNull +import org.checkerframework.framework.qual.DefaultQualifier + +@DefaultQualifier(NonNull::class) +object SparklyPaperCommands { + private val COMMANDS = mapOf( + "sparklypaper" to SparklyPaperCommand("sparklypaper") + ) + + fun registerCommands(server: MinecraftServer) { + COMMANDS.forEach { (s: String, command: Command) -> + server.server.commandMap.register( + s, "SparklyPaper", command + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt new file mode 100644 index 0000000000000000000000000000000000000000..f633fe54c176c4e6ec46e54078f8485efadf0fce --- /dev/null +++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt @@ -0,0 +1,50 @@ +package net.sparklypower.sparklypaper.configs + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +class SparklyPaperConfig( + @SerialName("config-version") + override val configVersion: Int, + @SerialName("parallel-world-ticking") + val parallelWorldTicking: ParallelWorldTicking, + @SerialName("world-settings") + val worldSettings: Map +) : UpgradeableConfig { + override fun isNewest() = true + + override fun upgradeToNext() = error("This config is already the newest version!") + + @Serializable + class ParallelWorldTicking( + val threads: Int + ) + + @Serializable + class SparklyPaperWorldConfig( + @SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer") + val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean, + @SerialName("blazingly-simple-farm-checks") + val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks, + @SerialName("ticks-per") + val ticksPer: TicksPer, + ) { + @Serializable + data class BlazinglySimpleFarmChecks( + val enabled: Boolean, + @SerialName("default-growth-speed") + val defaultGrowthSpeed: Float, + @SerialName("moist-growth-speed") + val moistGrowthSpeed: Float, + @SerialName("skip-middle-aging-stages-for-crops") + val skipMiddleAgingStagesForCrops: Boolean + ) + + @Serializable + data class TicksPer( + @SerialName("hopper-cooldown-when-target-container-is-full") + val hopperCooldownWhenTargetContainerIsFull: Int + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..072b5811acf9ecc58e3bba7f74dc0dcf8556e848 --- /dev/null +++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt @@ -0,0 +1,93 @@ +package net.sparklypower.sparklypaper.configs + +import com.charleskorn.kaml.* +import com.google.common.base.Throwables +import kotlinx.serialization.SerializationException +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import net.sparklypower.sparklypaper.configs.previous.SparklyPaperConfigV1 +import org.bukkit.Bukkit +import java.io.File +import java.util.logging.Level + +object SparklyPaperConfigUtils { + private const val CURRENT_CONFIG_VERSION = 2 + val yaml = Yaml( + configuration = YamlConfiguration( + strictMode = false + ) + ) + val deserializationStrategiesForVersions = mapOf( + 1 to SparklyPaperConfigV1.serializer(), + CURRENT_CONFIG_VERSION to SparklyPaperConfig.serializer() + ) + + lateinit var config: SparklyPaperConfig + + fun init(configFile: File) { + // Write default config if the file doesn't exist + if (!configFile.exists()) { + configFile.writeText( + yaml.encodeToString( + SparklyPaperConfig( + CURRENT_CONFIG_VERSION, + SparklyPaperConfig.ParallelWorldTicking( + threads = 8 + ), + mapOf( + "default" to SparklyPaperConfig.SparklyPaperWorldConfig( + skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true, + blazinglySimpleFarmChecks = SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks( + enabled = false, + defaultGrowthSpeed = 1.0f, + moistGrowthSpeed = 5.0f, + skipMiddleAgingStagesForCrops = true + ), + SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer( + hopperCooldownWhenTargetContainerIsFull = 0 + ) + ) + ) + ) + ) + ) + } + + val loadedConfig = try { + // Read the version file from the config before attempting to parse + val yamlNode = yaml.parseToYamlNode(configFile.readText()) + var configVersion = yamlNode.yamlMap.getScalar("config-version")?.toInt() ?: 1 // The first config version didn't have the "config-version" key + + if (configVersion != CURRENT_CONFIG_VERSION) { + var upgradedVersion: UpgradeableConfig? = null + + while (configVersion != CURRENT_CONFIG_VERSION) { + Bukkit.getLogger().log(Level.INFO, "Attempting to upgrade SparklyPaper Config from version $configVersion to the next version...") + + val upgradeableConfig = yaml.decodeFromYamlNode(deserializationStrategiesForVersions[configVersion]!!, yamlNode) + if (!upgradeableConfig.isNewest()) { + upgradedVersion = upgradeableConfig.upgradeToNext() + + Bukkit.getLogger().log(Level.INFO, "Upgraded SparklyPaper Config from version $configVersion to ${upgradedVersion.configVersion}") + configVersion = upgradedVersion.configVersion + } + } + + upgradedVersion as SparklyPaperConfig + } else { + yaml.decodeFromYamlNode(SparklyPaperConfig.serializer(), yamlNode) + } + } catch (e: SerializationException) { + Bukkit.getLogger().log(Level.SEVERE, "Could not load sparklypaper.yml, please correct your syntax errors", e) + throw Throwables.propagate(e) + } + // Rewrite the config file to remove old fields and stuff + // TODO: Maybe handle this in another way? This feels kinda bad + configFile.writeText(yaml.encodeToString(loadedConfig)) + config = loadedConfig + } + + fun getWorldSettings(levelName: String): SparklyPaperConfig.SparklyPaperWorldConfig { + return config.worldSettings[levelName] ?: config.worldSettings["default"] ?: error("Missing default world-settings in sparklypaper.yml!") + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt new file mode 100644 index 0000000000000000000000000000000000000000..e6de89ef69bd492a9e9facaa189e260678e2c6e6 --- /dev/null +++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt @@ -0,0 +1,7 @@ +package net.sparklypower.sparklypaper.configs + +interface UpgradeableConfig { + abstract val configVersion: Int + fun isNewest(): Boolean + fun upgradeToNext(): UpgradeableConfig +} \ No newline at end of file diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt new file mode 100644 index 0000000000000000000000000000000000000000..fe86a557388cea29dfad8ba5e3990e3272cf0c55 --- /dev/null +++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt @@ -0,0 +1,65 @@ +package net.sparklypower.sparklypaper.configs.previous + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.sparklypower.sparklypaper.configs.SparklyPaperConfig +import net.sparklypower.sparklypaper.configs.UpgradeableConfig + +@Serializable +class SparklyPaperConfigV1( + @SerialName("parallel-world-ticking") + val parallelWorldTicking: ParallelWorldTicking, + @SerialName("world-settings") + val worldSettings: Map +) : UpgradeableConfig { + override val configVersion = 1 + + override fun isNewest() = false + + override fun upgradeToNext(): UpgradeableConfig { + return SparklyPaperConfig( + 2, + SparklyPaperConfig.ParallelWorldTicking( + this.parallelWorldTicking.threads + ), + worldSettings.mapValues { + SparklyPaperConfig.SparklyPaperWorldConfig( + it.value.skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer, + SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks( + it.value.blazinglySimpleFarmChecks.enabled, + it.value.blazinglySimpleFarmChecks.defaultGrowthSpeed, + it.value.blazinglySimpleFarmChecks.moistGrowthSpeed, + it.value.blazinglySimpleFarmChecks.skipMiddleAgingStagesForCrops, + ), + SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer( + 0 + ) + ) + } + ) + } + + @Serializable + class ParallelWorldTicking( + val threads: Int + ) + + @Serializable + class SparklyPaperWorldConfig( + @SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer") + val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean, + @SerialName("blazingly-simple-farm-checks") + val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks + ) { + @Serializable + data class BlazinglySimpleFarmChecks( + val enabled: Boolean, + @SerialName("default-growth-speed") + val defaultGrowthSpeed: Float, + @SerialName("moist-growth-speed") + val moistGrowthSpeed: Float, + @SerialName("skip-middle-aging-stages-for-crops") + val skipMiddleAgingStagesForCrops: Boolean + ) + } +} \ No newline at end of file