diff --git a/src/main/java/net/minecraftforge/common/ForgeChunkManager.java b/src/main/java/net/minecraftforge/common/ForgeChunkManager.java index ee8d5519e..1fd38c656 100644 --- a/src/main/java/net/minecraftforge/common/ForgeChunkManager.java +++ b/src/main/java/net/minecraftforge/common/ForgeChunkManager.java @@ -20,12 +20,9 @@ package net.minecraftforge.common; import java.io.*; -import java.util.ArrayList; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -53,9 +50,6 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.IChunk; import net.minecraft.world.chunk.storage.AnvilChunkLoader; import net.minecraft.world.storage.ThreadedFileIOBase; -import net.minecraftforge.common.config.ConfigCategory; -import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.common.config.Property; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fml.server.ServerLifecycleHooks; import net.minecraftforge.fml.ModContainer; @@ -98,13 +92,8 @@ public class ForgeChunkManager { public static Marker CHUNK_MANAGER = MarkerManager.getMarker("CHUNKMANAGER"); private static Logger LOGGER = LogManager.getLogger(); - private static int defaultMaxCount; - private static int defaultMaxChunks; - private static boolean overridesEnabled; private static Map> tickets = new MapMaker().weakKeys().makeMap(); - private static Map ticketConstraints = Maps.newHashMap(); - private static Map chunkConstraints = Maps.newHashMap(); private static SetMultimap playerTickets = HashMultimap.create(); @@ -115,23 +104,10 @@ public class ForgeChunkManager private static Map> dormantChunkCache = new MapMaker().weakKeys().makeMap(); - private static File cfgFile; - private static Configuration config; - private static int playerTicketLength; - private static int dormantChunkCacheSize; - public static boolean asyncChunkLoading; - public static final List MOD_PROP_ORDER = new ArrayList(2); - private static Set warnedMods = Sets.newHashSet(); - static - { - MOD_PROP_ORDER.add("maximumTicketCount"); - MOD_PROP_ORDER.add("maximumChunksPerTicket"); - } - private static class ChunkEntry { public final Chunk chunk; @@ -246,7 +222,7 @@ public class ForgeChunkManager this.modId = modId; this.ticketType = type; this.world = world; - this.maxDepth = getMaxChunkDepthFor(modId); + this.maxDepth = ForgeConfig.CHUNK.chunksPerTicket(modId); this.requestedChunks = Sets.newLinkedHashSet(); } @@ -271,9 +247,10 @@ public class ForgeChunkManager */ public void setChunkListDepth(int depth) { - if (depth > getMaxChunkDepthFor(modId) || (depth <= 0 && getMaxChunkDepthFor(modId) > 0)) + + if (depth > maxDepth || (depth <= 0 && maxDepth > 0)) { - LOGGER.warn(CHUNK_MANAGER, "The mod {} tried to modify the chunk ticket depth to: {}, its allowed maximum is: {}", modId, depth, getMaxChunkDepthFor(modId)); + LOGGER.warn(CHUNK_MANAGER, "The mod {} tried to modify the chunk ticket depth to: {}, its allowed maximum is: {}", modId, depth, maxDepth); } else { @@ -300,7 +277,7 @@ public class ForgeChunkManager */ public int getMaxChunkListDepth() { - return getMaxChunkDepthFor(modId); + return maxDepth; } /** @@ -471,9 +448,9 @@ public class ForgeChunkManager return; } - if (dormantChunkCacheSize != 0) + if (ForgeConfig.CHUNK.dormantChunkCacheSize() != 0) { // only put into cache if we're using dormant chunk caching - dormantChunkCache.put(world, CacheBuilder.newBuilder().maximumSize(dormantChunkCacheSize).build()); + dormantChunkCache.put(world, CacheBuilder.newBuilder().maximumSize(ForgeConfig.CHUNK.dormantChunkCacheSize()).build()); } WorldServer worldServer = (WorldServer) world; File chunkDir = worldServer.getChunkSaveLocation(); @@ -575,7 +552,7 @@ public class ForgeChunkManager { continue; } - int maxTicketLength = getMaxTicketLengthFor(modId); + int maxTicketLength = ForgeConfig.CHUNK.maxTickets(modId); List tickets = loadedTickets.get(modId); if (loadingCallback instanceof OrderedLoadingCallback) { @@ -621,7 +598,7 @@ public class ForgeChunkManager } forcedChunks.remove(world); - if (dormantChunkCacheSize != 0) // only if in use + if (ForgeConfig.CHUNK.dormantChunkCacheSize() != 0) // only if in use { dormantChunkCache.remove(world); } @@ -664,7 +641,7 @@ public class ForgeChunkManager if (container!=null) { String modId = container.getModId(); - int allowedCount = getMaxTicketLengthFor(modId); + int allowedCount = ForgeConfig.CHUNK.maxTickets(modId); return allowedCount - tickets.get(world).get(modId).size(); } else @@ -679,21 +656,9 @@ public class ForgeChunkManager return container; } - public static int getMaxTicketLengthFor(String modId) - { - int allowedCount = ticketConstraints.containsKey(modId) && overridesEnabled ? ticketConstraints.get(modId) : defaultMaxCount; - return allowedCount; - } - - public static int getMaxChunkDepthFor(String modId) - { - int allowedCount = chunkConstraints.containsKey(modId) && overridesEnabled ? chunkConstraints.get(modId) : defaultMaxChunks; - return allowedCount; - } - public static int ticketCountAvailableFor(String username) { - return playerTicketLength - playerTickets.get(username).size(); + return ForgeConfig.CHUNK.playerTicketCount() - playerTickets.get(username).size(); } @Nullable @@ -705,7 +670,7 @@ public class ForgeChunkManager LOGGER.error(CHUNK_MANAGER, "Failed to locate the container for mod instance {} ({} : {})", mod, mod.getClass().getName(), Integer.toHexString(System.identityHashCode(mod))); return null; } - if (playerTickets.get(player).size()>playerTicketLength) + if (playerTickets.get(player).size() > ForgeConfig.CHUNK.playerTicketCount()) { LOGGER.warn(CHUNK_MANAGER, "Unable to assign further chunkloading tickets to player {} (on behalf of mod {})", player, mc.getModId()); return null; @@ -739,7 +704,7 @@ public class ForgeChunkManager throw new RuntimeException("Invalid ticket request"); } - int allowedCount = getMaxTicketLengthFor(modId); + int allowedCount = ForgeConfig.CHUNK.maxTickets(modId); if (tickets.get(world).get(modId).size() >= allowedCount) { @@ -861,27 +826,6 @@ public class ForgeChunkManager forcedChunks.put(ticket.world,newMap); } - static void loadConfiguration() - { - ticketConstraints.clear(); - chunkConstraints.clear(); - for (String mod : config.getCategoryNames()) - { - if (mod.equals(ForgeVersion.MOD_ID) || mod.equals("defaults")) - { - continue; - } - Property modTC = config.get(mod, "maximumTicketCount", 200); - Property modCPT = config.get(mod, "maximumChunksPerTicket", 25); - ticketConstraints.put(mod, modTC.getInt(200)); - chunkConstraints.put(mod, modCPT.getInt(25)); - } - if (config.hasChanged()) - { - config.save(); - } - } - /** * The list of persistent chunks in the world. This set is immutable. * @param world @@ -975,7 +919,7 @@ public class ForgeChunkManager public static void putDormantChunk(long coords, Chunk chunk) { - if (dormantChunkCacheSize == 0) return; // Skip if we're not dormant caching chunks + if (ForgeConfig.CHUNK.dormantChunkCacheSize() == 0) return; // Skip if we're not dormant caching chunks Cache cache = dormantChunkCache.get(chunk.getWorld()); if (cache != null) { @@ -985,7 +929,7 @@ public class ForgeChunkManager public static void storeChunkNBT(World world, IChunk ichunk, NBTTagCompound nbt) { - if (dormantChunkCacheSize == 0) return; + if (ForgeConfig.CHUNK.dormantChunkCacheSize() == 0) return; Cache cache = dormantChunkCache.get(world); if (cache == null) return; @@ -1012,7 +956,7 @@ public class ForgeChunkManager @Nullable public static Chunk fetchDormantChunk(long coords, World world) { - if (dormantChunkCacheSize == 0) return null; // Don't bother with maps at all if its never gonna get a response + if (ForgeConfig.CHUNK.dormantChunkCacheSize() == 0) return null; // Don't bother with maps at all if its never gonna get a response Cache cache = dormantChunkCache.get(world); if (cache == null) return null; @@ -1042,160 +986,4 @@ public class ForgeChunkManager if (tileEntity != null) chunk.addTileEntity(tileEntity); } } - - static void captureConfig(File configDir) - { - cfgFile = new File(configDir,"forgeChunkLoading.cfg"); - config = new Configuration(cfgFile, true); - try - { - config.load(); - } - catch (Exception e) - { - File dest = new File(cfgFile.getParentFile(),"forgeChunkLoading.cfg.bak"); - if (dest.exists()) - { - dest.delete(); - } - cfgFile.renameTo(dest); - LOGGER.error(CHUNK_MANAGER, "A critical error occurred reading the forgeChunkLoading.cfg file, defaults will be used - the invalid file is backed up at forgeChunkLoading.cfg.bak", e); - } - syncConfigDefaults(); - } - - /** - * Synchronizes the local fields with the values in the Configuration object. - */ - public static void syncConfigDefaults() - { - // By adding a property order list we are defining the order that the properties will appear both in the config file and on the GUIs. - // Property order lists are defined per-ConfigCategory. - List propOrder = new ArrayList(); - - config.setCategoryComment("defaults", "Default configuration for forge chunk loading control") - .setCategoryRequiresWorldRestart("defaults", true); - - Property temp = config.get("defaults", "enabled", true); - temp.setComment("Are mod overrides enabled?"); - temp.setLanguageKey("forge.configgui.enableModOverrides"); - overridesEnabled = temp.getBoolean(true); - propOrder.add("enabled"); - - temp = config.get("defaults", "maximumChunksPerTicket", 25); - temp.setComment("The default maximum number of chunks a mod can force, per ticket, \n" + - "for a mod without an override. This is the maximum number of chunks a single ticket can force."); - temp.setLanguageKey("forge.configgui.maximumChunksPerTicket"); - temp.setMinValue(0); - defaultMaxChunks = temp.getInt(25); - propOrder.add("maximumChunksPerTicket"); - - temp = config.get("defaults", "maximumTicketCount", 200); - temp.setComment("The default maximum ticket count for a mod which does not have an override\n" + - "in this file. This is the number of chunk loading requests a mod is allowed to make."); - temp.setLanguageKey("forge.configgui.maximumTicketCount"); - temp.setMinValue(0); - defaultMaxCount = temp.getInt(200); - propOrder.add("maximumTicketCount"); - - temp = config.get("defaults", "playerTicketCount", 500); - temp.setComment("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."); - temp.setLanguageKey("forge.configgui.playerTicketCount"); - temp.setMinValue(0); - playerTicketLength = temp.getInt(500); - propOrder.add("playerTicketCount"); - - temp = config.get("defaults", "dormantChunkCacheSize", 0); - temp.setComment("Unloaded chunks can first be kept in a dormant cache for quicker\n" + - "loading times. Specify the size (in chunks) of that cache here"); - temp.setLanguageKey("forge.configgui.dormantChunkCacheSize"); - temp.setMinValue(0); - dormantChunkCacheSize = temp.getInt(0); - propOrder.add("dormantChunkCacheSize"); - LOGGER.info(CHUNK_MANAGER, "Configured a dormant chunk cache size of {}", temp.getInt(0)); - - temp = config.get("defaults", "asyncChunkLoading", true); - temp.setComment("Load chunks asynchronously for players, reducing load on the server thread.\n" + - "Can be disabled to help troubleshoot chunk loading issues."); - temp.setLanguageKey("forge.configgui.asyncChunkLoading"); - asyncChunkLoading = temp.getBoolean(true); - propOrder.add("asyncChunkLoading"); - - config.setCategoryPropertyOrder("defaults", propOrder); - - config.addCustomCategoryComment(ForgeVersion.MOD_ID, "Sample mod specific control section.\n" + - "Copy this section and rename the with the modid for the mod you wish to override.\n" + - "A value of zero in either entry effectively disables any chunkloading capabilities\n" + - "for that mod"); - - temp = config.get(ForgeVersion.MOD_ID, "maximumTicketCount", 200); - temp.setComment("Maximum ticket count for the mod. Zero disables chunkloading capabilities."); - temp = config.get(ForgeVersion.MOD_ID, "maximumChunksPerTicket", 25); - temp.setComment("Maximum chunks per ticket for the mod."); - for (String mod : config.getCategoryNames()) - { - if (mod.equals(ForgeVersion.MOD_ID) || mod.equals("defaults")) - { - continue; - } - config.get(mod, "maximumTicketCount", 200).setLanguageKey("forge.configgui.maximumTicketCount").setMinValue(0); - config.get(mod, "maximumChunksPerTicket", 25).setLanguageKey("forge.configgui.maximumChunksPerTicket").setMinValue(0); - } - - if (config.hasChanged()) - { - config.save(); - } - } - - public static Configuration getConfig() - { - return config; - } - - public static ConfigCategory getDefaultsCategory() - { - return config.getCategory("defaults"); - } - - public static List getModCategories() - { - List list = new ArrayList(); - for (String mod : config.getCategoryNames()) - { - if (mod.equals(ForgeVersion.MOD_ID) || mod.equals("defaults")) - { - continue; - } - list.add(config.getCategory(mod)); - } - return list; - } - - @Nullable - public static ConfigCategory getConfigFor(Object mod) - { - ModContainer container = getContainer(mod); - if (container != null) - { - return config.getCategory(container.getModId()); - } - - return null; - } - - public static void addConfigProperty(Object mod, String propertyName, String value, Property.Type type) - { - ModContainer container = getContainer(mod); - if (container != null) - { - ConfigCategory cat = config.getCategory(container.getModId()); - Property prop = new Property(propertyName, value, type).setLanguageKey("forge.configgui." + propertyName); - if (type == Property.Type.INTEGER) - { - prop.setMinValue(0); - } - cat.put(propertyName, prop); - } - } } diff --git a/src/main/java/net/minecraftforge/common/ForgeConfig.java b/src/main/java/net/minecraftforge/common/ForgeConfig.java index 9f5e52e86..5b18a9e99 100644 --- a/src/main/java/net/minecraftforge/common/ForgeConfig.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfig.java @@ -23,13 +23,23 @@ import static net.minecraftforge.fml.Logging.CORE; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.electronwill.nightconfig.core.io.WritingMode; -import net.minecraftforge.common.config.ForgeConfigSpec; +import net.minecraftforge.versions.forge.ForgeVersion; public class ForgeConfig { @@ -118,9 +128,71 @@ public class ForgeConfig .build(); + private static ForgeConfigSpec chunk_spec = new ForgeConfigSpec.Builder() + .comment("Default configuration for Forge chunk loading control") + .push("defaults") + .comment("Allow mod overrides, false will use default for everything.") + .translation("forge.configgui.enableModOverrides") + .define("enable", true) + + .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 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 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("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("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) + .pop() + + //Not sure how to do unlimited nested config objects, so doing this for now as it works. + .comment("Per Mod settings. If a mod is missing a entry, or value the default will be used.") + .defineList("mods", () -> { + Map ret = new HashMap<>(); + ret.put("modid", ForgeVersion.MOD_ID); + ret.put("maxTickets", 200); + ret.put("chunksPerTicket", 25); + return Arrays.asList(ret); + }, (o) -> { + if (!(o instanceof Map)) return false; + @SuppressWarnings("unchecked") + Map map = (Map)o; + for (Entry e : map.entrySet()) { + if ("modid".equals(e.getKey())) { + if (!(e.getValue() instanceof String)) + return false; + } else if ("maxTickets".equals(e.getKey())) { + if (!(e.getValue() instanceof Integer)) + return false; + } else if ("chunksPerTicket".equals(e.getKey())) { + if (!(e.getValue() instanceof Integer)) + return false; + } else { //Unknown entry + return false; + } + } + return true; + }) + .build(); + private CommentedFileConfig configData; - private void loadFrom(final Path configFile) - { + private CommentedFileConfig chunkData; + private void loadFrom(final Path configRoot) { + Path configFile = configRoot.resolve("forge.toml"); configData = CommentedFileConfig.builder(configFile).sync() .autosave() //.autoreload() @@ -128,18 +200,32 @@ public class ForgeConfig .build(); configData.load(); if (!spec.isCorrect(configData)) { - LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configFile); + LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configRoot); spec.correct(configData, (action, path, incorrectValue, correctedValue) -> LogManager.getLogger().warn(CORE, "Incorrect key {} was corrected from {} to {}", path, incorrectValue, correctedValue)); configData.save(); } + LogManager.getLogger().debug(CORE, "Loaded Forge config from {}", configFile); + + + configFile = configRoot.resolve("forge_chunks.toml"); + chunkData = CommentedFileConfig.builder(configFile).sync() + .autosave() + //.autoreload() + .writingMode(WritingMode.REPLACE) + .build(); + chunkData.load(); + if (!chunk_spec.isCorrect(chunkData)) { + LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configRoot); + chunk_spec.correct(chunkData, (action, path, incorrectValue, correctedValue) -> + LogManager.getLogger().warn(CORE, "Incorrect key {} was corrected from {} to {}", path, incorrectValue, correctedValue)); + chunkData.save(); + } + LogManager.getLogger().debug(CORE, "Loaded Forge Chunk config from {}", configFile); } - public static void load() - { - Path configFile = Paths.get("config").resolve("forge.toml"); - INSTANCE.loadFrom(configFile); - LogManager.getLogger().debug(CORE, "Loaded FML config from {}", configFile); + public static void load() { + INSTANCE.loadFrom(Paths.get("config")); } //TODO: Make this less duplciate? Maybe static CfgEntry zombieBaseSummonChance = create((spec, name) -> spec.comment().translation().define(name), "zombieBaseSummonChance") @@ -173,6 +259,40 @@ public class ForgeConfig } } + public static class CHUNK { + public static boolean enableModOverrides() { + return ForgeConfig.INSTANCE.chunkData.getOrElse("defaults.enable", true); + } + public static int playerTicketCount() { + return ForgeConfig.INSTANCE.chunkData.getOrElse("defaults.playerTicketCount", 500); + } + public static int dormantChunkCacheSize() { + return ForgeConfig.INSTANCE.chunkData.getOrElse("defaults.dormantChunkCacheSize", 0); + } + private static int maxTickets() { + return ForgeConfig.INSTANCE.chunkData.getOrElse("defaults.maxTickets", 200); + } + public static int chunksPerTicket() { + return ForgeConfig.INSTANCE.chunkData.getOrElse("defaults.chunksPerTicket", 0); + } + public static int maxTickets(@Nullable String modid) { + if (!enableModOverrides() || modid == null) + return maxTickets(); + Map data = ForgeConfig.INSTANCE.chunkData.>>getOrElse("mods", Collections.emptyList()) + .stream().filter(e -> modid.equals(e.get("modid"))).findFirst().orElse(null); + Integer ret = data == null ? null : (Integer)data.get("maxTickets"); + return ret == null ? maxTickets() : ret; + } + public static int chunksPerTicket(@Nullable String modid) { + if (!enableModOverrides() || modid == null) + return chunksPerTicket(); + Map data = ForgeConfig.INSTANCE.chunkData.>>getOrElse("mods", Collections.emptyList()) + .stream().filter(e -> modid.equals(e.get("modid"))).findFirst().orElse(null); + Integer ret = data == null ? null : (Integer)data.get("chunksPerTicket"); + return ret == null ? chunksPerTicket() : ret; + } + } + //General //public static boolean disableVersionCheck = false; //public static boolean logCascadingWorldGeneration = true; // see Chunk#logCascadingWorldGeneration() diff --git a/src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java b/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java similarity index 92% rename from src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java rename to src/main/java/net/minecraftforge/common/ForgeConfigSpec.java index b03c14e71..d186d594e 100644 --- a/src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java +++ b/src/main/java/net/minecraftforge/common/ForgeConfigSpec.java @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -package net.minecraftforge.common.config; +package net.minecraftforge.common; import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.ADD; import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.REMOVE; @@ -33,20 +33,17 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Predicate; +import java.util.function.Supplier; import com.electronwill.nightconfig.core.CommentedConfig; import com.electronwill.nightconfig.core.Config; -import com.electronwill.nightconfig.core.ConfigFormat; import com.electronwill.nightconfig.core.InMemoryFormat; -import com.electronwill.nightconfig.core.UnmodifiableConfig; import com.electronwill.nightconfig.core.utils.UnmodifiableConfigWrapper; import com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction; import com.electronwill.nightconfig.core.ConfigSpec.CorrectionListener; import com.google.common.base.Joiner; import com.google.common.base.Splitter; -import com.google.common.base.Supplier; import com.google.common.collect.Lists; /* @@ -219,8 +216,7 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper public > Builder defineInRange(String path, Supplier defaultSupplier, V min, V max, Class clazz) { return defineInRange(split(path), defaultSupplier, min, max, clazz); } - public > Builder defineInRange(List path, Supplier defaultSupplier, V min, V max, Class clazz) - { + public > Builder defineInRange(List path, Supplier defaultSupplier, V min, V max, Class clazz) { Range range = new Range<>(clazz, min, max); context.setRange(range); if (min.compareTo(max) > 0) @@ -228,17 +224,32 @@ public class ForgeConfigSpec extends UnmodifiableConfigWrapper define(path, defaultSupplier, range); return this; } - public void defineInList(String path, Object defaultValue, Collection acceptableValues) { - defineInList(split(path), defaultValue, acceptableValues); + public Builder defineInList(String path, Object defaultValue, Collection acceptableValues) { + return defineInList(split(path), defaultValue, acceptableValues); } - public void defineInList(String path, Supplier defaultSupplier, Collection acceptableValues) { - defineInList(split(path), defaultSupplier, acceptableValues); + public Builder defineInList(String path, Supplier defaultSupplier, Collection acceptableValues) { + return defineInList(split(path), defaultSupplier, acceptableValues); } - public void defineInList(List path, Object defaultValue, Collection acceptableValues) { - defineInList(path, () -> defaultValue, acceptableValues); + public Builder defineInList(List path, Object defaultValue, Collection acceptableValues) { + return defineInList(path, () -> defaultValue, acceptableValues); } - public void defineInList(List path, Supplier defaultSupplier, Collection acceptableValues) { - define(path, defaultSupplier, acceptableValues::contains); + public Builder defineInList(List path, Supplier defaultSupplier, Collection acceptableValues) { + return define(path, defaultSupplier, acceptableValues::contains); + } + public Builder defineList(String path, List defaultValue, Predicate elementValidator) { + return defineList(split(path), defaultValue, elementValidator); + } + public Builder defineList(String path, Supplier> defaultSupplier, Predicate elementValidator) { + return defineList(split(path), defaultSupplier, elementValidator); + } + public Builder defineList(List path, List defaultValue, Predicate elementValidator) { + return defineList(path, () -> defaultValue, elementValidator); + } + public Builder defineList(List path, Supplier> defaultSupplier, Predicate elementValidator) { + return define(path, defaultSupplier, (Object o) -> { + if (!(o instanceof List)) return false; + return ((List)o).stream().allMatch(elementValidator); + }); } //Enum diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 4c51c0203..57b615fb7 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -114,7 +114,6 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook CapabilityAnimation.register(); CapabilityEnergy.register(); MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER); -// ForgeChunkManager.captureConfig(evt.getModConfigurationDirectory()); MinecraftForge.EVENT_BUS.register(this); if (!ForgeMod.disableVersionCheck) diff --git a/src/main/java/net/minecraftforge/common/config/Config.java b/src/main/java/net/minecraftforge/common/config/Config.java deleted file mode 100644 index c52ef3c5e..000000000 --- a/src/main/java/net/minecraftforge/common/config/Config.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.common.config; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Config -{ - /** - * The mod id that this configuration is associated with. - */ - String modid(); - /** - * A user friendly name for the config file, - * the default will be modid - */ - String name() default ""; - - /** - * The type this is, right now the only value is INSTANCE. - * This is intended to be expanded upon later for more Forge controlled - * configs. - */ - Type type() default Type.INSTANCE; - - /** - * Root element category, defaults to "general", if this is an empty string then the root category is disabled. - * Any primitive fields will cause an error, and you must specify sub-category objects - */ - String category() default "general"; - - public static enum Type - { - /** - * Loaded once, directly after mod construction. Before pre-init. - * This class must have static fields. - */ - INSTANCE(true); - - - private boolean isStatic = true; - private Type(boolean isStatic) { this.isStatic = isStatic; } - public boolean isStatic(){ return this.isStatic; } - } - - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.FIELD, ElementType.TYPE}) - @interface LangKey - { - String value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - @interface Comment - { - String[] value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - @interface Ignore - {} - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - @interface RangeInt - { - int min() default Integer.MIN_VALUE; - int max() default Integer.MAX_VALUE; - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - @interface RangeDouble - { - double min() default Double.MIN_VALUE; - double max() default Double.MAX_VALUE; - } - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - @interface Name - { - String value(); - } - - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.FIELD, ElementType.TYPE}) - @interface RequiresMcRestart - {} - - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.FIELD, ElementType.TYPE}) - @interface RequiresWorldRestart - {} -} diff --git a/src/main/java/net/minecraftforge/common/config/ConfigCategory.java b/src/main/java/net/minecraftforge/common/config/ConfigCategory.java deleted file mode 100644 index f90ef4467..000000000 --- a/src/main/java/net/minecraftforge/common/config/ConfigCategory.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.common.config; - -import static net.minecraftforge.common.config.Configuration.COMMENT_SEPARATOR; -import static net.minecraftforge.common.config.Configuration.NEW_LINE; -import static net.minecraftforge.common.config.Configuration.allowedProperties; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; - -import net.minecraftforge.fml.client.config.IConfigEntry; - -public class ConfigCategory implements Map -{ - private String name; - private String comment; - private String languagekey; - private ArrayList children = new ArrayList(); - private Map properties = new TreeMap(); - @SuppressWarnings("unused") - private int propNumber = 0; - public final ConfigCategory parent; - private boolean changed = false; - private boolean requiresWorldRestart = false; - private boolean showInGui = true; - private boolean requiresMcRestart = false; - private Class customEntryClass = null; - private List propertyOrder = null; - - public ConfigCategory(String name) - { - this(name, null); - } - - public ConfigCategory(String name, ConfigCategory parent) - { - this.name = name; - this.parent = parent; - if (parent != null) - { - parent.children.add(this); - } - } - - @Override - public boolean equals(Object obj) - { - if (obj instanceof ConfigCategory) - { - ConfigCategory cat = (ConfigCategory)obj; - return name.equals(cat.name) && children.equals(cat.children); - } - - return false; - } - - public String getName() - { - return name; - } - - public String getQualifiedName() - { - return getQualifiedName(name, parent); - } - - public static String getQualifiedName(String name, ConfigCategory parent) - { - return (parent == null ? name : parent.getQualifiedName() + Configuration.CATEGORY_SPLITTER + name); - } - - public ConfigCategory getFirstParent() - { - return (parent == null ? this : parent.getFirstParent()); - } - - public boolean isChild() - { - return parent != null; - } - - public Map getValues() - { - return ImmutableMap.copyOf(properties); - } - - public List getOrderedValues() - { - if (this.propertyOrder != null) - { - ArrayList set = new ArrayList(); - for (String key : this.propertyOrder) - if (properties.containsKey(key)) - set.add(properties.get(key)); - - return ImmutableList.copyOf(set); - } - else - return ImmutableList.copyOf(properties.values()); - } - - public ConfigCategory setConfigEntryClass(Class clazz) - { - this.customEntryClass = clazz; - return this; - } - - public Class getConfigEntryClass() - { - return this.customEntryClass; - } - - public ConfigCategory setLanguageKey(String languagekey) - { - this.languagekey = languagekey; - return this; - } - - public String getLanguagekey() - { - if (this.languagekey != null) - return this.languagekey; - else - return getQualifiedName(); - } - - public void setComment(String comment) - { - this.comment = comment; - } - - public String getComment() - { - return this.comment; - } - - /** - * Sets the flag for whether or not this category can be edited while a world is running. Care should be taken to ensure - * that only properties that are truly dynamic can be changed from the in-game options menu. Only set this flag to - * true if all child properties/categories are unable to be modified while a world is running. - */ - public ConfigCategory setRequiresWorldRestart(boolean requiresWorldRestart) - { - this.requiresWorldRestart = requiresWorldRestart; - return this; - } - - /** - * Returns whether or not this category is able to be edited while a world is running using the in-game Mod Options screen - * as well as the Mods list screen, or only from the Mods list screen. - */ - public boolean requiresWorldRestart() - { - return this.requiresWorldRestart; - } - - /** - * Sets whether or not this ConfigCategory should be allowed to show on config GUIs. - * Defaults to true. - */ - public ConfigCategory setShowInGui(boolean showInGui) - { - this.showInGui = showInGui; - return this; - } - - /** - * Gets whether or not this ConfigCategory should be allowed to show on config GUIs. - * Defaults to true unless set to false. - */ - public boolean showInGui() - { - return showInGui; - } - - /** - * Sets whether or not this ConfigCategory requires Minecraft to be restarted when changed. - * Defaults to false. Only set this flag to true if ALL child properties/categories require - * Minecraft to be restarted when changed. Setting this flag will also prevent modification - * of the child properties/categories while a world is running. - */ - public ConfigCategory setRequiresMcRestart(boolean requiresMcRestart) - { - this.requiresMcRestart = this.requiresWorldRestart = requiresMcRestart; - return this; - } - - /** - * Gets whether or not this ConfigCategory requires Minecraft to be restarted when changed. - * Defaults to false unless set to true. - */ - public boolean requiresMcRestart() - { - return this.requiresMcRestart; - } - - public ConfigCategory setPropertyOrder(List propertyOrder) - { - this.propertyOrder = propertyOrder; - for (String s : properties.keySet()) - if (!propertyOrder.contains(s)) - propertyOrder.add(s); - return this; - } - - public List getPropertyOrder() - { - if (this.propertyOrder != null) - return ImmutableList.copyOf(this.propertyOrder); - else - return ImmutableList.copyOf(properties.keySet()); - } - - public boolean containsKey(String key) - { - return properties.containsKey(key); - } - - public Property get(String key) - { - return properties.get(key); - } - - private void write(BufferedWriter out, String... data) throws IOException - { - write(out, true, data); - } - - private void write(BufferedWriter out, boolean new_line, String... data) throws IOException - { - for (int x = 0; x < data.length; x++) - { - out.write(data[x]); - } - if (new_line) out.write(NEW_LINE); - } - - public void write(BufferedWriter out, int indent) throws IOException - { - String pad0 = getIndent(indent); - String pad1 = getIndent(indent + 1); - String pad2 = getIndent(indent + 2); - - if (comment != null && !comment.isEmpty()) - { - write(out, pad0, COMMENT_SEPARATOR); - write(out, pad0, "# ", name); - write(out, pad0, "#--------------------------------------------------------------------------------------------------------#"); - Splitter splitter = Splitter.onPattern("\r?\n"); - - for (String line : splitter.split(comment)) - { - write(out, pad0, "# ", line); - } - - write(out, pad0, COMMENT_SEPARATOR, NEW_LINE); - } - - String displayName = name; - - if (!allowedProperties.matchesAllOf(name)) - { - displayName = '"' + name + '"'; - } - - write(out, pad0, displayName, " {"); - - Property[] props = getOrderedValues().toArray(new Property[] {}); - - for (int x = 0; x < props.length; x++) - { - Property prop = props[x]; - - if (prop.getComment() != null && !prop.getComment().isEmpty()) - { - if (x != 0) - { - out.newLine(); - } - - Splitter splitter = Splitter.onPattern("\r?\n"); - for (String commentLine : splitter.split(prop.getComment())) - { - write(out, pad1, "# ", commentLine); - } - } - - String propName = prop.getName(); - - if (!allowedProperties.matchesAllOf(propName)) - { - propName = '"' + propName + '"'; - } - - if (prop.isList()) - { - char type = prop.getType().getID(); - - write(out, pad1, String.valueOf(type), ":", propName, " <"); - - for (String line : prop.getStringList()) - { - write(out, pad2, line); - } - - write(out, pad1, " >"); - } - else if (prop.getType() == null) - { - write(out, pad1, propName, "=", prop.getString()); - } - else - { - char type = prop.getType().getID(); - write(out, pad1, String.valueOf(type), ":", propName, "=", prop.getString()); - } - - prop.resetChangedState(); - } - - if (children.size() > 0) - out.newLine(); - - for (ConfigCategory child : children) - { - child.write(out, indent + 1); - } - - write(out, pad0, "}", NEW_LINE); - } - - private String getIndent(int indent) - { - StringBuilder buf = new StringBuilder(""); - for (int x = 0; x < indent; x++) - { - buf.append(" "); - } - return buf.toString(); - } - - public boolean hasChanged() - { - if (changed) return true; - for (Property prop : properties.values()) - { - if (prop.hasChanged()) return true; - } - return false; - } - - void resetChangedState() - { - changed = false; - for (Property prop : properties.values()) - { - prop.resetChangedState(); - } - } - - - //Map bouncer functions for compatibility with older mods, to be removed once all mods stop using it. - @Override public int size(){ return properties.size(); } - @Override public boolean isEmpty() { return properties.isEmpty(); } - @Override public boolean containsKey(Object key) { return properties.containsKey(key); } - @Override public boolean containsValue(Object value){ return properties.containsValue(value); } - @Override public Property get(Object key) { return properties.get(key); } - @Override public Property put(String key, Property value) - { - changed = true; - if (this.propertyOrder != null && !this.propertyOrder.contains(key)) - this.propertyOrder.add(key); - return properties.put(key, value); - } - @Override public Property remove(Object key) - { - changed = true; - return properties.remove(key); - } - @Override public void putAll(Map m) - { - changed = true; - if (this.propertyOrder != null) - for (String key : m.keySet()) - if (!this.propertyOrder.contains(key)) - this.propertyOrder.add(key); - properties.putAll(m); - } - @Override public void clear() - { - changed = true; - properties.clear(); - } - @Override public Set keySet() { return properties.keySet(); } - @Override public Collection values() { return properties.values(); } - - @Override //Immutable copy, changes will NOT be reflected in this category - public Set> entrySet() - { - return ImmutableSet.copyOf(properties.entrySet()); - } - - public Set getChildren(){ return ImmutableSet.copyOf(children); } - - public void removeChild(ConfigCategory child) - { - if (children.contains(child)) - { - children.remove(child); - changed = true; - } - } -} diff --git a/src/main/java/net/minecraftforge/common/config/ConfigElement.java b/src/main/java/net/minecraftforge/common/config/ConfigElement.java deleted file mode 100644 index 511f93ed9..000000000 --- a/src/main/java/net/minecraftforge/common/config/ConfigElement.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.common.config; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -import com.google.common.base.Strings; -import com.google.common.collect.Lists; - -import net.minecraftforge.fml.client.config.ConfigGuiType; -import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement; -import net.minecraftforge.fml.client.config.IConfigEntry; -import net.minecraftforge.fml.client.config.IArrayEntry; -import net.minecraftforge.fml.client.config.IConfigElement; - -/** - * This class bridges the gap between the FML config GUI classes and the Forge Configuration classes. - */ -public class ConfigElement implements IConfigElement -{ - private Property prop; - private Property.Type type; - private boolean isProperty; - private ConfigCategory category; - private boolean categoriesFirst = true; - - public ConfigElement(ConfigCategory category) - { - this.category = category; - isProperty = false; - } - - public ConfigElement(Property prop) - { - this.prop = prop; - this.type = prop.getType(); - this.isProperty = true; - } - - public ConfigElement listCategoriesFirst(boolean categoriesFirst) - { - this.categoriesFirst = categoriesFirst; - return this; - } - - @Override - public List getChildElements() - { - if (!isProperty) - { - List elements = new ArrayList(); - Iterator ccI = category.getChildren().iterator(); - Iterator pI = category.getOrderedValues().iterator(); - @SuppressWarnings("unused") - int index = 0; - - if (categoriesFirst) - while (ccI.hasNext()) - { - ConfigElement temp = new ConfigElement(ccI.next()); - if (temp.showInGui()) // don't bother adding elements that shouldn't show - elements.add(temp); - } - - while (pI.hasNext()) - { - ConfigElement temp = new ConfigElement(pI.next()); - if (temp.showInGui()) - elements.add(temp); - } - - if (!categoriesFirst) - while (ccI.hasNext()) - { - ConfigElement temp = new ConfigElement(ccI.next()); - if (temp.showInGui()) - elements.add(temp); - } - - return elements; - } - return null; - } - - @Override - public String getName() - { - return isProperty ? prop.getName() : category.getName(); - } - - @Override - public boolean isProperty() - { - return isProperty; - } - - @Override - public Class getConfigEntryClass() - { - return isProperty ? prop.getConfigEntryClass() : category.getConfigEntryClass(); - } - - @Override - public Class getArrayEntryClass() - { - return isProperty ? prop.getArrayEntryClass() : null; - } - - @Override - public String getQualifiedName() - { - return isProperty ? prop.getName() : category.getQualifiedName(); - } - - @Override - public ConfigGuiType getType() - { - return isProperty ? getType(this.prop) : ConfigGuiType.CONFIG_CATEGORY; - } - - public static ConfigGuiType getType(Property prop) - { - return prop.getType() == Property.Type.BOOLEAN ? ConfigGuiType.BOOLEAN : prop.getType() == Property.Type.DOUBLE ? ConfigGuiType.DOUBLE : - prop.getType() == Property.Type.INTEGER ? ConfigGuiType.INTEGER : prop.getType() == Property.Type.COLOR ? ConfigGuiType.COLOR : - prop.getType() == Property.Type.MOD_ID ? ConfigGuiType.MOD_ID : ConfigGuiType.STRING; - } - - @Override - public boolean isList() - { - return isProperty && prop.isList(); - } - - @Override - public boolean isListLengthFixed() - { - return isProperty && prop.isListLengthFixed(); - } - - @Override - public int getMaxListLength() - { - return isProperty ? prop.getMaxListLength() : -1; - } - - @Override - public String getComment() - { - return isProperty ? prop.getComment() : category.getComment(); - } - - @Override - public boolean isDefault() - { - return !isProperty || prop.isDefault(); - } - - @Override - public void setToDefault() - { - if (isProperty) - prop.setToDefault(); - } - - @Override - public boolean requiresWorldRestart() - { - return isProperty ? prop.requiresWorldRestart() : category.requiresWorldRestart(); - } - - @Override - public boolean showInGui() - { - return isProperty ? prop.showInGui() : category.showInGui(); - } - - @Override - public boolean requiresMcRestart() - { - return isProperty ? prop.requiresMcRestart() : category.requiresMcRestart(); - } - - @Override - public String[] getValidValues() - { - return isProperty ? prop.getValidValues() : null; - } - - @Override - public String getLanguageKey() - { - return isProperty ? prop.getLanguageKey() : category.getLanguagekey(); - } - - @Override - public Object getDefault() - { - return isProperty ? prop.getDefault() : null; - } - - @Override - public Object[] getDefaults() - { - if (isProperty) - { - String[] aVal = prop.getDefaults(); - if (type == Property.Type.BOOLEAN) - { - Boolean[] ba = new Boolean[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ba[i] = Boolean.valueOf(aVal[i]); - return ba; - } - else if (type == Property.Type.DOUBLE) - { - Double[] da = new Double[aVal.length]; - for(int i = 0; i < aVal.length; i++) - da[i] = Double.valueOf(aVal[i].toString()); - return da; - } - else if (type == Property.Type.INTEGER) - { - Integer[] ia = new Integer[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ia[i] = Integer.valueOf(aVal[i].toString()); - return ia; - } - else - return aVal; - } - return null; - } - - @Override - public Pattern getValidationPattern() - { - return isProperty ? prop.getValidationPattern() : null; - } - - @Override - public Object get() - { - return isProperty ? prop.getString() : null; - } - - @Override - public Object[] getList() - { - if (isProperty) - { - String[] aVal = prop.getStringList(); - if (type == Property.Type.BOOLEAN) - { - Boolean[] ba = new Boolean[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ba[i] = Boolean.valueOf(aVal[i]); - return ba; - } - else if (type == Property.Type.DOUBLE) - { - Double[] da = new Double[aVal.length]; - for(int i = 0; i < aVal.length; i++) - da[i] = Double.valueOf(aVal[i].toString()); - return da; - } - else if (type == Property.Type.INTEGER) - { - Integer[] ia = new Integer[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ia[i] = Integer.valueOf(aVal[i].toString()); - return ia; - } - else - return aVal; - } - return null; - } - - @Override - public void set(Object value) - { - if (isProperty) - { - if (type == Property.Type.BOOLEAN) - prop.set(Boolean.parseBoolean(value.toString())); - else if (type == Property.Type.DOUBLE) - prop.set(Double.parseDouble(value.toString())); - else if (type == Property.Type.INTEGER) - prop.set(Integer.parseInt(value.toString())); - else - prop.set(value.toString()); - } - } - - @Override - public void set(Object[] aVal) - { - if (isProperty) - { - if (type == Property.Type.BOOLEAN) - { - boolean[] ba = new boolean[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ba[i] = Boolean.valueOf(aVal[i].toString()); - prop.set(ba); - } - else if (type == Property.Type.DOUBLE) - { - double[] da = new double[aVal.length]; - for(int i = 0; i < aVal.length; i++) - da[i] = Double.valueOf(aVal[i].toString()); - prop.set(da); - } - else if (type == Property.Type.INTEGER) - { - int[] ia = new int[aVal.length]; - for(int i = 0; i < aVal.length; i++) - ia[i] = Integer.valueOf(aVal[i].toString()); - prop.set(ia); - } - else - { - String[] is = new String[aVal.length]; - for(int i = 0; i < aVal.length; i++) - is[i] = aVal[i].toString(); - prop.set(is); - } - } - } - - @Override - public Object getMinValue() - { - return isProperty ? prop.getMinValue() : null; - } - - @Override - public Object getMaxValue() - { - return isProperty ? prop.getMaxValue() : null; - } -} diff --git a/src/main/java/net/minecraftforge/common/config/Configuration.java b/src/main/java/net/minecraftforge/common/config/Configuration.java deleted file mode 100644 index 3ea4e0c77..000000000 --- a/src/main/java/net/minecraftforge/common/config/Configuration.java +++ /dev/null @@ -1,1727 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.common.config; - -import static net.minecraftforge.common.config.Property.Type.BOOLEAN; -import static net.minecraftforge.common.config.Property.Type.DOUBLE; -import static net.minecraftforge.common.config.Property.Type.INTEGER; -import static net.minecraftforge.common.config.Property.Type.STRING; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PushbackInputStream; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.google.common.base.CharMatcher; -import com.google.common.collect.ImmutableSet; - -import com.google.common.primitives.Floats; -import net.minecraftforge.fml.loading.FMLPaths; -import org.apache.commons.io.IOUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -/** - * This class offers advanced configurations capabilities, allowing to provide - * various categories for configuration variables. - */ -public class Configuration -{ - private static final Logger LOGGER = LogManager.getLogger(); - - public static final String CATEGORY_GENERAL = "general"; - public static final String CATEGORY_CLIENT = "client"; - public static final String ALLOWED_CHARS = "._-"; - public static final String DEFAULT_ENCODING = "UTF-8"; - public static final String CATEGORY_SPLITTER = "."; - public static final String NEW_LINE; - public static final String COMMENT_SEPARATOR = "##########################################################################################################"; - private static final String CONFIG_VERSION_MARKER = "~CONFIG_VERSION"; - private static final Pattern CONFIG_START = Pattern.compile("START: \"([^\\\"]+)\""); - private static final Pattern CONFIG_END = Pattern.compile("END: \"([^\\\"]+)\""); - public static final CharMatcher allowedProperties = CharMatcher.javaLetterOrDigit().or(CharMatcher.anyOf(ALLOWED_CHARS)); - private static Configuration PARENT = null; - - File file; - - private Map categories = new TreeMap(); - private Map children = new TreeMap(); - - private boolean caseSensitiveCustomCategories; - public String defaultEncoding = DEFAULT_ENCODING; - private String fileName = null; - public boolean isChild = false; - private boolean changed = false; - private String definedConfigVersion = null; - private String loadedConfigVersion = null; - - static - { - NEW_LINE = System.getProperty("line.separator"); - } - - public Configuration(){} - - /** - * Create a configuration file for the file given in parameter. - */ - public Configuration(File file) - { - this(file, null); - } - - /** - * Create a configuration file for the file given in parameter with the provided config version number. - * / - private void runConfiguration(File file, String configVersion) - { - this.file = file; - this.definedConfigVersion = configVersion; - String basePath = ((File)(FMLInjectionData.data()[6])).getAbsolutePath().replace(File.separatorChar, '/').replace("/.", ""); - String path = file.getAbsolutePath().replace(File.separatorChar, '/').replace("/./", "/").replace(basePath, ""); - if (PARENT != null) - { - PARENT.setChild(path, this); - isChild = true; - } - else - { - fileName = path; - try - { - load(); - } - catch (Throwable e) - { - File fileBak = new File(file.getAbsolutePath() + "_" + - new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".errored"); - LOGGER.fatal("An exception occurred while loading config file {}. This file will be renamed to {} " + - "and a new config file will be generated.", file.getName(), fileBak.getName(), e); - - file.renameTo(fileBak); - load(); - } - } - } -*/ - public Configuration(File file, String configVersion) - { -// runConfiguration(file, configVersion); - } - - public Configuration(File file, String configVersion, boolean caseSensitiveCustomCategories) - { - this.caseSensitiveCustomCategories = caseSensitiveCustomCategories; -// runConfiguration(file, configVersion); - } - - public Configuration(File file, boolean caseSensitiveCustomCategories) - { - this(file, null, caseSensitiveCustomCategories); - } - - @Override - public String toString() - { - return file.getAbsolutePath(); - } - - public String getDefinedConfigVersion() - { - return this.definedConfigVersion; - } - - public String getLoadedConfigVersion() - { - return this.loadedConfigVersion; - } - - /****************************************************************************************************************** - * - * BOOLEAN gets - * - *****************************************************************************************************************/ - - /** - * Gets a boolean Property object without a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @return a boolean Property object without a comment - */ - public Property get(String category, String key, boolean defaultValue) - { - return get(category, key, defaultValue, null); - } - - /** - * Gets a boolean Property object with a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @return a boolean Property object without a comment - */ - public Property get(String category, String key, boolean defaultValue, String comment) - { - Property prop = get(category, key, Boolean.toString(defaultValue), comment, BOOLEAN); - prop.setDefaultValue(Boolean.toString(defaultValue)); - - if (!prop.isBooleanValue()) - { - prop.setValue(defaultValue); - } - return prop; - - } - - /** - * Gets a boolean array Property without a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @return a boolean array Property without a comment using these defaults: isListLengthFixed = false, maxListLength = -1 - */ - public Property get(String category, String key, boolean[] defaultValues) - { - return get(category, key, defaultValues, null); - } - - /** - * Gets a boolean array Property with a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @return a boolean array Property with a comment using these defaults: isListLengthFixed = false, maxListLength = -1 - */ - public Property get(String category, String key, boolean[] defaultValues, String comment) - { - return get(category, key, defaultValues, comment, false, -1); - } - - /** - * Gets a boolean array Property with all settings defined. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param isListLengthFixed boolean for whether this array is required to be a specific length (defined by the default value array - * length or maxListLength) - * @param maxListLength the maximum length of this array, use -1 for no max length - * @return a boolean array Property with all settings defined - */ - public Property get(String category, String key, boolean[] defaultValues, String comment, - boolean isListLengthFixed, int maxListLength) - { - String[] values = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - { - values[i] = Boolean.toString(defaultValues[i]); - } - - Property prop = get(category, key, values, comment, BOOLEAN); - prop.setDefaultValues(values); - prop.setIsListLengthFixed(isListLengthFixed); - prop.setMaxListLength(maxListLength); - - if (!prop.isBooleanList()) - { - prop.setValues(values); - } - - return prop; - } - - /* **************************************************************************************************************** - * - * INTEGER gets - * - *****************************************************************************************************************/ - - /** - * Gets an integer Property object without a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @return an integer Property object with default bounds of Integer.MIN_VALUE and Integer.MAX_VALUE - */ - public Property get(String category, String key, int defaultValue) - { - return get(category, key, defaultValue, null, Integer.MIN_VALUE, Integer.MAX_VALUE); - } - - /** - * Gets an integer Property object with a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @return an integer Property object with default bounds of Integer.MIN_VALUE and Integer.MAX_VALUE - */ - public Property get(String category, String key, int defaultValue, String comment) - { - return get(category, key, defaultValue, comment, Integer.MIN_VALUE, Integer.MAX_VALUE); - } - - /** - * Gets an integer Property object with the defined comment, minimum and maximum bounds. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @return an integer Property object with the defined comment, minimum and maximum bounds - */ - public Property get(String category, String key, int defaultValue, String comment, int minValue, int maxValue) - { - Property prop = get(category, key, Integer.toString(defaultValue), comment, INTEGER); - prop.setDefaultValue(Integer.toString(defaultValue)); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - - if (!prop.isIntValue()) - { - prop.setValue(defaultValue); - } - return prop; - } - - /** - * Gets an integer array Property object without a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @return an integer array Property object with default bounds of Integer.MIN_VALUE and Integer.MAX_VALUE, isListLengthFixed = false, - * maxListLength = -1 - */ - public Property get(String category, String key, int[] defaultValues) - { - return get(category, key, defaultValues, null); - } - - /** - * Gets an integer array Property object with a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @return an integer array Property object with default bounds of Integer.MIN_VALUE and Integer.MAX_VALUE, isListLengthFixed = false, - * maxListLength = -1 - */ - public Property get(String category, String key, int[] defaultValues, String comment) - { - return get(category, key, defaultValues, comment, Integer.MIN_VALUE, Integer.MAX_VALUE, false, -1); - } - - /** - * Gets an integer array Property object with the defined comment, minimum and maximum bounds. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @return an integer array Property object with the defined comment, minimum and maximum bounds, isListLengthFixed - * = false, maxListLength = -1 - */ - public Property get(String category, String key, int[] defaultValues, String comment, int minValue, int maxValue) - { - return get(category, key, defaultValues, comment, minValue, maxValue, false, -1); - } - - /** - * Gets an integer array Property object with all settings defined. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @param isListLengthFixed boolean for whether this array is required to be a specific length (defined by the default value array - * length or maxListLength) - * @param maxListLength the maximum length of this array, use -1 for no max length - * @return an integer array Property object with all settings defined - */ - public Property get(String category, String key, int[] defaultValues, String comment, int minValue, int maxValue, - boolean isListLengthFixed, int maxListLength) - { - String[] values = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - { - values[i] = Integer.toString(defaultValues[i]); - } - - Property prop = get(category, key, values, comment, INTEGER); - prop.setDefaultValues(values); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - prop.setIsListLengthFixed(isListLengthFixed); - prop.setMaxListLength(maxListLength); - - if (!prop.isIntList()) - { - prop.setValues(values); - } - - return prop; - } - - /* **************************************************************************************************************** - * - * DOUBLE gets - * - *****************************************************************************************************************/ - - /** - * Gets a double Property object without a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @return a double Property object with default bounds of Double.MIN_VALUE and Double.MAX_VALUE - */ - public Property get(String category, String key, double defaultValue) - { - return get(category, key, defaultValue, null); - } - - /** - * Gets a double Property object with a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @return a double Property object with default bounds of Double.MIN_VALUE and Double.MAX_VALUE - */ - public Property get(String category, String key, double defaultValue, String comment) - { - return get(category, key, defaultValue, comment, -Double.MAX_VALUE, Double.MAX_VALUE); - } - - /** - * Gets a double Property object with the defined comment, minimum and maximum bounds - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @return a double Property object with the defined comment, minimum and maximum bounds - */ - public Property get(String category, String key, double defaultValue, String comment, double minValue, double maxValue) - { - Property prop = get(category, key, Double.toString(defaultValue), comment, DOUBLE); - prop.setDefaultValue(Double.toString(defaultValue)); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - - if (!prop.isDoubleValue()) - { - prop.setValue(defaultValue); - } - return prop; - } - - /** - * Gets a double array Property object without a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @return a double array Property object with default bounds of Double.MIN_VALUE and Double.MAX_VALUE, isListLengthFixed = false, - * maxListLength = -1 - */ - public Property get(String category, String key, double[] defaultValues) - { - return get(category, key, defaultValues, null); - } - - /** - * Gets a double array Property object without a comment using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @return a double array Property object with default bounds of Double.MIN_VALUE and Double.MAX_VALUE, isListLengthFixed = false, - * maxListLength = -1 - */ - public Property get(String category, String key, double[] defaultValues, String comment) - { - return get(category, key, defaultValues, comment, -Double.MAX_VALUE, Double.MAX_VALUE, false, -1); - } - - /** - * Gets a double array Property object with the defined comment, minimum and maximum bounds. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @return a double array Property object with the defined comment, minimum and maximum bounds, isListLengthFixed = - * false, maxListLength = -1 - */ - public Property get(String category, String key, double[] defaultValues, String comment, double minValue, double maxValue) - { - return get(category, key, defaultValues, comment, minValue, maxValue, false, -1); - } - - /** - * Gets a double array Property object with all settings defined. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param minValue minimum boundary - * @param maxValue maximum boundary - * @param isListLengthFixed boolean for whether this array is required to be a specific length (defined by the default value array - * length or maxListLength) - * @param maxListLength the maximum length of this array, use -1 for no max length - * @return a double array Property object with all settings defined - */ - public Property get(String category, String key, double[] defaultValues, String comment, double minValue, double maxValue, - boolean isListLengthFixed, int maxListLength) - { - String[] values = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - { - values[i] = Double.toString(defaultValues[i]); - } - - - Property prop = get(category, key, values, comment, DOUBLE); - prop.setDefaultValues(values); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - prop.setIsListLengthFixed(isListLengthFixed); - prop.setMaxListLength(maxListLength); - - if (!prop.isDoubleList()) - { - prop.setValues(values); - } - - return prop; - } - - /* **************************************************************************************************************** - * - * STRING gets - * - *****************************************************************************************************************/ - - /** - * Gets a string Property without a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @return a string Property with validationPattern = null, validValues = null - */ - public Property get(String category, String key, String defaultValue) - { - return get(category, key, defaultValue, null); - } - - /** - * Gets a string Property with a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @return a string Property with validationPattern = null, validValues = null - */ - public Property get(String category, String key, String defaultValue, String comment) - { - return get(category, key, defaultValue, comment, STRING); - } - - /** - * Gets a string Property with a comment using the defined validationPattern and otherwise default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @param validationPattern a Pattern object for input validation - * @return a string Property with the defined validationPattern, validValues = null - */ - public Property get(String category, String key, String defaultValue, String comment, Pattern validationPattern) - { - Property prop = get(category, key, defaultValue, comment, STRING); - prop.setValidationPattern(validationPattern); - return prop; - } - - /** - * Gets a string Property with a comment using the defined validValues array and otherwise default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @param validValues an array of valid values that this Property can be set to. If an array is provided the Config GUI control will be - * a value cycle button. - * @return a string Property with the defined validValues array, validationPattern = null - */ - public Property get(String category, String key, String defaultValue, String comment, String[] validValues) - { - Property prop = get(category, key, defaultValue, comment, STRING); - prop.setValidValues(validValues); - return prop; - } - - /** - * Gets a string array Property without a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @return a string array Property with validationPattern = null, isListLengthFixed = false, maxListLength = -1 - */ - public Property get(String category, String key, String[] defaultValues) - { - return get(category, key, defaultValues, null, false, -1, null); - } - - /** - * Gets a string array Property with a comment using the default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @return a string array Property with validationPattern = null, isListLengthFixed = false, maxListLength = -1 - */ - public Property get(String category, String key, String[] defaultValues, String comment) - { - return get(category, key, defaultValues, comment, false, -1, null); - } - - /** - * Gets a string array Property with a comment using the defined validationPattern and otherwise default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param validationPattern a Pattern object for input validation - * @return a string array Property with the defined validationPattern, isListLengthFixed = false, maxListLength = -1 - */ - public Property get(String category, String key, String[] defaultValues, String comment, Pattern validationPattern) - { - return get(category, key, defaultValues, comment, false, -1, validationPattern); - } - - /** - * Gets a string array Property with a comment with all settings defined. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param isListLengthFixed boolean for whether this array is required to be a specific length (defined by the default value array - * length or maxListLength) - * @param maxListLength the maximum length of this array, use -1 for no max length - * @param validationPattern a Pattern object for input validation - * @return a string array Property with a comment with all settings defined - */ - public Property get(String category, String key, String[] defaultValues, String comment, - boolean isListLengthFixed, int maxListLength, Pattern validationPattern) - { - Property prop = get(category, key, defaultValues, comment, STRING); - prop.setIsListLengthFixed(isListLengthFixed); - prop.setMaxListLength(maxListLength); - prop.setValidationPattern(validationPattern); - return prop; - } - - /* **************************************************************************************************************** - * - * GENERIC gets - * - *****************************************************************************************************************/ - - /** - * Gets a Property object of the specified type using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValue the default value - * @param comment a String comment - * @param type a Property.Type enum value - * @return a Property object of the specified type using default settings - */ - public Property get(String category, String key, String defaultValue, String comment, Property.Type type) - { - ConfigCategory cat = getCategory(category); - - if (cat.containsKey(key)) - { - Property prop = cat.get(key); - - if (prop.getType() == null) - { - prop = new Property(prop.getName(), prop.getString(), type); - cat.put(key, prop); - } - - prop.setDefaultValue(defaultValue); - prop.setComment(comment); - return prop; - } - else if (defaultValue != null) - { - Property prop = new Property(key, defaultValue, type); - prop.setValue(defaultValue); //Set and mark as dirty to signify it should save - cat.put(key, prop); - prop.setDefaultValue(defaultValue); - prop.setComment(comment); - return prop; - } - else - { - return null; - } - } - - /** - * Gets a list (array) Property object of the specified type using default settings. - * - * @param category the config category - * @param key the Property key value - * @param defaultValues an array containing the default values - * @param comment a String comment - * @param type a Property.Type enum value - * @return a list (array) Property object of the specified type using default settings - */ - public Property get(String category, String key, String[] defaultValues, String comment, Property.Type type) - { - ConfigCategory cat = getCategory(category); - - if (cat.containsKey(key)) - { - Property prop = cat.get(key); - - if (prop.getType() == null) - { - prop = new Property(prop.getName(), prop.getString(), type); - cat.put(key, prop); - } - - prop.setDefaultValues(defaultValues); - prop.setComment(comment); - - return prop; - } - else if (defaultValues != null) - { - Property prop = new Property(key, defaultValues, type); - prop.setDefaultValues(defaultValues); - prop.setComment(comment); - cat.put(key, prop); - return prop; - } - else - { - return null; - } - } - - /* **************************************************************************************************************** - * - * Other methods - * - *************************************************************************************************************** */ - - public boolean hasCategory(String category) - { - if (!caseSensitiveCustomCategories) - category = category.toLowerCase(Locale.ENGLISH); - return categories.get(category) != null; - } - - public boolean hasKey(String category, String key) - { - if (!caseSensitiveCustomCategories) - category = category.toLowerCase(Locale.ENGLISH); - ConfigCategory cat = categories.get(category); - return cat != null && cat.containsKey(key); - } - - public void load() - { - if (PARENT != null && PARENT != this) - { - return; - } - - BufferedReader buffer = null; - UnicodeInputStreamReader input = null; - try - { - if (file.getParentFile() != null) - { - file.getParentFile().mkdirs(); - } - - if (!file.exists()) - { - // Either a previous load attempt failed or the file is new; clear maps - categories.clear(); - children.clear(); - if (!file.createNewFile()) - return; - } - - if (file.canRead()) - { - input = new UnicodeInputStreamReader(new FileInputStream(file), defaultEncoding); - defaultEncoding = input.getEncoding(); - buffer = new BufferedReader(input); - - String line; - ConfigCategory currentCat = null; - Property.Type type = null; - ArrayList tmpList = null; - int lineNum = 0; - String name = null; - loadedConfigVersion = null; - - while (true) - { - lineNum++; - line = buffer.readLine(); - - if (line == null) - { - if (lineNum == 1) - loadedConfigVersion = definedConfigVersion; - break; - } - - Matcher start = CONFIG_START.matcher(line); - Matcher end = CONFIG_END.matcher(line); - - if (start.matches()) - { - fileName = start.group(1); - categories = new TreeMap(); - continue; - } - else if (end.matches()) - { - fileName = end.group(1); - Configuration child = new Configuration(); - child.categories = categories; - this.children.put(fileName, child); - continue; - } - - int nameStart = -1, nameEnd = -1; - boolean skip = false; - boolean quoted = false; - boolean isFirstNonWhitespaceCharOnLine = true; - - for (int i = 0; i < line.length() && !skip; ++i) - { - if (Character.isLetterOrDigit(line.charAt(i)) || ALLOWED_CHARS.indexOf(line.charAt(i)) != -1 || (quoted && line.charAt(i) != '"')) - { - if (nameStart == -1) - { - nameStart = i; - } - - nameEnd = i; - isFirstNonWhitespaceCharOnLine = false; - } - else if (Character.isWhitespace(line.charAt(i))) - { - // ignore space characters - } - else - { - switch (line.charAt(i)) - { - case '#': - if (tmpList != null) // allow special characters as part of string lists - break; - skip = true; - continue; - - case '"': - if (tmpList != null) // allow special characters as part of string lists - break; - if (quoted) - { - quoted = false; - } - if (!quoted && nameStart == -1) - { - quoted = true; - } - break; - - case '{': - if (tmpList != null) // allow special characters as part of string lists - break; - name = line.substring(nameStart, nameEnd + 1); - if (!caseSensitiveCustomCategories) - name = name.toLowerCase(Locale.ENGLISH); - String qualifiedName = ConfigCategory.getQualifiedName(name, currentCat); - - ConfigCategory cat = categories.get(qualifiedName); - if (cat == null) - { - currentCat = new ConfigCategory(name, currentCat); - categories.put(qualifiedName, currentCat); - } - else - { - currentCat = cat; - } - name = null; - - break; - - case '}': - if (tmpList != null) // allow special characters as part of string lists - break; - if (currentCat == null) - { - throw new RuntimeException(String.format("Config file corrupt, attempted to close to many categories '%s:%d'", fileName, lineNum)); - } - currentCat = currentCat.parent; - break; - - case '=': - if (tmpList != null) // allow special characters as part of string lists - break; - name = line.substring(nameStart, nameEnd + 1); - - if (currentCat == null) - { - throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum)); - } - - Property prop = new Property(name, line.substring(i + 1), type, true); - i = line.length(); - - currentCat.put(name, prop); - - break; - - case ':': - if (tmpList != null) // allow special characters as part of string lists - break; - type = Property.Type.tryParse(line.substring(nameStart, nameEnd + 1).charAt(0)); - nameStart = nameEnd = -1; - break; - - case '<': - if ((tmpList != null && i + 1 == line.length()) || (tmpList == null && i + 1 != line.length())) - { - throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum)); - } - else if (i + 1 == line.length()) - { - name = line.substring(nameStart, nameEnd + 1); - - if (currentCat == null) - { - throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum)); - } - - tmpList = new ArrayList(); - - skip = true; - } - - break; - - case '>': - if (tmpList == null) - { - throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum)); - } - - if (isFirstNonWhitespaceCharOnLine) - { - currentCat.put(name, new Property(name, tmpList.toArray(new String[tmpList.size()]), type)); - name = null; - tmpList = null; - type = null; - } // else allow special characters as part of string lists - break; - - case '~': - if (tmpList != null) // allow special characters as part of string lists - break; - - if (line.startsWith(CONFIG_VERSION_MARKER)) - { - int colon = line.indexOf(':'); - if (colon != -1) - loadedConfigVersion = line.substring(colon + 1).trim(); - - skip = true; - } - break; - - default: - if (tmpList != null) // allow special characters as part of string lists - break; - throw new RuntimeException(String.format("Unknown character '%s' in '%s:%d'", line.charAt(i), fileName, lineNum)); - } - isFirstNonWhitespaceCharOnLine = false; - } - } - - if (quoted) - { - throw new RuntimeException(String.format("Unmatched quote in '%s:%d'", fileName, lineNum)); - } - else if (tmpList != null && !skip) - { - tmpList.add(line.trim()); - } - } - } - } - catch (IOException e) - { - LOGGER.error("Error while loading config {}.", fileName, e); - } - finally - { - IOUtils.closeQuietly(buffer); - IOUtils.closeQuietly(input); - } - - resetChangedState(); - } - - public void save() - { - if (PARENT != null && PARENT != this) - { - PARENT.save(); - return; - } - - try - { - if (file.getParentFile() != null) - { - file.getParentFile().mkdirs(); - } - - if (!file.exists() && !file.createNewFile()) - { - return; - } - - if (file.canWrite()) - { - FileOutputStream fos = new FileOutputStream(file); - BufferedWriter buffer = new BufferedWriter(new OutputStreamWriter(fos, defaultEncoding)); - - buffer.write("# Configuration file" + NEW_LINE + NEW_LINE); - - if (this.definedConfigVersion != null) - buffer.write(CONFIG_VERSION_MARKER + ": " + this.definedConfigVersion + NEW_LINE + NEW_LINE); - - if (children.isEmpty()) - { - save(buffer); - } - else - { - for (Map.Entry entry : children.entrySet()) - { - buffer.write("START: \"" + entry.getKey() + "\"" + NEW_LINE); - entry.getValue().save(buffer); - buffer.write("END: \"" + entry.getKey() + "\"" + NEW_LINE + NEW_LINE); - } - } - - buffer.close(); - fos.close(); - } - } - catch (IOException e) - { - LOGGER.error("Error while saving config {}.", fileName, e); - } - } - - private void save(BufferedWriter out) throws IOException - { - for (ConfigCategory cat : categories.values()) - { - if (!cat.isChild()) - { - cat.write(out, 0); - out.newLine(); - } - } - } - - public ConfigCategory getCategory(String category) - { - if (!caseSensitiveCustomCategories) - category = category.toLowerCase(Locale.ENGLISH); - - ConfigCategory ret = categories.get(category); - - if (ret == null) - { - if (category.contains(CATEGORY_SPLITTER)) - { - String[] hierarchy = category.split("\\"+CATEGORY_SPLITTER); - ConfigCategory parent = categories.get(hierarchy[0]); - - if (parent == null) - { - parent = new ConfigCategory(hierarchy[0]); - categories.put(parent.getQualifiedName(), parent); - changed = true; - } - - for (int i = 1; i < hierarchy.length; i++) - { - String name = ConfigCategory.getQualifiedName(hierarchy[i], parent); - ConfigCategory child = categories.get(name); - - if (child == null) - { - child = new ConfigCategory(hierarchy[i], parent); - categories.put(name, child); - changed = true; - } - - ret = child; - parent = child; - } - } - else - { - ret = new ConfigCategory(category); - categories.put(category, ret); - changed = true; - } - } - - return ret; - } - - public void removeCategory(ConfigCategory category) - { - for (ConfigCategory child : category.getChildren()) - { - removeCategory(child); - } - - if (categories.containsKey(category.getQualifiedName())) - { - categories.remove(category.getQualifiedName()); - if (category.parent != null) - { - category.parent.removeChild(category); - } - changed = true; - } - } - - /** - * Adds a comment to the specified ConfigCategory object - * - * @param category the config category - * @param comment a String comment - */ - public Configuration setCategoryComment(String category, String comment) - { - getCategory(category).setComment(comment); - return this; - } - - public void addCustomCategoryComment(String category, String comment) - { - this.setCategoryComment(category, comment); - } - - /** - * Adds a language key to the specified ConfigCategory object - * - * @param category the config category - * @param langKey a language key string such as configcategory.general - */ - public Configuration setCategoryLanguageKey(String category, String langKey) - { - getCategory(category).setLanguageKey(langKey); - return this; - } - - /** - * Sets the custom IConfigEntry class that should be used in place of the standard entry class (which is just a button that - * navigates into the category). This class MUST provide a constructor with the following parameter types: {@link GuiConfig} (the parent - * GuiConfig screen will be provided), {@link GuiConfigEntries} (the parent GuiConfigEntries will be provided), {@link IConfigElement} - * (the IConfigElement for this Property will be provided). - * - * @see GuiConfigEntries.ListEntryBase - * @see GuiConfigEntries.StringEntry - * @see GuiConfigEntries.BooleanEntry - * @see GuiConfigEntries.DoubleEntry - * @see GuiConfigEntries.IntegerEntry - * / - public Configuration setCategoryConfigEntryClass(String category, Class clazz) - { - getCategory(category).setConfigEntryClass(clazz); - return this; - } -*/ - /** - * Sets the flag for whether or not this category can be edited while a world is running. Care should be taken to ensure - * that only properties that are truly dynamic can be changed from the in-game options menu. Only set this flag to - * true if all child properties/categories are unable to be modified while a world is running. - */ - public Configuration setCategoryRequiresWorldRestart(String category, boolean requiresWorldRestart) - { - getCategory(category).setRequiresWorldRestart(requiresWorldRestart); - return this; - } - - /** - * Sets whether or not this ConfigCategory requires Minecraft to be restarted when changed. - * Defaults to false. Only set this flag to true if ALL child properties/categories require - * Minecraft to be restarted when changed. Setting this flag will also prevent modification - * of the child properties/categories while a world is running. - */ - public Configuration setCategoryRequiresMcRestart(String category, boolean requiresMcRestart) - { - getCategory(category).setRequiresMcRestart(requiresMcRestart); - return this; - } - - /** - * Sets the order that direct child properties of this config category will be written to the config file and will be displayed in - * config GUIs. - */ - public Configuration setCategoryPropertyOrder(String category, List propOrder) - { - getCategory(category).setPropertyOrder(propOrder); - return this; - } - - private void setChild(String name, Configuration child) - { - if (!children.containsKey(name)) - { - children.put(name, child); - changed = true; - } - else - { - Configuration old = children.get(name); - child.categories = old.categories; - child.fileName = old.fileName; - old.changed = true; - } - } - - public static void enableGlobalConfig() - { - PARENT = new Configuration(new File(FMLPaths.FMLCONFIG.get().toFile(), "global.cfg")); - PARENT.load(); - } - - public static class UnicodeInputStreamReader extends Reader - { - private final InputStreamReader input; - @SuppressWarnings("unused") - private final String defaultEnc; - - public UnicodeInputStreamReader(InputStream source, String encoding) throws IOException - { - defaultEnc = encoding; - String enc = encoding; - byte[] data = new byte[4]; - - PushbackInputStream pbStream = new PushbackInputStream(source, data.length); - int read = pbStream.read(data, 0, data.length); - int size = 0; - - int bom16 = (data[0] & 0xFF) << 8 | (data[1] & 0xFF); - int bom24 = bom16 << 8 | (data[2] & 0xFF); - int bom32 = bom24 << 8 | (data[3] & 0xFF); - - if (bom24 == 0xEFBBBF) - { - enc = "UTF-8"; - size = 3; - } - else if (bom16 == 0xFEFF) - { - enc = "UTF-16BE"; - size = 2; - } - else if (bom16 == 0xFFFE) - { - enc = "UTF-16LE"; - size = 2; - } - else if (bom32 == 0x0000FEFF) - { - enc = "UTF-32BE"; - size = 4; - } - else if (bom32 == 0xFFFE0000) //This will never happen as it'll be caught by UTF-16LE, - { //but if anyone ever runs across a 32LE file, i'd like to dissect it. - enc = "UTF-32LE"; - size = 4; - } - - if (size < read) - { - pbStream.unread(data, size, read - size); - } - - this.input = new InputStreamReader(pbStream, enc); - } - - public String getEncoding() - { - return input.getEncoding(); - } - - @Override - public int read(char[] cbuf, int off, int len) throws IOException - { - return input.read(cbuf, off, len); - } - - @Override - public void close() throws IOException - { - input.close(); - } - } - - public boolean hasChanged() - { - if (changed) return true; - - for (ConfigCategory cat : categories.values()) - { - if (cat.hasChanged()) return true; - } - - for (Configuration child : children.values()) - { - if (child.hasChanged()) return true; - } - - return false; - } - - private void resetChangedState() - { - changed = false; - for (ConfigCategory cat : categories.values()) - { - cat.resetChangedState(); - } - - for (Configuration child : children.values()) - { - child.resetChangedState(); - } - } - - public Set getCategoryNames() - { - return ImmutableSet.copyOf(categories.keySet()); - } - - /** - * Renames a property in a given category. - * - * @param category the category in which the property resides - * @param oldPropName the existing property name - * @param newPropName the new property name - * @return true if the category and property exist, false otherwise - */ - public boolean renameProperty(String category, String oldPropName, String newPropName) - { - if (hasCategory(category)) - { - ConfigCategory cat = getCategory(category); - if (cat.containsKey(oldPropName) && !oldPropName.equalsIgnoreCase(newPropName)) - { - Property prop = cat.remove(oldPropName); - prop.setName(newPropName); - cat.put(newPropName, prop); - return true; - } - } - return false; - } - - /** - * Moves a property from one category to another. - * - * @param oldCategory the category the property currently resides in - * @param propName the name of the property to move - * @param newCategory the category the property should be moved to - * @return true if the old category and property exist, false otherwise - */ - public boolean moveProperty(String oldCategory, String propName, String newCategory) - { - if (!oldCategory.equals(newCategory)) - if (hasCategory(oldCategory)) - if (getCategory(oldCategory).containsKey(propName)) - { - getCategory(newCategory).put(propName, getCategory(oldCategory).remove(propName)); - return true; - } - return false; - } - - /** - * Copies property objects from another Configuration object to this one using the list of category names. Properties that only exist in the - * "from" object are ignored. Pass null for the ctgys array to include all categories. - */ - public void copyCategoryProps(Configuration fromConfig, String[] ctgys) - { - if (ctgys == null) - ctgys = this.getCategoryNames().toArray(new String[this.getCategoryNames().size()]); - - for (String ctgy : ctgys) - if (fromConfig.hasCategory(ctgy) && this.hasCategory(ctgy)) - { - ConfigCategory thiscc = this.getCategory(ctgy); - ConfigCategory fromcc = fromConfig.getCategory(ctgy); - for (Entry entry : thiscc.getValues().entrySet()) - if (fromcc.containsKey(entry.getKey())) - thiscc.put(entry.getKey(), fromcc.get(entry.getKey())); - } - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment) - { - return getString(name, category, defaultValue, comment, name, null); - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @param langKey A language key used for localization of GUIs - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment, String langKey) - { - return getString(name, category, defaultValue, comment, langKey, null); - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment, Pattern pattern) - { - return getString(name, category, defaultValue, comment, name, pattern); - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @param langKey A language key used for localization of GUIs - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment, String langKey, Pattern pattern) - { - Property prop = this.get(category, name, defaultValue); - prop.setLanguageKey(langKey); - prop.setValidationPattern(pattern); - prop.setComment(comment + " [default: " + defaultValue + "]"); - return prop.getString(); - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @param validValues A list of valid values that this property can be set to. - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment, String[] validValues) - { - return getString(name, category, defaultValue, comment, validValues, name); - } - - /** - * Creates a string property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @param validValues A list of valid values that this property can be set to. - * @param langKey A language key used for localization of GUIs - * @return The value of the new string property. - */ - public String getString(String name, String category, String defaultValue, String comment, String[] validValues, String langKey) - { - Property prop = this.get(category, name, defaultValue); - prop.setValidValues(validValues); - prop.setLanguageKey(langKey); - prop.setComment(comment + " [default: " + defaultValue + "]"); - return prop.getString(); - } - - /** - * Creates a string list property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValues Default values of the property. - * @param comment A brief description what the property does. - * @return The value of the new string property. - */ - public String[] getStringList(String name, String category, String[] defaultValues, String comment) - { - return getStringList(name, category, defaultValues, comment, null, name); - } - - /** - * Creates a string list property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @return The value of the new string property. - */ - public String[] getStringList(String name, String category, String[] defaultValue, String comment, String[] validValues) - { - return getStringList(name, category, defaultValue, comment, validValues, name); - } - - /** - * Creates a string list property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @return The value of the new string property. - */ - public String[] getStringList(String name, String category, String[] defaultValue, String comment, String[] validValues, String langKey) - { - Property prop = this.get(category, name, defaultValue); - prop.setLanguageKey(langKey); - prop.setValidValues(validValues); - prop.setComment(comment + " [default: " + prop.getDefault() + "]"); - return prop.getStringList(); - } - - /** - * Creates a boolean property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @return The value of the new boolean property. - */ - public boolean getBoolean(String name, String category, boolean defaultValue, String comment) - { - return getBoolean(name, category, defaultValue, comment, name); - } - - /** - * Creates a boolean property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param comment A brief description what the property does. - * @param langKey A language key used for localization of GUIs - * @return The value of the new boolean property. - */ - public boolean getBoolean(String name, String category, boolean defaultValue, String comment, String langKey) - { - Property prop = this.get(category, name, defaultValue); - prop.setLanguageKey(langKey); - prop.setComment(comment + " [default: " + defaultValue + "]"); - return prop.getBoolean(defaultValue); - } - - /** - * Creates a integer property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param minValue Minimum value of the property. - * @param maxValue Maximum value of the property. - * @param comment A brief description what the property does. - * @return The value of the new integer property. - */ - public int getInt(String name, String category, int defaultValue, int minValue, int maxValue, String comment) - { - return getInt(name, category, defaultValue, minValue, maxValue, comment, name); - } - - /** - * Creates a integer property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param minValue Minimum value of the property. - * @param maxValue Maximum value of the property. - * @param comment A brief description what the property does. - * @param langKey A language key used for localization of GUIs - * @return The value of the new integer property. - */ - public int getInt(String name, String category, int defaultValue, int minValue, int maxValue, String comment, String langKey) - { - Property prop = this.get(category, name, defaultValue); - prop.setLanguageKey(langKey); - prop.setComment(comment + " [range: " + minValue + " ~ " + maxValue + ", default: " + defaultValue + "]"); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - return prop.getInt(defaultValue) < minValue ? minValue : (prop.getInt(defaultValue) > maxValue ? maxValue : prop.getInt(defaultValue)); - } - - /** - * Creates a float property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param minValue Minimum value of the property. - * @param maxValue Maximum value of the property. - * @param comment A brief description what the property does. - * @return The value of the new float property. - */ - public float getFloat(String name, String category, float defaultValue, float minValue, float maxValue, String comment) - { - return getFloat(name, category, defaultValue, minValue, maxValue, comment, name); - } - - /** - * Creates a float property. - * - * @param name Name of the property. - * @param category Category of the property. - * @param defaultValue Default value of the property. - * @param minValue Minimum value of the property. - * @param maxValue Maximum value of the property. - * @param comment A brief description what the property does. - * @param langKey A language key used for localization of GUIs - * @return The value of the new float property. - */ - public float getFloat(String name, String category, float defaultValue, float minValue, float maxValue, String comment, String langKey) - { - Property prop = this.get(category, name, Float.toString(defaultValue), name); - prop.setLanguageKey(langKey); - prop.setComment(comment + " [range: " + minValue + " ~ " + maxValue + ", default: " + defaultValue + "]"); - prop.setMinValue(minValue); - prop.setMaxValue(maxValue); - try - { - float parseFloat = Float.parseFloat(prop.getString()); - return Floats.constrainToRange(parseFloat, minValue, maxValue); - } - catch (Exception e) - { - LOGGER.error("Failed to get float for {}/{}", name, category, e); - } - return defaultValue; - } - - public File getConfigFile() - { - return file; - } -} diff --git a/src/main/java/net/minecraftforge/common/config/Property.java b/src/main/java/net/minecraftforge/common/config/Property.java deleted file mode 100644 index a7465f906..000000000 --- a/src/main/java/net/minecraftforge/common/config/Property.java +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.common.config; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.regex.Pattern; - -import net.minecraftforge.fml.client.config.IArrayEntry; -import net.minecraftforge.fml.client.config.IConfigElement; -import net.minecraftforge.fml.client.config.IConfigEntry; - -public class Property -{ - public String getComment() - { - return comment; - } - - public void setComment(String comment) - { - this.comment = comment; - } - - public enum Type - { - STRING, - INTEGER, - BOOLEAN, - DOUBLE, - COLOR, - MOD_ID; - - public static Type tryParse(char id) - { - for (int x = 0; x < values().length; x++) - { - if (values()[x].getID() == id) - { - return values()[x]; - } - } - - return STRING; - } - - public char getID() - { - return name().charAt(0); - } - } - - private String name; - private String value; - private String defaultValue; - private String comment; - private String[] values; - private String[] defaultValues; - private String[] validValues; - private String langKey; - private String minValue; - private String maxValue; - - private Class configEntryClass = null; - private Class arrayEntryClass = null; - - private boolean requiresWorldRestart = false; - private boolean showInGui = true; - private boolean requiresMcRestart = false; - private Pattern validationPattern; - private final boolean wasRead; - private final boolean isList; - private boolean isListLengthFixed = false; - private int maxListLength = -1; - private final Type type; - private boolean changed = false; - - public Property(String name, String value, Type type) - { - this(name, value, type, false, new String[0], name); - } - - public Property(String name, String value, Type type, boolean read) - { - this(name, value, type, read, new String[0], name); - } - - public Property(String name, String value, Type type, String[] validValues) - { - this(name, value, type, false, validValues, name); - } - - public Property(String name, String value, Type type, String langKey) - { - this(name, value, type, false, new String[0], langKey); - } - - public Property(String name, String value, Type type, boolean read, String langKey) - { - this(name, value, type, read, new String[0], langKey); - } - - public Property(String name, String value, Type type, String[] validValues, String langKey) - { - this(name, value, type, false, validValues, langKey); - } - - Property(String name, String value, Type type, boolean read, String[] validValues, String langKey) - { - setName(name); - this.value = value; - this.values = new String[0]; - this.type = type; - wasRead = read; - isList = false; - this.defaultValue = value; - this.defaultValues = new String[0]; - this.validValues = validValues; - this.isListLengthFixed = false; - this.maxListLength = -1; - this.minValue = String.valueOf(Integer.MIN_VALUE); - this.maxValue = String.valueOf(Integer.MAX_VALUE); - this.langKey = langKey; - this.setComment(""); - } - - public Property(String name, String[] values, Type type) - { - this(name, values, type, false); - } - - Property(String name, String[] values, Type type, boolean read) - { - this(name, values, type, read, new String[0], name); - } - - public Property(String name, String[] values, Type type, String langKey) - { - this(name, values, type, false, langKey); - } - - Property(String name, String[] values, Type type, boolean read, String langKey) - { - this(name, values, type, read, new String[0], langKey); - } - - Property(String name, String[] values, Type type, boolean read, String[] validValues, String langKey) - { - setName(name); - this.type = type; - this.values = Arrays.copyOf(values, values.length); - wasRead = read; - isList = true; - this.value = ""; - this.defaultValue = ""; - for (String s : values) - this.defaultValue += ", [" + s + "]"; - this.defaultValue = this.defaultValue.replaceFirst(", ", ""); - this.defaultValues = Arrays.copyOf(values, values.length); - this.validValues = validValues; - this.isListLengthFixed = false; - this.maxListLength = -1; - this.minValue = String.valueOf(Integer.MIN_VALUE); - this.maxValue = String.valueOf(Integer.MAX_VALUE); - this.langKey = langKey; - this.setComment(""); - } - - /** - * Returns whether or not this Property is defaulted. - * - * @return true if the current value(s) is(are) deeply equal to the default value(s) - */ - public boolean isDefault() - { - if (this.isBooleanList()) - { - if (values.length == defaultValues.length) - { - for (int i = 0; i < values.length; i++) - if (Boolean.parseBoolean(values[i]) != Boolean.parseBoolean(defaultValues[i])) - return false; - - return true; - } - else - return false; - } - - if (this.isIntList()) - { - if (values.length == defaultValues.length) - { - for (int i = 0; i < values.length; i++) - if (Integer.parseInt(values[i]) != Integer.parseInt(defaultValues[i])) - return false; - - return true; - } - else - return false; - } - - if (this.isDoubleList()) - { - if (values.length == defaultValues.length) - { - for (int i = 0; i < values.length; i++) - if (Double.parseDouble(values[i]) != Double.parseDouble(defaultValues[i])) - return false; - - return true; - } - else - return false; - } - - if (this.isList()) - { - if (values.length == defaultValues.length) - { - for (int i = 0; i < values.length; i++) - if (!values[i].equals(defaultValues[i])) - return false; - - return true; - } - else - return false; - } - - if (this.type == Type.BOOLEAN && this.isBooleanValue()) - return Boolean.parseBoolean(value) == Boolean.parseBoolean(defaultValue); - - if (this.type == Type.INTEGER && this.isIntValue()) - return Integer.parseInt(value) == Integer.parseInt(defaultValue); - - if (this.type == Type.DOUBLE && this.isDoubleValue()) - return Double.parseDouble(value) == Double.parseDouble(defaultValue); - - return value.equals(defaultValue); - } - - /** - * Sets the current value(s) of this Property to the default value(s). - */ - public Property setToDefault() - { - this.value = this.defaultValue; - this.values = Arrays.copyOf(this.defaultValues, this.defaultValues.length); - return this; - } - - /** - * Gets the raw String default value of this Property. Check for isList() == false first. - * - * @return the default value String - */ - public String getDefault() - { - return defaultValue; - } - - /** - * Gets the raw String[] default values of this Property. Check for isList() == true first. - * - * @return the default values String[] - */ - public String[] getDefaults() - { - return Arrays.copyOf(this.defaultValues, this.defaultValues.length); - } - - /** - * Sets the flag for whether or not this Property can be edited while a world is running. Care should be taken to ensure - * that only properties that are truly dynamic can be changed from the in-game options menu. When set to false the Property will be - * editable from both the main menu Mods list config screen and the in-game Mod Options config screen. When set to true the Property - * will only be editable from the main menu Mods list config screen. - */ - public Property setRequiresWorldRestart(boolean requiresWorldRestart) - { - this.requiresWorldRestart = requiresWorldRestart; - return this; - } - - /** - * Returns whether or not this Property is able to be edited while a world is running using the in-game Mod Options screen - * as well as the Mods list screen, or only from the Mods list screen. Setting this flag to true will disable editing of - * this property while a world is running. - */ - public boolean requiresWorldRestart() - { - return this.requiresWorldRestart; - } - - /** - * Sets whether or not this Property should be allowed to show on config GUIs. - * Defaults to true. - */ - public Property setShowInGui(boolean showInGui) - { - this.showInGui = showInGui; - return this; - } - - /** - * Gets whether or not this Property should be allowed to show on config GUIs. - * Defaults to true unless set to false. - */ - public boolean showInGui() - { - return showInGui; - } - - /** - * Sets whether or not this Property requires Minecraft to be restarted when changed. - * Defaults to false. Setting this flag to true will also disable editing of - * this property while a world is running. - */ - public Property setRequiresMcRestart(boolean requiresMcRestart) - { - this.requiresMcRestart = this.requiresWorldRestart = requiresMcRestart; - return this; - } - - /** - * Gets whether or not this Property requires Minecraft to be restarted when changed. - * Defaults to false unless set to true. - */ - public boolean requiresMcRestart() - { - return this.requiresMcRestart; - } - - /** - * Sets the maximum length of this list/array Property. Only important if isList() == true. If the current values array or default - * values array is longer than the new maximum it will be resized. If calling both this method and setIsListLengthFixed(true), this - * method should be called afterwards (but is not required). - */ - public Property setMaxListLength(int max) - { - this.maxListLength = max; - if (this.maxListLength != -1) - { - if (values != null && values.length != maxListLength) - if (this.isListLengthFixed || values.length > maxListLength) - values = Arrays.copyOf(values, maxListLength); - - if (defaultValues != null && defaultValues.length != maxListLength) - if (this.isListLengthFixed || defaultValues.length > maxListLength) - defaultValues = Arrays.copyOf(defaultValues, maxListLength); - } - return this; - } - - /** - * Gets the maximum length of this list/array Property. Only important if isList() == true. - */ - public int getMaxListLength() - { - return this.maxListLength; - } - - /** - * Sets the flag for whether this list/array Property has a fixed length. Only important if isList() == true. If calling both this - * method and setMaxListLength(), this method should be called first (but is not required). - */ - public Property setIsListLengthFixed(boolean isListLengthFixed) - { - this.isListLengthFixed = isListLengthFixed; - return this; - } - - /** - * Returns whether or not this list/array has a fixed length. Only important if isList() == true. - */ - public boolean isListLengthFixed() - { - return this.isListLengthFixed; - } - - /** - * Sets a custom IConfigEntry class that should be used in place of the standard entry class for this Property type. This class - * MUST provide a constructor with the following parameter types: {@link GuiConfig} (the owning GuiConfig screen will be provided), - * {@link GuiConfigEntries} (the owning GuiConfigEntries will be provided), {@link IConfigElement} (the IConfigElement for this Property - * will be provided). - * - * @see GuiConfigEntries.ListEntryBase - * @see GuiConfigEntries.StringEntry - * @see GuiConfigEntries.BooleanEntry - * @see GuiConfigEntries.DoubleEntry - * @see GuiConfigEntries.IntegerEntry - */ - public Property setConfigEntryClass(Class clazz) - { - this.configEntryClass = clazz; - return this; - } - - /** - * Gets the custom IConfigEntry class that should be used in place of the standard entry class for this Property type, or null if - * none has been set. - * - * @return a class that implements IConfigEntry - */ - public Class getConfigEntryClass() - { - return this.configEntryClass; - } - - /** - * Sets a custom IGuiEditListEntry class that should be used in place of the standard entry class for this Property type. This class - * MUST provide a constructor with the following parameter types: {@link GuiEditArray} (the owning GuiEditArray screen will be provided), - * {@link GuiEditArrayEntries} (the parent GuiEditArrayEntries will be provided), {@link IConfigElement} (the IConfigElement for this Property - * will be provided), and {@link Object} for the property's value. - * - * @see GuiEditArrayEntries.BaseEntry - * @see GuiEditArrayEntries.StringEntry - * @see GuiEditArrayEntries.BooleanEntry - * @see GuiEditArrayEntries.DoubleEntry - * @see GuiEditArrayEntries.IntegerEntry - */ - public Property setArrayEntryClass(Class clazz) - { - this.arrayEntryClass = clazz; - return this; - } - - /** - * Gets the custom IArrayEntry class that should be used in place of the standard entry class for this Property type, or null if - * none has been set. - * - * @return a class that implements IArrayEntry - */ - public Class getArrayEntryClass() - { - return this.arrayEntryClass; - } - - /** - * Sets a regex Pattern object used to validate user input for formatted String or String[] properties. - * - * @param validationPattern - */ - public Property setValidationPattern(Pattern validationPattern) - { - this.validationPattern = validationPattern; - return this; - } - - /** - * Gets the Pattern object used to validate user input for this Property. - * - * @return the user input validation Pattern object, or null if none is set - */ - public Pattern getValidationPattern() - { - return this.validationPattern; - } - - /** - * Sets the localization language key for this Property so that the config GUI screens are nice and pretty <3. The string languageKey + - * ".tooltip" is used for tooltips when a user hovers the mouse over a GUI property label. - * - * @param langKey a string language key such as myawesomemod.config.myPropName - */ - public Property setLanguageKey(String langKey) - { - this.langKey = langKey; - return this; - } - - /** - * Gets the language key string for this Property. - * - * @return the language key - */ - public String getLanguageKey() - { - return this.langKey; - } - - /** - * Sets the default string value of this Property. - * - * @param defaultValue a String value - */ - public Property setDefaultValue(String defaultValue) - { - this.defaultValue = defaultValue; - return this; - } - - /** - * Sets the default String[] values of this Property. - * - * @param defaultValues an array of String values - */ - public Property setDefaultValues(String[] defaultValues) - { - this.defaultValue = ""; - for (String s : defaultValues) - this.defaultValue += ", [" + s + "]"; - this.defaultValue = this.defaultValue.replaceFirst(", ", ""); - this.defaultValues = Arrays.copyOf(defaultValues, defaultValues.length); - return this; - } - - /** - * Sets the default int value of this Property. - * - * @param defaultValue an int value - */ - public Property setDefaultValue(int defaultValue) - { - setDefaultValue(Integer.toString(defaultValue)); - return this; - } - - /** - * Sets the default int[] values of this Property. - * - * @param defaultValues an array of int values - */ - public Property setDefaultValues(int[] defaultValues) - { - String[] temp = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - temp[i] = Integer.toString(defaultValues[i]); - - setDefaultValues(temp); - return this; - } - - /** - * Sets the default double value of this Property. - * - * @param defaultValue a double value - */ - public Property setDefaultValue(double defaultValue) - { - setDefaultValue(Double.toString(defaultValue)); - return this; - } - - /** - * Sets the default double[] values of this Property - * - * @param defaultValues an array of double values - */ - public Property setDefaultValues(double[] defaultValues) - { - String[] temp = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - temp[i] = Double.toString(defaultValues[i]); - - setDefaultValues(temp); - return this; - } - - /** - * Sets the default boolean value of this Property. - * - * @param defaultValue a boolean value - */ - public Property setDefaultValue(boolean defaultValue) - { - setDefaultValue(Boolean.toString(defaultValue)); - return this; - } - - /** - * Sets the default boolean[] values of this Property. - * - * @param defaultValues an array of boolean values - */ - public Property setDefaultValues(boolean[] defaultValues) - { - String[] temp = new String[defaultValues.length]; - for (int i = 0; i < defaultValues.length; i++) - temp[i] = Boolean.toString(defaultValues[i]); - - setDefaultValues(temp); - return this; - } - - /** - * Sets the minimum int value of this Property. - * - * @param minValue an int value - */ - public Property setMinValue(int minValue) - { - this.minValue = Integer.toString(minValue); - return this; - } - - /** - * Sets the maximum int value of this Property. - * - * @param maxValue an int value - */ - public Property setMaxValue(int maxValue) - { - this.maxValue = Integer.toString(maxValue); - return this; - } - - /** - * Sets the minimum double value of this Property. - * - * @param minValue a double value - */ - public Property setMinValue(double minValue) - { - this.minValue = Double.toString(minValue); - return this; - } - - /** - * Sets the maximum double value of this Property. - * - * @param maxValue a double value - */ - public Property setMaxValue(double maxValue) - { - this.maxValue = Double.toString(maxValue); - return this; - } - - /** - * Gets the minimum value. - * - * @return the minimum value bound - */ - public String getMinValue() - { - return minValue; - } - - /** - * Gets the maximum value. - * - * @return the maximum value bound - */ - public String getMaxValue() - { - return maxValue; - } - - /** - * Returns the value in this property as it's raw string. - * - * @return current value - */ - public String getString() - { - return value; - } - - /** - * Sets the array of valid values that this String Property can be set to. When an array of valid values is defined for a Property the - * GUI control for that property will be a value cycle button. - * - * @param validValues a String array of valid values - */ - public Property setValidValues(String[] validValues) - { - this.validValues = validValues; - return this; - } - - /** - * Gets the array of valid values that this String Property can be set to, or null if not defined. - * - * @return a String array of valid values - */ - public String[] getValidValues() - { - return this.validValues; - } - - /** - * Returns the value in this property as an integer, - * if the value is not a valid integer, it will return the initially provided default. - * - * @return The value - */ - public int getInt() - { - return getInt(Integer.parseInt(defaultValue)); - } - - /** - * Returns the value in this property as an integer, - * if the value is not a valid integer, it will return the - * provided default. - * - * @param _default The default to provide if the current value is not a valid integer - * @return The value - */ - public int getInt(int _default) - { - try - { - return Integer.parseInt(value); - } - catch (NumberFormatException e) - { - return _default; - } - } - - /** - * Checks if the current value stored in this property can be converted to an integer. - * @return True if the type of the Property is an Integer - */ - public boolean isIntValue() - { - try - { - Integer.parseInt(value); - return true; - } - catch (NumberFormatException e) - { - return false; - } - } - - /** - * Returns the value in this property as a long, - * if the value is not a valid long, it will return the initially provided default. - * - * @return The value - */ - public long getLong() - { - return getLong(Long.parseLong(defaultValue)); - } - - /** - * Returns the value in this property as a long, - * if the value is not a valid long, it will return the - * provided default. - * - * @param _default The default to provide if the current value is not a validlong - * @return The value - */ - public long getLong(long _default) - { - try - { - return Long.parseLong(value); - } - catch (NumberFormatException e) - { - return _default; - } - } - - /** - * Checks if the current value stored in this property can be converted to a long. - * @return True if the type of the Property is an Long - */ - public boolean isLongValue() - { - try - { - Long.parseLong(value); - return true; - } - catch (NumberFormatException e) - { - return false; - } - } - - /** - * Returns the value in this property as a boolean, - * if the value is not a valid boolean, it will return the - * provided default. - * - * @param _default The default to provide - * @return The value as a boolean, or the default - */ - public boolean getBoolean(boolean _default) - { - if (isBooleanValue()) - { - return Boolean.parseBoolean(value); - } - else - { - return _default; - } - } - - /** - * Returns the value in this property as a boolean, if the value is not a valid boolean, it will return the provided default. - * - * @return The value as a boolean, or the default - */ - public boolean getBoolean() - { - if (isBooleanValue()) - { - return Boolean.parseBoolean(value); - } - else - { - return Boolean.parseBoolean(defaultValue); - } - } - - /** - * Checks if the current value held by this property is a valid boolean value. - * - * @return True if it is a boolean value - */ - public boolean isBooleanValue() - { - return ("true".equals(value.toLowerCase()) || "false".equals(value.toLowerCase())); - } - - /** - * Checks if the current value held by this property is a valid double value. - * @return True if the value can be converted to an double - */ - public boolean isDoubleValue() - { - try - { - Double.parseDouble(value); - return true; - } - catch (NumberFormatException e) - { - return false; - } - } - - /** - * Returns the value in this property as a double, - * if the value is not a valid double, it will return the - * provided default. - * - * @param _default The default to provide if the current value is not a valid double - * @return The value - */ - public double getDouble(double _default) - { - try - { - return Double.parseDouble(value); - } - catch (NumberFormatException e) - { - return _default; - } - } - - /** - * Returns the value in this property as a double, if the value is not a valid double, it will return the provided default. - * - * @return The value - */ - public double getDouble() - { - try - { - return Double.parseDouble(value); - } - catch (NumberFormatException e) - { - return Double.parseDouble(defaultValue); - } - } - - public String[] getStringList() - { - return values; - } - - /** - * Returns the integer value of all values that can - * be parsed in the list. - * - * @return Array of length 0 if none of the values could be parsed. - */ - public int[] getIntList() - { - ArrayList nums = new ArrayList(); - - for (String value : values) - { - try - { - nums.add(Integer.parseInt(value)); - } - catch (NumberFormatException e){} - } - - int[] primitives = new int[nums.size()]; - - for (int i = 0; i < nums.size(); i++) - { - primitives[i] = nums.get(i); - } - - return primitives; - } - - /** - * Checks if all of the current values stored in this property can be converted to an integer. - * @return True if the type of the Property is an Integer List - */ - public boolean isIntList() - { - if (isList && type == Type.INTEGER) - for (String value : values) - { - try - { - Integer.parseInt(value); - } - catch (NumberFormatException e) - { - return false; - } - } - return isList && type == Type.INTEGER; - } - - /** - * Returns the boolean value of all values that can - * be parsed in the list. - * - * @return Array of length 0 if none of the values could be parsed. - */ - public boolean[] getBooleanList() - { - ArrayList tmp = new ArrayList(); - for (String value : values) - { - try - { - tmp.add(Boolean.parseBoolean(value)); - } - catch (NumberFormatException e){} - } - - boolean[] primitives = new boolean[tmp.size()]; - - for (int i = 0; i < tmp.size(); i++) - { - primitives[i] = tmp.get(i); - } - - return primitives; - } - - /** - * Checks if all of current values stored in this property can be converted to a boolean. - * @return True if it is a boolean value - */ - public boolean isBooleanList() - { - if (isList && type == Type.BOOLEAN) - for (String value : values) - { - if (!"true".equalsIgnoreCase(value) && !"false".equalsIgnoreCase(value)) - { - return false; - } - } - - return isList && type == Type.BOOLEAN; - } - - /** - * Returns the double value of all values that can - * be parsed in the list. - * - * @return Array of length 0 if none of the values could be parsed. - */ - public double[] getDoubleList() - { - ArrayList tmp = new ArrayList(); - for (String value : values) - { - try - { - tmp.add(Double.parseDouble(value)); - } - catch (NumberFormatException e) {} - } - - double[] primitives = new double[tmp.size()]; - - for (int i = 0; i < tmp.size(); i++) - { - primitives[i] = tmp.get(i); - } - - return primitives; - } - - /** - * Checks if all of the current values stored in this property can be converted to a double. - * @return True if the type of the Property is a double List - */ - public boolean isDoubleList() - { - if (isList && type == Type.DOUBLE) - for (String value : values) - { - try - { - Double.parseDouble(value); - } - catch (NumberFormatException e) - { - return false; - } - } - - return isList && type == Type.DOUBLE; - } - - /** - * Gets the name/key for this Property. - * - * @return the Property name - */ - public String getName() - { - return name; - } - - /** - * Sets the name/key for this Property. - * - * @param name a name - */ - public void setName(String name) - { - this.name = name; - } - - /** - * Determines if this config value was just created, or if it was read from the config file. - * This is useful for mods who auto-assign their blocks to determine if the ID returned is - * a configured one, or a automatically generated one. - * - * @return True if this property was loaded from the config file with a value - */ - public boolean wasRead() - { - return wasRead; - } - - /** - * Gets the Property.Type enum value for this Property. - * - * @return the Property's type - */ - public Type getType() - { - return type; - } - - /** - * Returns whether or not this Property is a list/array. - * - * @return true if this Property is a list/array, false otherwise - */ - public boolean isList() - { - return isList; - } - - /** - * Gets the changed status of this Property. - * - * @return true if this Property has changed, false otherwise - */ - public boolean hasChanged(){ return changed; } - void resetChangedState(){ changed = false; } - - /** - * Sets the value of this Property to the provided String value. - */ - public Property setValue(String value) - { - this.value = value; - changed = true; - return this; - } - - public void set(String value) - { - this.setValue(value); - } - - /** - * Sets the values of this Property to the provided String[] values. - */ - public Property setValues(String[] values) - { - this.values = Arrays.copyOf(values, values.length); - changed = true; - return this; - } - - public void set(String[] values) - { - this.setValues(values); - } - - /** - * Sets the value of this Property to the provided int value. - */ - public Property setValue(int value) - { - setValue(Integer.toString(value)); - return this; - } - - /** - * Sets the value of this Property to the provided boolean value. - */ - public Property setValue(boolean value) - { - setValue(Boolean.toString(value)); - return this; - } - - /** - * Sets the value of this Property to the provided double value. - */ - public Property setValue(double value) - { - setValue(Double.toString(value)); - return this; - } - - /** - * Sets the values of this Property to the provided boolean[] values. - */ - public Property setValues(boolean[] values) - { - this.values = new String[values.length]; - for (int i = 0; i < values.length; i++) - this.values[i] = String.valueOf(values[i]); - changed = true; - return this; - } - - public void set(boolean[] values) - { - this.setValues(values); - } - - /** - * Sets the values of this Property to the provided int[] values. - */ - public Property setValues(int[] values) - { - this.values = new String[values.length]; - for (int i = 0; i < values.length; i++) - this.values[i] = String.valueOf(values[i]); - changed = true; - return this; - } - - public void set(int[] values) - { - this.setValues(values); - } - - /** - * Sets the values of this Property to the provided double[] values. - */ - public Property setValues(double[] values) - { - this.values = new String[values.length]; - for (int i = 0; i < values.length; i++) - this.values[i] = String.valueOf(values[i]); - changed = true; - return this; - } - - public void set(double[] values) - { - this.setValues(values); - } - public void set(int value){ set(Integer.toString(value)); } - public void set(long value){ set(Long.toString(value)); } - public void set(boolean value){ set(Boolean.toString(value)); } - public void set(double value){ set(Double.toString(value)); } -}