From 0d379fdd6b7c9a35a65f0741882ec0e6ca5964e8 Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 10 Feb 2019 16:38:14 -0500 Subject: [PATCH] Fix config to use new system properly, without exploding the server. Separates server specific config into the server config file. Signed-off-by: cpw --- .../entity/monster/EntityZombie.java.patch | 4 +- .../management/PlayerChunkMapEntry.java.patch | 2 +- .../net/minecraft/world/World.java.patch | 6 +- .../minecraftforge/fml/loading/FMLConfig.java | 13 +- .../resources/META-INF/defaultfmlconfig.toml | 2 + .../common/DimensionManager.java | 3 +- .../minecraftforge/common/ForgeConfig.java | 154 +++++++++--------- .../common/ForgeConfigSpec.java | 12 ++ .../net/minecraftforge/common/ForgeHooks.java | 2 +- .../net/minecraftforge/common/ForgeMod.java | 11 +- .../minecraftforge/fml/VersionChecker.java | 8 +- .../minecraftforge/fml/config/ModConfig.java | 20 ++- 12 files changed, 134 insertions(+), 103 deletions(-) diff --git a/patches/minecraft/net/minecraft/entity/monster/EntityZombie.java.patch b/patches/minecraft/net/minecraft/entity/monster/EntityZombie.java.patch index 744596f22..4f6ac7e63 100644 --- a/patches/minecraft/net/minecraft/entity/monster/EntityZombie.java.patch +++ b/patches/minecraft/net/minecraft/entity/monster/EntityZombie.java.patch @@ -5,7 +5,7 @@ this.func_110148_a(SharedMonsterAttributes.field_111264_e).func_111128_a(3.0D); this.func_110148_a(SharedMonsterAttributes.field_188791_g).func_111128_a(2.0D); - this.func_110140_aT().func_111150_b(field_110186_bp).func_111128_a(this.field_70146_Z.nextDouble() * (double)0.1F); -+ this.func_110140_aT().func_111150_b(field_110186_bp).func_111128_a(this.field_70146_Z.nextDouble() * net.minecraftforge.common.ForgeConfig.GENERAL.zombieBaseSummonChance.get()); ++ this.func_110140_aT().func_111150_b(field_110186_bp).func_111128_a(this.field_70146_Z.nextDouble() * net.minecraftforge.common.ForgeConfig.SERVER.zombieBaseSummonChance.get()); } protected void func_70088_a() { @@ -52,7 +52,7 @@ this.func_98053_h(this.field_70146_Z.nextFloat() < 0.55F * f); if (p_204210_2_ == null) { - p_204210_2_ = new EntityZombie.GroupData(this.field_70170_p.field_73012_v.nextFloat() < 0.05F); -+ p_204210_2_ = new EntityZombie.GroupData(this.field_70170_p.field_73012_v.nextFloat() < net.minecraftforge.common.ForgeConfig.GENERAL.zombieBabyChance.get()); ++ p_204210_2_ = new EntityZombie.GroupData(this.field_70170_p.field_73012_v.nextFloat() < net.minecraftforge.common.ForgeConfig.SERVER.zombieBabyChance.get()); } if (p_204210_2_ instanceof EntityZombie.GroupData) { diff --git a/patches/minecraft/net/minecraft/server/management/PlayerChunkMapEntry.java.patch b/patches/minecraft/net/minecraft/server/management/PlayerChunkMapEntry.java.patch index 1654bbb0f..265e63674 100644 --- a/patches/minecraft/net/minecraft/server/management/PlayerChunkMapEntry.java.patch +++ b/patches/minecraft/net/minecraft/server/management/PlayerChunkMapEntry.java.patch @@ -104,7 +104,7 @@ this.func_187273_a(this.field_187282_b.func_72688_a().func_175625_s(blockpos)); } - } else if (this.field_187287_g == 64) { -+ } else if (this.field_187287_g >= net.minecraftforge.common.ForgeConfig.GENERAL.clumpingThreshold.get()) { ++ } else if (this.field_187287_g >= net.minecraftforge.common.ForgeConfig.SERVER.clumpingThreshold.get()) { this.func_187267_a(new SPacketChunkData(this.field_187286_f, this.field_187288_h)); + //TODO: Fix Mojang's fuckup to modded by combining all TE data into the chunk data packet... seriously... packet size explosion! } else { diff --git a/patches/minecraft/net/minecraft/world/World.java.patch b/patches/minecraft/net/minecraft/world/World.java.patch index e2bbb290a..aa5b7f7ce 100644 --- a/patches/minecraft/net/minecraft/world/World.java.patch +++ b/patches/minecraft/net/minecraft/world/World.java.patch @@ -405,7 +405,7 @@ entity.func_85029_a(crashreportcategory); } -+ if (net.minecraftforge.common.ForgeConfig.GENERAL.removeErroringEntities.get()) { ++ if (net.minecraftforge.common.ForgeConfig.SERVER.removeErroringEntities.get()) { + LogManager.getLogger().fatal("{}", crashreport.func_71502_e()); + func_72900_e(entity); + } else @@ -423,7 +423,7 @@ CrashReport crashreport1 = CrashReport.func_85055_a(throwable1, "Ticking entity"); CrashReportCategory crashreportcategory1 = crashreport1.func_85058_a("Entity being ticked"); entity2.func_85029_a(crashreportcategory1); -+ if (net.minecraftforge.common.ForgeConfig.GENERAL.removeErroringEntities.get()) { ++ if (net.minecraftforge.common.ForgeConfig.SERVER.removeErroringEntities.get()) { + LogManager.getLogger().fatal("{}", crashreport1.func_71502_e()); + func_72900_e(entity2); + } else @@ -468,7 +468,7 @@ CrashReport crashreport2 = CrashReport.func_85055_a(throwable, "Ticking block entity"); CrashReportCategory crashreportcategory2 = crashreport2.func_85058_a("Block entity being ticked"); tileentity.func_145828_a(crashreportcategory2); -+ if (net.minecraftforge.common.ForgeConfig.GENERAL.removeErroringTileEntities.get()) { ++ if (net.minecraftforge.common.ForgeConfig.SERVER.removeErroringTileEntities.get()) { + LogManager.getLogger().fatal("{}", crashreport2.func_71502_e()); + tileentity.func_145843_s(); + this.func_175713_t(tileentity.func_174877_v()); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLConfig.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLConfig.java index 5ec8f957d..ec26e01a0 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLConfig.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLConfig.java @@ -40,6 +40,7 @@ public class FMLConfig static { configSpec.define("splashscreen", Boolean.TRUE); configSpec.define("maxThreads", -1); + configSpec.define("versionCheck", Boolean.TRUE); } private CommentedFileConfig configData; @@ -64,8 +65,10 @@ public class FMLConfig { final Path configFile = FMLPaths.FMLCONFIG.get(); INSTANCE.loadFrom(configFile); - LOGGER.debug(CORE, "Loaded FML config from {}", FMLPaths.FMLCONFIG.get()); - LOGGER.debug(CORE, "Splash screen is {}", INSTANCE.splashScreenEnabled()); + LOGGER.trace(CORE, "Loaded FML config from {}", FMLPaths.FMLCONFIG.get()); + LOGGER.trace(CORE, "Splash screen is {}", FMLConfig::splashScreenEnabled); + LOGGER.trace(CORE, "Max threads for mod loading computed at {}", FMLConfig::loadingThreadCount); + LOGGER.trace(CORE, "Version check is {}", FMLConfig::runVersionCheck); } public static boolean splashScreenEnabled() { @@ -73,8 +76,12 @@ public class FMLConfig } public static int loadingThreadCount() { - int val = INSTANCE.configData.get("maxThreads"); + int val = INSTANCE.configData.getOptional("maxThreads").orElse(-1); if (val <= 0) return Runtime.getRuntime().availableProcessors(); return val; } + + public static boolean runVersionCheck() { + return INSTANCE.configData.getOptional("versionCheck").orElse(Boolean.TRUE); + } } diff --git a/src/fmllauncher/resources/META-INF/defaultfmlconfig.toml b/src/fmllauncher/resources/META-INF/defaultfmlconfig.toml index dd5a6903d..7e899b418 100644 --- a/src/fmllauncher/resources/META-INF/defaultfmlconfig.toml +++ b/src/fmllauncher/resources/META-INF/defaultfmlconfig.toml @@ -2,3 +2,5 @@ splashscreen = true # max threads for parallel loading : -1 uses Runtime#availableProcessors maxThreads = -1 +# Enable forge global version checking +versionCheck = true diff --git a/src/main/java/net/minecraftforge/common/DimensionManager.java b/src/main/java/net/minecraftforge/common/DimensionManager.java index 08cfb4374..29088cfdc 100644 --- a/src/main/java/net/minecraftforge/common/DimensionManager.java +++ b/src/main/java/net/minecraftforge/common/DimensionManager.java @@ -23,7 +23,6 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; -import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.List; import java.util.ListIterator; @@ -395,7 +394,7 @@ public class DimensionManager { int id = queueIterator.nextInt(); DimensionData dimension = dimensions.get(id); - if (dimension.ticksWaited < ForgeConfig.GENERAL.dimensionUnloadQueueDelay.get()) + if (dimension.ticksWaited < ForgeConfig.SERVER.dimensionUnloadQueueDelay.get()) { dimension.ticksWaited++; continue; diff --git a/src/main/java/net/minecraftforge/common/ForgeConfig.java b/src/main/java/net/minecraftforge/common/ForgeConfig.java index a8dc7a3f6..610f9d536 100644 --- a/src/main/java/net/minecraftforge/common/ForgeConfig.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfig.java @@ -22,43 +22,30 @@ package net.minecraftforge.common; import static net.minecraftforge.fml.Logging.CORE; import static net.minecraftforge.fml.loading.LogMarkers.FORGEMOD; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -import javax.annotation.Nullable; - -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.config.ModConfig; -import org.apache.logging.log4j.LogManager; - import com.electronwill.nightconfig.core.CommentedConfig; import com.google.common.collect.Lists; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.config.ModConfig; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; -import net.minecraftforge.common.ForgeConfigSpec.ConfigValue; import net.minecraftforge.common.ForgeConfigSpec.DoubleValue; import net.minecraftforge.common.ForgeConfigSpec.IntValue; -import net.minecraftforge.fml.loading.FMLPaths; + +import javax.annotation.Nullable; +import java.util.List; public class ForgeConfig -{ - private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); - - public static final General GENERAL = new General(BUILDER); - public static final Client CLIENT = new Client(BUILDER); - - public static class General { - - public final BooleanValue disableVersionCheck; - - public final BooleanValue removeErroringEntities; +{ + public static class Server { + public final BooleanValue removeErroringEntities; public final BooleanValue removeErroringTileEntities; public final BooleanValue fullBoundingBoxLadders; public final DoubleValue zombieBaseSummonChance; - public final DoubleValue zombieBabyChance ; + public final DoubleValue zombieBabyChance; public final BooleanValue logCascadingWorldGeneration; public final BooleanValue fixVanillaCascading; @@ -67,14 +54,9 @@ public class ForgeConfig public final IntValue clumpingThreshold; - General(ForgeConfigSpec.Builder builder) { - builder.comment("General settings that effect both the client and server") - .push("general"); - - disableVersionCheck = builder - .comment("Set to true to disable Forge's version check mechanics. Forge queries a small json file on our server for version information. For more details see the ForgeVersion class in our github.") - .translation("forge.configgui.disableVersionCheck") - .define("disableVersionCheck", false); + Server(ForgeConfigSpec.Builder builder) { + builder.comment("Server configuration settings") + .push("server"); removeErroringEntities = builder .comment("Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.") @@ -130,7 +112,10 @@ public class ForgeConfig builder.pop(); } } - + + /** + * Client specific configuration - only loaded clientside from forge-client.toml + */ public static class Client { public final BooleanValue zoomInMissingModelTextInGui; @@ -184,14 +169,31 @@ public class ForgeConfig } } - static final ForgeConfigSpec spec = BUILDER.build(); - + static final ForgeConfigSpec clientSpec; + public static final Client CLIENT; + static { + final Pair specPair = new ForgeConfigSpec.Builder().configure(Client::new); + clientSpec = specPair.getRight(); + CLIENT = specPair.getLeft(); + } + + + static final ForgeConfigSpec serverSpec; + public static final Server SERVER; + static { + final Pair specPair = new ForgeConfigSpec.Builder().configure(Server::new); + serverSpec = specPair.getRight(); + SERVER = specPair.getLeft(); + } + + + private static final ForgeConfigSpec.Builder CHUNK_BUILDER = new ForgeConfigSpec.Builder(); - + public static final Chunk CHUNK = new Chunk(CHUNK_BUILDER); - + public static class Chunk { - + public final BooleanValue enable; public final IntValue chunksPerTicket; @@ -209,61 +211,61 @@ public class ForgeConfig .defineInRange("maxTickets", 200, 0, Integer.MAX_VALUE).next() .defineInRange("chunksPerTicket", 25, 0, Integer.MAX_VALUE).next() .build(); - + private final CommentedConfig modCfgDefault = CommentedConfig.inMemory(); - + Chunk(ForgeConfigSpec.Builder builder) { builder.comment("Default configuration for Forge chunk loading control") - .push("defaults"); - + .push("defaults"); + enable = builder - .comment("Allow mod overrides, false will use default for everything.") - .translation("forge.configgui.enableModOverrides") - .define("enable", true); - + .comment("Allow mod overrides, false will use default for everything.") + .translation("forge.configgui.enableModOverrides") + .define("enable", true); + chunksPerTicket = builder - .comment("The default maximum number of chunks a mod can force, per ticket,", - "for a mod without an override. This is the maximum number of chunks a single ticket can force.") - .translation("forge.configgui.maximumChunksPerTicket") - .defineInRange("chunksPerTicket", 25, 0, Integer.MAX_VALUE); - + .comment("The default maximum number of chunks a mod can force, per ticket,", + "for a mod without an override. This is the maximum number of chunks a single ticket can force.") + .translation("forge.configgui.maximumChunksPerTicket") + .defineInRange("chunksPerTicket", 25, 0, Integer.MAX_VALUE); + maxTickets = builder - .comment("The default maximum ticket count for a mod which does not have an override", - "in this file. This is the number of chunk loading requests a mod is allowed to make.") - .translation("forge.configgui.maximumTicketCount") - .defineInRange("maxTickets", 200, 0, Integer.MAX_VALUE); - + .comment("The default maximum ticket count for a mod which does not have an override", + "in this file. This is the number of chunk loading requests a mod is allowed to make.") + .translation("forge.configgui.maximumTicketCount") + .defineInRange("maxTickets", 200, 0, Integer.MAX_VALUE); + playerTicketCount = builder - .comment("The number of tickets a player can be assigned instead of a mod. This is shared across all mods and it is up to the mods to use it.") - .translation("forge.configgui.playerTicketCount") - .defineInRange("playerTicketCount", 500, 0, Integer.MAX_VALUE); - + .comment("The number of tickets a player can be assigned instead of a mod. This is shared across all mods and it is up to the mods to use it.") + .translation("forge.configgui.playerTicketCount") + .defineInRange("playerTicketCount", 500, 0, Integer.MAX_VALUE); + dormantChunkCacheSize = builder - .comment("Unloaded chunks can first be kept in a dormant cache for quicker loading times. Specify the size (in chunks) of that cache here") - .translation("forge.configgui.dormantChunkCacheSize") - .defineInRange("dormantChunkCacheSize", 0, 0, Integer.MAX_VALUE); - + .comment("Unloaded chunks can first be kept in a dormant cache for quicker loading times. Specify the size (in chunks) of that cache here") + .translation("forge.configgui.dormantChunkCacheSize") + .defineInRange("dormantChunkCacheSize", 0, 0, Integer.MAX_VALUE); + asyncChunkLoading = builder - .comment("Load chunks asynchronously for players, reducing load on the server thread.", - "Can be disabled to help troubleshoot chunk loading issues.") - .translation("forge.configgui.asyncChunkLoading") - .define("asyncChunkLoading", true); - + .comment("Load chunks asynchronously for players, reducing load on the server thread.", + "Can be disabled to help troubleshoot chunk loading issues.") + .translation("forge.configgui.asyncChunkLoading") + .define("asyncChunkLoading", true); + chunkSpec.correct(modCfgDefault); builder.pop(); } - - private final ConfigValue> mods = CHUNK_BUILDER + + private final ForgeConfigSpec.ConfigValue> mods = CHUNK_BUILDER .defineList("mods", Lists.newArrayList(modCfgDefault), o -> { if (!(o instanceof CommentedConfig)) return false; return chunkSpec.isCorrect((CommentedConfig) o); }); - - private int getByMod(ConfigValue def, String name, String modid) { + + private int getByMod(ForgeConfigSpec.ConfigValue def, String name, String modid) { if (!enable.get() || modid == null) return def.get(); - + return mods.get().stream().filter(c -> modid.equals(c.get("modid"))).findFirst() .map(c -> c.get(name)) .orElseGet(def::get); @@ -272,12 +274,12 @@ public class ForgeConfig public int maxTickets(@Nullable String modid) { return getByMod(maxTickets, "maxTickets", modid); } - + public int chunksPerTicket(@Nullable String modid) { return getByMod(chunksPerTicket, "chunksPerTicket", modid); } } - + public static final ForgeConfigSpec chunk_spec = CHUNK_BUILDER.build(); diff --git a/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java b/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java index 0a9325dc8..156569113 100644 --- a/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java @@ -36,9 +36,12 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import com.electronwill.nightconfig.core.CommentedConfig; @@ -434,6 +437,11 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper return this; } + public Pair configure(Function consumer) { + T o = consumer.apply(this); + return Pair.of(o, this.build()); + } + public ForgeConfigSpec build() { context.ensureEmpty(); @@ -441,6 +449,10 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper values.forEach(v -> v.spec = ret); return ret; } + + public interface BuilderConsumer { + void accept(Builder builder); + } } private static class BuilderContext diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 405d6660f..2da66c17e 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -401,7 +401,7 @@ public class ForgeHooks { boolean isSpectator = (entity instanceof EntityPlayer && ((EntityPlayer)entity).isSpectator()); if (isSpectator) return false; - if (!ForgeConfig.GENERAL.fullBoundingBoxLadders.get()) + if (!ForgeConfig.SERVER.fullBoundingBoxLadders.get()) { return state.getBlock().isLadder(state, world, pos, entity); } diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 2edfa2893..d442ad268 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -22,6 +22,7 @@ package net.minecraftforge.common; import net.minecraftforge.fml.FMLWorldPersistenceHook; import net.minecraftforge.fml.VersionChecker; import net.minecraftforge.fml.WorldPersistenceHooks; +import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.lifecycle.FMLModIdMappingEvent; @@ -91,14 +92,10 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook MinecraftForge.EVENT_BUS.addListener(this::serverStarting); MinecraftForge.EVENT_BUS.addListener(this::playerLogin); MinecraftForge.EVENT_BUS.addListener(this::serverStopping); - /* - FMLModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.spec); - FMLModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ForgeConfig.chunk_spec); + FMLModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, ForgeConfig.clientSpec); + FMLModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, ForgeConfig.serverSpec); FMLModLoadingContext.get().getModEventBus().register(ForgeConfig.class); - */ - //Temporary, until I can talk to CPW about how certian types of config setups - loadConfig(ForgeConfig.spec, FMLPaths.CONFIGDIR.get().resolve("forge.toml")); - loadConfig(ForgeConfig.chunk_spec, FMLPaths.CONFIGDIR.get().resolve("forge_chunk.toml")); + loadConfig(ForgeConfig.chunk_spec, FMLPaths.CONFIGDIR.get().resolve("forge_chunks.toml")); } private void loadConfig(ForgeConfigSpec spec, Path path) { diff --git a/src/main/java/net/minecraftforge/fml/VersionChecker.java b/src/main/java/net/minecraftforge/fml/VersionChecker.java index 654897832..3fae2c9ae 100644 --- a/src/main/java/net/minecraftforge/fml/VersionChecker.java +++ b/src/main/java/net/minecraftforge/fml/VersionChecker.java @@ -22,6 +22,7 @@ package net.minecraftforge.fml; import com.google.common.io.ByteStreams; import com.google.gson.Gson; import net.minecraftforge.common.ForgeConfig; +import net.minecraftforge.fml.loading.FMLConfig; import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import net.minecraftforge.forgespi.language.IModInfo; import net.minecraftforge.versions.mcp.MCPVersion; @@ -131,16 +132,13 @@ public class VersionChecker @Override public void run() { - if (ForgeConfig.GENERAL.disableVersionCheck.get()) + if (!FMLConfig.runVersionCheck()) { LOGGER.info("Global Forge version check system disabled, no further processing."); return; } - for (IModInfo entry : gatherMods()) - { - process(entry); - } + gatherMods().forEach(this::process); } /** diff --git a/src/main/java/net/minecraftforge/fml/config/ModConfig.java b/src/main/java/net/minecraftforge/fml/config/ModConfig.java index 617483a59..e897d1b26 100644 --- a/src/main/java/net/minecraftforge/fml/config/ModConfig.java +++ b/src/main/java/net/minecraftforge/fml/config/ModConfig.java @@ -86,8 +86,19 @@ public class ModConfig public enum Type { /** - * Client type config is exclusively for configuration affecting the client state. - * Graphical options, for example. + * Common mod config for configuration that needs to be loaded on both environments. + * Loaded on both servers and clients. + * Stored in the global config directory. + * Not synced. + * Suffix is "-common" by default. + */ + COMMON, + /** + * Client config is for configuration affecting the ONLY client state such as graphical options. + * Only loaded on the client side. + * Stored in the global config directory. + * Not synced. + * Suffix is "-client" by default. */ CLIENT, // /** @@ -97,7 +108,10 @@ public class ModConfig // PLAYER, /** * Server type config is configuration that is associated with a server instance. - * It will be synced from a server to the client on connection. + * Only loaded during server startup. + * Stored in a server/save specific "serverconfig" directory. + * Synced to clients during connection. + * Suffix is "-server" by default. */ SERVER;