diff --git a/src/main/java/net/minecraftforge/common/ForgeConfig.java b/src/main/java/net/minecraftforge/common/ForgeConfig.java new file mode 100644 index 000000000..07ce2a667 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/ForgeConfig.java @@ -0,0 +1,225 @@ +/* + * 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; + +import static net.minecraftforge.fml.Logging.CORE; + +import java.nio.file.Path; + +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.fml.common.FMLPaths; + +public class ForgeConfig +{ + private static ForgeConfig INSTANCE = new ForgeConfig(); + private static ForgeConfigSpec spec = new ForgeConfigSpec.Builder() + //General + .comment("Set to true to disable Forge's version check mechanics. Forge queries a small json file on our server for version information. For more details see the ForgeVersion class in our github.") + .translation("forge.configgui.disableVersionCheck") + .define("general.disableVersionCheck", false) + + .comment("Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.") + .translation("forge.configgui.removeErroringEntities") + .worldRestart() + .define("general.removeErroringEntities", false) + + .comment("Set this to true to remove any TileEntity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.") + .translation("forge.configgui.removeErroringTileEntities") + .worldRestart() + .define("general.removeErroringTileEntities", false) + + .comment("Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. Default: false") + .translation("forge.configgui.fullBoundingBoxLadders") + .worldRestart() + .define("general.fullBoundingBoxLadders", false) + + .comment("Base zombie summoning spawn chance. Allows changing the bonus zombie summoning mechanic.") + .translation("forge.configgui.zombieBaseSummonChance") + .worldRestart() + .defineInRange("general.zombieBaseSummonChance", 0.1D, 0.0D, 1.0D) + + .comment("Chance that a zombie (or subclass) is a baby. Allows changing the zombie spawning mechanic.") + .translation("forge.configgui.zombieBabyChance") + .worldRestart() + .defineInRange("general.zombieBabyChance", 0.05D, 0.0D, 1.0D) + + .comment("Log cascading chunk generation issues during terrain population.") + .translation("forge.configgui.logCascadingWorldGeneration") + .define("general.logCascadingWorldGeneration", true) + + .comment("Fix vanilla issues that cause worldgen cascading. This DOES change vanilla worldgen so DO NOT report bugs related to world differences if this flag is on.") + .translation("forge.configgui.fixVanillaCascading") + .define("general.fixVanillaCascading", false) + + + .comment("The time in ticks the server will wait when a dimension was queued to unload. This can be useful when rapidly loading and unloading dimensions, like e.g. throwing items through a nether portal a few time per second.") + .translation("forge.configgui.dimensionUnloadQueueDelay") + .defineInRange("general.dimensionUnloadQueueDelay", 0, 0, Integer.MAX_VALUE) + + //Client + .comment("Controls the number threshold at which Packet51 is preferred over Packet52, default and minimum 64, maximum 1024") + .translation("forge.configgui.clumpingThreshold") + .worldRestart() + .defineInRange("client.clumpingThreshold", 64, 64, 1024) + + .comment("Toggle off to make missing model text in the gui fit inside the slot.") + .translation("forge.configgui.zoomInMissingModelTextInGui") + .define("client.zoomInMissingModelTextInGui", false) + + .comment("Enable uploading cloud geometry to the GPU for faster rendering.") + .translation("forge.configgui.forgeCloudsEnabled") + .define("client.forgeCloudsEnabled", true) + + .comment("Disable culling of hidden faces next to stairs and slabs. Causes extra rendering, but may fix some resource packs that exploit this vanilla mechanic.") + .translation("forge.configgui.disableStairSlabCulling") + .define("client.disableStairSlabCulling", false) + + .comment("Enable forge to queue all chunk updates to the Chunk Update thread. May increase FPS significantly, but may also cause weird rendering lag. Not recommended for computers without a significant number of cores available.") + .translation("forge.configgui.alwaysSetupTerrainOffThread") + .define("client.alwaysSetupTerrainOffThread", false) + + .comment("Enable the forge block rendering pipeline - fixes the lighting of custom models.") + .translation("forge.configgui.forgeLightPipelineEnabled") + .define("client.forgeLightPipelineEnabled", true) + + .comment("When enabled, makes specific reload tasks such as language changing quicker to run.") + .translation("forge.configgui.selectiveResourceReloadEnabled") + .define("client.selectiveResourceReloadEnabled", true) + + + .build(); + + private CommentedFileConfig configData; + private void loadFrom(final Path configFile) + { + configData = CommentedFileConfig.builder(configFile).sync(). + autosave().autoreload(). + writingMode(WritingMode.REPLACE). + build(); + configData.load(); + if (!spec.isCorrect(configData)) { + LogManager.getLogger().warn(CORE, "Configuration file {} is not correct. Correcting", configFile); + spec.correct(configData, (action, path, incorrectValue, correctedValue) -> + LogManager.getLogger().warn(CORE, "Incorrect key {} was corrected from {} to {}", path, incorrectValue, correctedValue)); + } + configData.save(); + } + + public static void load() + { + Path configFile = FMLPaths.CONFIGDIR.get().resolve("forge.toml"); + INSTANCE.loadFrom(configFile); + LogManager.getLogger().debug(CORE, "Loaded FML config from {}", configFile); + } + + //General + //public static boolean disableVersionCheck = false; + //public static boolean removeErroringEntities = false; + //public static boolean removeErroringTileEntities = false; + //public static boolean fullBoundingBoxLadders = false; + //public static double zombieSummonBaseChance = 0.1; + //public static float zombieBabyChance = 0.05f; + //public static boolean logCascadingWorldGeneration = true; // see Chunk#logCascadingWorldGeneration() + //public static boolean fixVanillaCascading = false; + //public static int dimensionUnloadQueueDelay = 0; + + //Client + //public static int clumpingThreshold = 64; + //public static boolean zoomInMissingModelTextInGui = false; + //public static boolean forgeCloudsEnabled = true; + //public static boolean disableStairSlabCulling = false; + //public static boolean alwaysSetupTerrainOffThread = false; + //public static boolean forgeLightPipelineEnabled = true; + //public static boolean selectiveResourceReloadEnabled = false; + + //TODO + //public static int[] blendRanges = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34 }; + + /* + private static void syncConfig(boolean load) + { + //prop = config.get(Configuration.CATEGORY_CLIENT, "biomeSkyBlendRange", new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34 }); + //prop.setComment("Control the range of sky blending for colored skies in biomes."); + //prop.setLanguageKey("forge.configgui.biomeSkyBlendRange"); + //blendRanges = prop.getIntList(); + //propOrder.add(prop.getName()); + } + + /** + * By subscribing to the OnConfigChangedEvent we are able to execute code when our config screens are closed. + * This implementation uses the optional configID string to handle multiple Configurations using one event handler. + * / + @SubscribeEvent + public void onConfigChanged(OnConfigChangedEvent event) + { + if (getMetadata().modId.equals(event.getModID())) + { + if ("chunkLoader".equals(event.getConfigID())) + { + ForgeChunkManager.syncConfigDefaults(); + ForgeChunkManager.loadConfiguration(); + } + else + { + boolean tmpStairs = disableStairSlabCulling; + + syncConfig(false); + + if (event.isWorldRunning() && tmpStairs != disableStairSlabCulling) + { + FMLCommonHandler.instance().reloadRenderers(); + } + + } + } + } + + @SubscribeEvent + public void missingMapping(RegistryEvent.MissingMappings event) + { + for (MissingMappings.Mapping entry : event.getAllMappings()) + { + if (entry.key.toString().equals("minecraft:totem")) //This item changed from 1.11 -> 1.11.2 + { + ResourceLocation newTotem = new ResourceLocation("minecraft:totem_of_undying"); + entry.remap(ForgeRegistries.ITEMS.getValue(newTotem)); + } + } + } + + @net.minecraftforge.eventbus.api.SubscribeEvent + public void playerLogin(PlayerEvent.PlayerLoggedInEvent event) + { + UsernameCache.setUsername(event.player.getPersistentID(), event.player.getGameProfile().getName()); + } + + @Subscribe + public void postInit(FMLPostInitializationEvent evt) + { + ForgeChunkManager.loadConfiguration(); + } + */ + +} diff --git a/src/main/java/net/minecraftforge/common/ForgeModContainer.java b/src/main/java/net/minecraftforge/common/ForgeModContainer.java index 35e597dbb..5e5e8eb7f 100644 --- a/src/main/java/net/minecraftforge/common/ForgeModContainer.java +++ b/src/main/java/net/minecraftforge/common/ForgeModContainer.java @@ -26,32 +26,8 @@ import net.minecraftforge.fml.loading.DefaultModInfos; public class ForgeModContainer extends FMLModContainer { /* - public static final String VERSION_CHECK_CAT = "version_checking"; - public static int clumpingThreshold = 64; - public static boolean removeErroringEntities = false; - public static boolean removeErroringTileEntities = false; - public static boolean fullBoundingBoxLadders = false; - public static double zombieSummonBaseChance = 0.1; - public static int[] blendRanges = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34 }; - public static float zombieBabyChance = 0.05f; - public static boolean shouldSortRecipies = true; - public static boolean disableVersionCheck = false; - public static boolean forgeLightPipelineEnabled = true; - public static boolean selectiveResourceReloadEnabled = false; - @Deprecated // TODO remove in 1.13 - public static boolean replaceVanillaBucketModel = true; - public static boolean zoomInMissingModelTextInGui = false; - public static boolean forgeCloudsEnabled = true; - public static boolean disableStairSlabCulling = false; // Also known as the "DontCullStairsBecauseIUseACrappyTexturePackThatBreaksBasicBlockShapesSoICantTrustBasicBlockCulling" flag - public static boolean alwaysSetupTerrainOffThread = false; // In RenderGlobal.setupTerrain, always force the chunk render updates to be queued to the thread - public static int dimensionUnloadQueueDelay = 0; - public static boolean logCascadingWorldGeneration = true; // see Chunk#logCascadingWorldGeneration() - public static boolean fixVanillaCascading = false; // There are various places in vanilla that cause cascading worldgen. Enabling this WILL change where blocks are placed to prevent this. - // DO NOT contact Forge about worldgen not 'matching' vanilla if this flag is set. - static final Logger log = LogManager.getLogger(ForgeVersion.MOD_ID); - private static Configuration config; private static ForgeModContainer INSTANCE; public static ForgeModContainer getInstance() { @@ -95,205 +71,6 @@ public class ForgeModContainer extends FMLModContainer return "net.minecraftforge.client.gui.ForgeGuiFactory"; } - public static Configuration getConfig() - { - return config; - } - - private static void remapGeneralPropertyToClient(String key) - { - ConfigCategory GENERAL = config.getCategory(CATEGORY_GENERAL); - if (GENERAL.containsKey(key)) - { - LOGGER.debug("Remapping property {} from category general to client", key); - Property property = GENERAL.get(key); - GENERAL.remove(key); - config.getCategory(CATEGORY_CLIENT).put(key, property); - } - } - - /** - * Synchronizes the local fields with the values in the Configuration object. - * / - private static void syncConfig(boolean load) - { - // 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(); - - if (!config.isChild) - { - if (load) - { - config.load(); - } - Property enableGlobalCfg = config.get(Configuration.CATEGORY_GENERAL, "enableGlobalConfig", false).setShowInGui(false); - if (enableGlobalCfg.getBoolean(false)) - { - Configuration.enableGlobalConfig(); - } - } - - Property prop; - - // clean up old properties that are not used anymore - if (config.getCategory(CATEGORY_GENERAL).containsKey("defaultSpawnFuzz")) config.getCategory(CATEGORY_GENERAL).remove("defaultSpawnFuzz"); - if (config.getCategory(CATEGORY_GENERAL).containsKey("spawnHasFuzz")) config.getCategory(CATEGORY_GENERAL).remove("spawnHasFuzz"); - if (config.getCategory(CATEGORY_GENERAL).containsKey("disableStitchedFileSaving")) config.getCategory(CATEGORY_GENERAL).remove("disableStitchedFileSaving"); - if (config.getCategory(CATEGORY_CLIENT).containsKey("java8Reminder")) config.getCategory(CATEGORY_CLIENT).remove("java8Reminder"); - if (config.getCategory(CATEGORY_CLIENT).containsKey("replaceVanillaBucketModel")) config.getCategory(CATEGORY_CLIENT).remove("replaceVanillaBucketModel"); - - // remap properties wrongly listed as general properties to client properties - remapGeneralPropertyToClient("biomeSkyBlendRange"); - remapGeneralPropertyToClient("forgeLightPipelineEnabled"); - - prop = config.get(CATEGORY_GENERAL, "disableVersionCheck", false); - prop.setComment("Set to true to disable Forge's version check mechanics. Forge queries a small json file on our server for version information. For more details see the ForgeVersion class in our github."); - // Language keys are a good idea to implement if you are using config GUIs. This allows you to use a .lang file that will hold the - // "pretty" version of the property name as well as allow others to provide their own localizations. - // This language key is also used to get the tooltip for a property. The tooltip language key is langKey + ".tooltip". - // If no tooltip language key is defined in your .lang file, the tooltip will default to the property comment field. - prop.setLanguageKey("forge.configgui.disableVersionCheck"); - disableVersionCheck = prop.getBoolean(disableVersionCheck); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "clumpingThreshold", 64, - "Controls the number threshold at which Packet51 is preferred over Packet52, default and minimum 64, maximum 1024", 64, 1024); - prop.setLanguageKey("forge.configgui.clumpingThreshold").setRequiresWorldRestart(true); - clumpingThreshold = prop.getInt(64); - if (clumpingThreshold > 1024 || clumpingThreshold < 64) - { - clumpingThreshold = 64; - prop.set(64); - } - propOrder.add(prop.getName()); - - prop = config.get(CATEGORY_GENERAL, "sortRecipies", true); - prop.setComment("Set to true to enable the post initialization sorting of crafting recipes using Forge's sorter. May cause desyncing on conflicting recipes. MUST RESTART MINECRAFT IF CHANGED FROM THE CONFIG GUI."); - prop.setLanguageKey("forge.configgui.sortRecipies").setRequiresMcRestart(true); - shouldSortRecipies = prop.getBoolean(true); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringEntities", false); - prop.setComment("Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES."); - prop.setLanguageKey("forge.configgui.removeErroringEntities").setRequiresWorldRestart(true); - removeErroringEntities = prop.getBoolean(false); - propOrder.add(prop.getName()); - - if (removeErroringEntities) - { - LOGGER.warn("Enabling removal of erroring Entities - USE AT YOUR OWN RISK"); - } - - prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringTileEntities", false); - prop.setComment("Set this to true to remove any TileEntity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES."); - prop.setLanguageKey("forge.configgui.removeErroringTileEntities").setRequiresWorldRestart(true); - removeErroringTileEntities = prop.getBoolean(false); - propOrder.add(prop.getName()); - - if (removeErroringTileEntities) - { - LOGGER.warn("Enabling removal of erroring Tile Entities - USE AT YOUR OWN RISK"); - } - - prop = config.get(Configuration.CATEGORY_GENERAL, "fullBoundingBoxLadders", false); - prop.setComment("Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. Default: false"); - prop.setLanguageKey("forge.configgui.fullBoundingBoxLadders").setRequiresWorldRestart(true); - fullBoundingBoxLadders = prop.getBoolean(false); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "zombieBaseSummonChance", 0.1, - "Base zombie summoning spawn chance. Allows changing the bonus zombie summoning mechanic.", 0.0D, 1.0D); - prop.setLanguageKey("forge.configgui.zombieBaseSummonChance").setRequiresWorldRestart(true); - zombieSummonBaseChance = prop.getDouble(0.1); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "zombieBabyChance", 0.05, - "Chance that a zombie (or subclass) is a baby. Allows changing the zombie spawning mechanic.", 0.0D, 1.0D); - prop.setLanguageKey("forge.configgui.zombieBabyChance").setRequiresWorldRestart(true); - zombieBabyChance = (float) prop.getDouble(0.05); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "logCascadingWorldGeneration", true, - "Log cascading chunk generation issues during terrain population."); - logCascadingWorldGeneration = prop.getBoolean(); - prop.setLanguageKey("forge.configgui.logCascadingWorldGeneration"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "fixVanillaCascading", false, - "Fix vanilla issues that cause worldgen cascading. This DOES change vanilla worldgen so DO NOT report bugs related to world differences if this flag is on."); - fixVanillaCascading = prop.getBoolean(); - prop.setLanguageKey("forge.configgui.fixVanillaCascading"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_GENERAL, "dimensionUnloadQueueDelay", 0, - "The time in ticks the server will wait when a dimension was queued to unload. " + - "This can be useful when rapidly loading and unloading dimensions, like e.g. throwing items through a nether portal a few time per second."); - dimensionUnloadQueueDelay = prop.getInt(0); - prop.setLanguageKey("forge.configgui.dimensionUnloadQueueDelay"); - propOrder.add(prop.getName()); - - config.setCategoryPropertyOrder(CATEGORY_GENERAL, propOrder); - - propOrder = new ArrayList(); - prop = config.get(VERSION_CHECK_CAT, "Global", true, "Enable the entire mod update check system. This only applies to mods using the Forge system."); - propOrder.add("Global"); - - config.setCategoryPropertyOrder(VERSION_CHECK_CAT, propOrder); - - // Client-Side only properties - propOrder = new ArrayList(); - - prop = config.get(Configuration.CATEGORY_CLIENT, "zoomInMissingModelTextInGui", false, - "Toggle off to make missing model text in the gui fit inside the slot."); - zoomInMissingModelTextInGui = prop.getBoolean(false); - prop.setLanguageKey("forge.configgui.zoomInMissingModelTextInGui"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "forgeCloudsEnabled", true, - "Enable uploading cloud geometry to the GPU for faster rendering."); - prop.setLanguageKey("forge.configgui.forgeCloudsEnabled"); - forgeCloudsEnabled = prop.getBoolean(); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "disableStairSlabCulling", false, - "Disable culling of hidden faces next to stairs and slabs. Causes extra rendering, but may fix some resource packs that exploit this vanilla mechanic."); - disableStairSlabCulling = prop.getBoolean(false); - prop.setLanguageKey("forge.configgui.disableStairSlabCulling"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "alwaysSetupTerrainOffThread", false, - "Enable forge to queue all chunk updates to the Chunk Update thread. May increase FPS significantly, but may also cause weird rendering lag. Not recommended for computers " + - "without a significant number of cores available."); - alwaysSetupTerrainOffThread = prop.getBoolean(false); - prop.setLanguageKey("forge.configgui.alwaysSetupTerrainOffThread"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "biomeSkyBlendRange", new int[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34 }); - prop.setComment("Control the range of sky blending for colored skies in biomes."); - prop.setLanguageKey("forge.configgui.biomeSkyBlendRange"); - blendRanges = prop.getIntList(); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "forgeLightPipelineEnabled", true, - "Enable the forge block rendering pipeline - fixes the lighting of custom models."); - forgeLightPipelineEnabled = prop.getBoolean(true); - prop.setLanguageKey("forge.configgui.forgeLightPipelineEnabled"); - propOrder.add(prop.getName()); - - prop = config.get(Configuration.CATEGORY_CLIENT, "selectiveResourceReloadEnabled", false, - "When enabled, makes specific reload tasks such as language changing quicker to run."); - selectiveResourceReloadEnabled = prop.getBoolean(false); - prop.setLanguageKey("forge.configgui.selectiveResourceReloadEnabled"); - propOrder.add(prop.getName()); - - config.setCategoryPropertyOrder(CATEGORY_CLIENT, propOrder); - - if (config.hasChanged()) - { - config.save(); - } - } /** * By subscribing to the OnConfigChangedEvent we are able to execute code when our config screens are closed. @@ -570,6 +347,7 @@ public class ForgeModContainer extends FMLModContainer public ForgeModContainer(ModLoadingClassLoader classLoader) { super(DefaultModInfos.forgeModInfo, "net.minecraftforge.common.ForgeMod", classLoader, null); + ForgeConfig.load(); } } diff --git a/src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java b/src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java new file mode 100644 index 000000000..4b4786291 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/config/ForgeConfigSpec.java @@ -0,0 +1,452 @@ +/* + * 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 com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.ADD; +import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.REMOVE; +import static com.electronwill.nightconfig.core.ConfigSpec.CorrectionAction.REPLACE; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; + +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.InMemoryFormat; +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; + +/* + * Like {@link com.electronwill.nightconfig.core.ConfigSpec} except in builder format, and extended to acept comments, language keys, + * and other things Forge configs would find useful. + */ + +public class ForgeConfigSpec +{ + private final Config storage; + private ForgeConfigSpec(Config storage) + { + this.storage = storage; + } + + public boolean isCorrect(CommentedConfig config) { + return correct(storage, config, null, null, null, true) == 0; + } + + public int correct(CommentedConfig config) { + return correct(config, (action, path, incorrectValue, correctedValue) -> {}); + } + public int correct(CommentedConfig config, CorrectionListener listener) { + LinkedList parentPath = new LinkedList<>(); //Linked list for fast add/removes + return correct(storage, config, parentPath, Collections.unmodifiableList(parentPath), listener, false); + } + + private int correct(Config spec, CommentedConfig config, LinkedList parentPath, List parentPathUnmodifiable, CorrectionListener listener, boolean dryRun) + { + int count = 0; + + Map specMap = spec.valueMap(); + Map configMap = config.valueMap(); + + for (Map.Entry specEntry : specMap.entrySet()) + { + final String key = specEntry.getKey(); + final Object specValue = specEntry.getValue(); + final Object configValue = configMap.get(key); + final CorrectionAction action = configValue == null ? ADD : REPLACE; + + if (!dryRun) + parentPath.addLast(key); + + if (specValue instanceof Config) + { + if (configValue instanceof CommentedConfig) + { + count += correct((Config)specValue, (CommentedConfig)configValue, parentPath, parentPathUnmodifiable, listener, dryRun); + if (count > 0 && dryRun) + return count; + } + else if (dryRun) + { + return 1; + } + else + { + CommentedConfig newValue = config.createSubConfig(); + configMap.put(key, newValue); + listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue); + count++; + } + } + else + { + ValueSpec valueSpec = (ValueSpec)specValue; + if (!valueSpec.test(configValue)) + { + if (dryRun) + return 1; + + Object newValue = valueSpec.getDefault(); + configMap.put(key, newValue); + listener.onCorrect(action, parentPathUnmodifiable, configValue, newValue); + count++; + } + String oldComment = config.getComment(key); + if (!Objects.equals(oldComment, valueSpec.getComment())) + { + if (dryRun) + return 1; + + //TODO: Comment correction listener? + config.setComment(key, valueSpec.getComment()); + } + } + if (!dryRun) + parentPath.removeLast(); + } + + // Second step: removes the unspecified values + for (Iterator> ittr = configMap.entrySet().iterator(); ittr.hasNext();) + { + Map.Entry entry = ittr.next(); + if (!specMap.containsKey(entry.getKey())) + { + if (dryRun) + return 1; + + ittr.remove(); + parentPath.addLast(entry.getKey()); + listener.onCorrect(REMOVE, parentPathUnmodifiable, entry.getValue(), null); + parentPath.removeLast(); + count++; + } + } + return count; + } + + public static class Builder + { + private final Config storage = InMemoryFormat.withUniversalSupport().createConfig(); + private BuilderContext context = new BuilderContext(); + + //Object + public Builder define(String path, Object defaultValue) { + return define(split(path), defaultValue); + } + public Builder define(List path, Object defaultValue) { + return define(path, defaultValue, o -> o != null && defaultValue.getClass().isAssignableFrom(o.getClass())); + } + public Builder define(String path, Object defaultValue, Predicate validator) { + return define(split(path), defaultValue, validator); + } + public Builder define(List path, Object defaultValue, Predicate validator) { + Objects.requireNonNull(defaultValue, "Default value can not be null"); + return define(path, () -> defaultValue, validator); + } + public Builder define(String path, Supplier defaultSupplier, Predicate validator) { + return define(split(path), defaultSupplier, validator); + } + public Builder define(List path, Supplier defaultSupplier, Predicate validator) { + return define(path, defaultSupplier, validator, Object.class); + } + public Builder define(List path, Supplier defaultSupplier, Predicate validator, Class clazz) { // This is the root where everything at the end of the day ends up. + context.setClazz(clazz); + storage.set(path, new ValueSpec(defaultSupplier, validator, context)); + context = new BuilderContext(); + return this; + } + public > Builder defineInRange(String path, V defaultValue, V min, V max, Class clazz) { + return defineInRange(split(path), defaultValue, min, max, clazz); + } + public > Builder defineInRange(List path, V defaultValue, V min, V max, Class clazz) { + return defineInRange(path, (Supplier)() -> defaultValue, min, max, clazz); + } + 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) + { + Range range = new Range<>(clazz, min, max); + context.setRange(range); + if (min.compareTo(max) > 0) + throw new IllegalArgumentException("Range min most be less then max."); + define(path, defaultSupplier, range); + return this; + } + public void defineInList(String path, Object defaultValue, Collection acceptableValues) { + defineInList(split(path), defaultValue, acceptableValues); + } + public void defineInList(String path, Supplier defaultSupplier, Collection acceptableValues) { + defineInList(split(path), defaultSupplier, acceptableValues); + } + public void defineInList(List path, Object defaultValue, Collection acceptableValues) { + defineInList(path, () -> defaultValue, acceptableValues); + } + public void defineInList(List path, Supplier defaultSupplier, Collection acceptableValues) { + define(path, defaultSupplier, acceptableValues::contains); + } + + //Enum + public > Builder defineEnum(String path, V defaultValue) { + return defineEnum(split(path), defaultValue); + } + public > Builder defineEnum(List path, V defaultValue) { + return defineEnum(path, defaultValue, defaultValue.getDeclaringClass().getEnumConstants()); + } + public > Builder defineEnum(String path, V defaultValue, @SuppressWarnings("unchecked") V... acceptableValues) { + return defineEnum(split(path), defaultValue, acceptableValues); + } + public > Builder defineEnum(List path, V defaultValue, @SuppressWarnings("unchecked") V... acceptableValues) { + return defineEnum(path, defaultValue, Arrays.asList(acceptableValues)); + } + public > Builder defineEnum(String path, V defaultValue, Collection acceptableValues) { + return defineEnum(split(path), defaultValue, acceptableValues); + } + public > Builder defineEnum(List path, V defaultValue, Collection acceptableValues) { + return defineEnum(path, defaultValue, acceptableValues::contains); + } + public > Builder defineEnum(String path, V defaultValue, Predicate validator) { + return defineEnum(split(path), defaultValue, validator); + } + public > Builder defineEnum(List path, V defaultValue, Predicate validator) { + return defineEnum(path, () -> defaultValue, validator, defaultValue.getDeclaringClass()); + } + public > Builder defineEnum(String path, Supplier defaultSupplier, Predicate validator, Class clazz) { + return defineEnum(split(path), defaultSupplier, validator, clazz); + } + public > Builder defineEnum(List path, Supplier defaultSupplier, Predicate validator, Class clazz) { + return define(path, defaultSupplier, validator, clazz); + } + + + //boolean + public Builder define(String path, boolean defaultValue) { + return define(split(path), defaultValue); + } + public Builder define(List path, boolean defaultValue) { + return define(path, (Supplier)() -> defaultValue); + } + public Builder define(String path, Supplier defaultSupplier) { + return define(split(path), defaultSupplier); + } + public Builder define(List path, Supplier defaultSupplier) { + return define(path, defaultSupplier, o -> { + if (o instanceof String) return ((String)o).equalsIgnoreCase("true") || ((String)o).equalsIgnoreCase("false"); + return o instanceof Boolean; + }, Boolean.class); + } + + //Double + public Builder defineInRange(String path, double defaultValue, double min, double max) { + return defineInRange(split(path), defaultValue, min, max); + } + public Builder defineInRange(List path, double defaultValue, double min, double max) { + return defineInRange(path, (Supplier)() -> defaultValue, min, max); + } + public Builder defineInRange(String path, Supplier defaultSupplier, double min, double max) { + return defineInRange(split(path), defaultSupplier, min, max); + } + public Builder defineInRange(List path, Supplier defaultSupplier, double min, double max) { + return defineInRange(path, defaultSupplier, min, max, Double.class); + } + //Ints + public Builder defineInRange(String path, int defaultValue, int min, int max) { + return defineInRange(split(path), defaultValue, min, max); + } + public Builder defineInRange(List path, int defaultValue, int min, int max) { + return defineInRange(path, (Supplier)() -> defaultValue, min, max); + } + public Builder defineInRange(String path, Supplier defaultSupplier, int min, int max) { + return defineInRange(split(path), defaultSupplier, min, max); + } + public Builder defineInRange(List path, Supplier defaultSupplier, int min, int max) { + return defineInRange(path, defaultSupplier, min, max, Integer.class); + } + //Longs + public Builder defineInRange(String path, long defaultValue, long min, long max) { + return defineInRange(split(path), defaultValue, min, max); + } + public Builder defineInRange(List path, long defaultValue, long min, long max) { + return defineInRange(path, (Supplier)() -> defaultValue, min, max); + } + public Builder defineInRange(String path, Supplier defaultSupplier, long min, long max) { + return defineInRange(split(path), defaultSupplier, min, max); + } + public Builder defineInRange(List path, Supplier defaultSupplier, long min, long max) { + return defineInRange(path, defaultSupplier, min, max, Long.class); + } + + public Builder comment(String comment) + { + context.setComment(comment); + return this; + } + public Builder comment(String... comment) + { + context.setComment(comment); + return this; + } + + public Builder translation(String translationKey) + { + context.setTranslationKey(translationKey); + return this; + } + + public Builder worldRestart() + { + context.worldRestart(); + return this; + } + + public ForgeConfigSpec build() + { + context.ensureEmpty(); + return new ForgeConfigSpec(storage); + } + } + + private static class BuilderContext + { + private String[] comment; + private String langKey; + private Range range; + private boolean worldRestart = false; + private Class clazz; + + public void setComment(String... value) { this.comment = value; } + public String[] getComment() { return this.comment; } + public void setTranslationKey(String value) { this.langKey = value; } + public String getTranslationKey() { return this.langKey; } + public > void setRange(Range value) + { + this.range = value; + this.setClazz(value.getClazz()); + } + @SuppressWarnings("unchecked") + public > Range getRange() { return (Range)this.range; } + public void worldRestart() { this.worldRestart = true; } + public boolean needsWorldRestart() { return this.worldRestart; } + public void setClazz(Class clazz) { this.clazz = clazz; } + public Class getClazz(){ return this.clazz; } + + public void ensureEmpty() + { + validate(comment, "Non-null comment when null expected"); + validate(langKey, "Non-null translation key when null expected"); + validate(range, "Non-null range when null expected"); + validate(worldRestart, "Dangeling world restart value set to true"); + } + + private void validate(Object value, String message) + { + if (value != null) + throw new IllegalStateException(message); + } + private void validate(boolean value, String message) + { + if (value) + throw new IllegalStateException(message); + } + } + + @SuppressWarnings("unused") + private static class Range> implements Predicate + { + private final Class clazz; + private final V min; + private final V max; + + private Range(Class clazz, V min, V max) + { + this.clazz = clazz; + this.min = min; + this.max = max; + } + + public Class getClazz() { return clazz; } + public V getMin() { return min; } + public V getMax() { return max; } + + @Override + public boolean test(Object t) + { + if (!clazz.isInstance(t)) return false; + V c = clazz.cast(t); + return c.compareTo(min) >= 0 && c.compareTo(max) <= 0; + } + } + + public static class ValueSpec + { + private final String comment; + private final String langKey; + private final Range range; + private final boolean worldRestart; + private final Class clazz; + private final Supplier supplier; + private final Predicate validator; + private Object _default = null; + + private ValueSpec(Supplier supplier, Predicate validator, BuilderContext context) + { + Objects.requireNonNull(supplier, "Default supplier can not be null"); + Objects.requireNonNull(validator, "Validator can not be null"); + + this.comment = Joiner.on("\n").join(context.getComment()); + this.langKey = context.getTranslationKey(); + this.range = context.getRange(); + this.worldRestart = context.needsWorldRestart(); + this.clazz = context.getClazz(); + this.supplier = supplier; + this.validator = validator; + } + + public String getComment() { return comment; } + public String getTranslationKey() { return langKey; } + @SuppressWarnings("unchecked") + public > Range getRange() { return (Range)this.range; } + public boolean needsWorldRestart() { return this.worldRestart; } + public Class getClazz(){ return this.clazz; } + public boolean test(Object value) { return validator.test(value); } + + public Object getDefault() + { + if (_default == null) + _default = supplier.get(); + return _default; + } + } + + private static final Splitter DOT_SPLITTER = Splitter.on("."); + private static List split(String path) + { + return Lists.newArrayList(DOT_SPLITTER.split(path)); + } +} diff --git a/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java b/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java index a4faa6214..6f76ff095 100644 --- a/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java +++ b/src/main/java/net/minecraftforge/common/crafting/CompoundIngredient.java @@ -46,11 +46,11 @@ public class CompoundIngredient extends Ingredient private IntList itemIds; private final boolean isSimple; - protected CompoundIngredient(Stream children) + protected CompoundIngredient(Collection children) { super(Stream.of()); - this.isSimple = children.allMatch(Ingredient::isSimple); - this.children = children.collect(Collectors.toList()); + this.children = children; + this.isSimple = children.stream().allMatch(Ingredient::isSimple); } @Override @@ -118,7 +118,7 @@ public class CompoundIngredient extends Ingredient @Override public CompoundIngredient parse(PacketBuffer buffer) { - return new CompoundIngredient(Stream.generate(() -> Ingredient.func_199566_b(buffer)).limit(buffer.readVarInt())); + return new CompoundIngredient(Stream.generate(() -> Ingredient.func_199566_b(buffer)).limit(buffer.readVarInt()).collect(Collectors.toList())); } @Override diff --git a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java index 306645dcb..25a6aa079 100644 --- a/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java +++ b/src/main/java/net/minecraftforge/common/crafting/CraftingHelper.java @@ -199,7 +199,7 @@ public class CraftingHelper if (ingredients.size() == 1) return ingredients.get(0); - return new CompoundIngredient(ingredients.stream()); + return new CompoundIngredient(ingredients); } if (!json.isJsonObject()) diff --git a/src/main/resources/assets/forge/lang/en_us.json b/src/main/resources/assets/forge/lang/en_us.json index f9ff6cc80..e48c70a00 100644 --- a/src/main/resources/assets/forge/lang/en_us.json +++ b/src/main/resources/assets/forge/lang/en_us.json @@ -7,7 +7,7 @@ "fml.menu.mods.config": "Config", "fml.menu.modoptions": "Mod Options...", "fml.menu.loadingmods": "{0,choice,0#No mods|1#1 mod|1<{0} mods} loaded", - + "commands.forge.dimensions.list": "Currently registered dimensions by type:", "commands.forge.entity.list.invalid": "Invalid filter, does not match any entities. Use /forge entity list for a proper list", "commands.forge.entity.list.invalidworld": "Could not load world for dimension {0}. Please select a valid dimension.", @@ -32,5 +32,38 @@ "commands.forge.tracking.te.enabled": "Tile Entity tracking enabled for %d seconds.", "commands.forge.tracking.te.reset": "Tile entity timings data has been cleared!", "commands.forge.tracking.timing_entry": "{0} - {1} [{2}, {3}, {4}]: {5}", - "commands.forge.tracking.no_data": "No data has been recorded yet." + "commands.forge.tracking.no_data": "No data has been recorded yet.", + + + "forge.configgui.clumpingThreshold.tooltip": "Controls the number threshold at which Packet51 is preferred over Packet52.", + "forge.configgui.clumpingThreshold": "Packet Clumping Threshold", + "forge.configgui.disableVersionCheck.tooltip": "Set to true to disable Forge's version check mechanics. Forge queries a small json file on our server for version information. For more details see the ForgeVersion class in our github.", + "forge.configgui.disableVersionCheck": "Disable Forge Version Check", + "forge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.", + "forge.configgui.removeErroringEntities": "Remove Erroring Entities", + "forge.configgui.removeErroringTileEntities.tooltip": "Set this to true to remove any TileEntity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.", + "forge.configgui.removeErroringTileEntities": "Remove Erroring Tile Entities", + "forge.configgui.fullBoundingBoxLadders.tooltip": "Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior.", + "forge.configgui.fullBoundingBoxLadders": "Full Bounding Box Ladders", + "forge.configgui.zombieBaseSummonChance.tooltip": "Base zombie summoning spawn chance. Allows changing the bonus zombie summoning mechanic.", + "forge.configgui.zombieBaseSummonChance": "Zombie Summon Chance", + "forge.configgui.zombieBabyChance.tooltip": "Chance that a zombie (or subclass) is a baby. Allows changing the zombie spawning mechanic.", + "forge.configgui.zombieBabyChance": "Zombie Baby Chance", + "forge.configgui.logCascadingWorldGeneration.tooltip": "Log cascading chunk generation issues during terrain population.", + "forge.configgui.logCascadingWorldGeneration": "Log Cascading World Gen", + "forge.configgui.fixVanillaCascading.tooltip": "Fix various bugs in vanilla world gen that causes extra chunks to load. This WILL change your worldgen from vanilla. Do not report differences if this is enabled.", + "forge.configgui.fixVanillaCascading": "Fix Vanilla Cascading", + "forge.configgui.dimensionUnloadQueueDelay.tooltip": "The time in ticks the server will wait until unloading a dimension. This can be useful when rapidly loading and unloading dimensions, like e.g. throwing items through a nether portal a few time per second.", + "forge.configgui.dimensionUnloadQueueDelay": "Delay when unloading dimension", + "forge.configgui.zoomInMissingModelTextInGui": "Zoom in Missing model text in the GUI", + "forge.configgui.forgeCloudsEnabled.tooltip": "Enable uploading cloud geometry to the GPU for faster rendering.", + "forge.configgui.forgeCloudsEnabled": "Use Forge's cloud renderer", + "forge.configgui.disableStairSlabCulling.tooltip": "Enable this if you see through blocks touching stairs/slabs with your resource pack.", + "forge.configgui.disableStairSlabCulling": "Disable Stair/Slab culling.", + "forge.configgui.alwaysSetupTerrainOffThread.tooltip": "Enable forge to queue all chunk updates to the Chunk Update thread. May increase FPS significantly, but may also cause weird rendering lag. Not recommended for computers without a significant number of cores available.", + "forge.configgui.alwaysSetupTerrainOffThread": "Force threaded chunk rendering", + "forge.configgui.forgeLightPipelineEnabled": "Forge Light Pipeline Enabled", + "forge.configgui.selectiveResourceReloadEnabled.tooltip": "When enabled, makes specific reload tasks such as language changing quicker to run.", + "forge.configgui.selectiveResourceReloadEnabled": "Enable Selective Resource Loading" + } diff --git a/src/main/resources/assets/forge/lang/en_us.lang b/src/main/resources/assets/forge/lang/en_us.lang index 667f042eb..7dd5c9752 100644 --- a/src/main/resources/assets/forge/lang/en_us.lang +++ b/src/main/resources/assets/forge/lang/en_us.lang @@ -1,40 +1,3 @@ -commands.forge.usage=Use /forge -commands.forge.usage.tracking=Use /forge track . Valid types are "te" (Tile Entities). Duration in seconds must be <= 60. -commands.forge.usage.help=Use help [command] to view usages for that command. -commands.forge.tps.summary=%s : Mean tick time: %d ms. Mean TPS: %d -commands.forge.tps.usage=Use /forge tps [dimension] -commands.forge.gen.usage=Use /forge gen [dimension] [interval] -commands.forge.gen.dim_fail=Failed to load world for dimension %d, Task terminated. -commands.forge.gen.progress=Generation Progress: %d/%d -commands.forge.gen.complete=Finished generating %d new chunks (out of %d) for dimension %d. -commands.forge.gen.start=Starting to generate %d chunks in a spiral around %d, %d in dimension %d. -commands.forge.entity.usage=Use /forge entity help for more information on entity subcommands. -commands.forge.entity.list.usage=Use /forge entity list [filter] [dim] to get entity info that matches the optional filter. -commands.forge.entity.list.invalid=Invalid filter, does not match any entities. Use /forge entity list for a proper list -commands.forge.entity.list.invalidworld=Could not load world for dimension %d. Please select a valid dimension. -commands.forge.entity.list.none=No entities found. -commands.forge.entity.list.single.header=Entity: %s Total: %d -commands.forge.entity.list.multiple.header=Total: %d -commands.forge.setdim.usage=Use /forge setdim [ ] -commands.forge.setdim.invalid.entity=The entity selected (%s) is not valid. -commands.forge.setdim.invalid.dim=The dimension ID specified (%d) is not valid. -commands.forge.setdim.invalid.nochange=The entity selected (%s) is already in the dimension specified (%d). -commands.forge.dimensions.usage=Use /forge dimensions -commands.forge.dimensions.list=Currently registered dimensions by type: - -commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds. -commands.forge.tracking.entity.enabled=Entity tracking enabled for %d seconds. -commands.forge.tracking.usage=Use /forge track help for more information on tracking subcommands. -commands.forge.tracking.start.usage=Use /forge track start -commands.forge.tracking.reset.usage=Use /forge track reset -commands.forge.tracking.reset=Timings data has been cleared! -commands.forge.tracking.te.usage=Use /forge track te - -commands.forge.tracking.timingEntry=%s - %s [%d, %d, %d]: %s -commands.forge.tracking.noData=No data has been recorded yet. -commands.tree_base.invalid_cmd=Invalid subcommand '%s'! -commands.tree_base.invalid_cmd.list_subcommands=Invalid subcommand '%s'! Available subcommands: %s -commands.tree_base.available_subcommands=Available SubCommands: %s forge.texture.preload.warning=Warning: Texture %s not preloaded, will cause render glitches! forge.client.shutdown.internal=Shutting down internal server... forge.update.newversion=New Forge version available: %s @@ -56,39 +19,11 @@ forge.configgui.ctgy.VersionCheckConfig=Version Check Settings forge.configgui.biomeSkyBlendRange.tooltip=Control the range of sky blending for colored skies in biomes. forge.configgui.biomeSkyBlendRange=Biome Sky Blend Range -forge.configgui.clumpingThreshold.tooltip=Controls the number threshold at which Packet51 is preferred over Packet52. -forge.configgui.clumpingThreshold=Packet Clumping Threshold -forge.configgui.disableVersionCheck.tooltip=Set to true to disable Forge's version check mechanics. Forge queries a small json file on our server for version information. For more details see the ForgeVersion class in our github. -forge.configgui.disableVersionCheck=Disable Forge Version Check -forge.configgui.dimensionUnloadQueueDelay=Delay when unloading dimension -forge.configgui.dimensionUnloadQueueDelay.tooltip=The time in ticks the server will wait until unloading a dimension. This can be useful when rapidly loading and unloading dimensions, like e.g. throwing items through a nether portal a few time per second. -forge.configgui.enableGlobalConfig=Enable Global Config forge.configgui.forceDuplicateFluidBlockCrash.tooltip=Set this to true to force a crash if more than one block attempts to link back to the same Fluid. forge.configgui.forceDuplicateFluidBlockCrash=Force Dupe Fluid Block Crash -forge.configgui.fullBoundingBoxLadders.tooltip=Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. -forge.configgui.fullBoundingBoxLadders=Full Bounding Box Ladders -forge.configgui.removeErroringEntities.tooltip=Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES. -forge.configgui.removeErroringEntities=Remove Erroring Entities -forge.configgui.removeErroringTileEntities.tooltip=Set this to true to remove any TileEntity that throws an error in its update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES. -forge.configgui.removeErroringTileEntities=Remove Erroring Tile Entities -forge.configgui.sortRecipies.tooltip=Set to true to enable the post initialization sorting of crafting recipes using Forge's sorter. May cause desyncing on conflicting recipies. MUST RESTART MINECRAFT IF CHANGED FROM THE CONFIG GUI. -forge.configgui.sortRecipies=Sort Recipes -forge.configgui.zombieBabyChance.tooltip=Chance that a zombie (or subclass) is a baby. Allows changing the zombie spawning mechanic. -forge.configgui.zombieBabyChance=Zombie Baby Chance -forge.configgui.zombieBaseSummonChance.tooltip=Base zombie summoning spawn chance. Allows changing the bonus zombie summoning mechanic. -forge.configgui.zombieBaseSummonChance=Zombie Summon Chance + forge.configgui.stencilbits=Enable GL Stencil Bits forge.configgui.replaceBuckets=Use Forge's bucket model -forge.configgui.forgeCloudsEnabled=Use Forge's cloud renderer -forge.configgui.forgeCloudsEnabled.tooltip=Enable uploading cloud geometry to the GPU for faster rendering. -forge.configgui.forgeLightPipelineEnabled=Forge Light Pipeline Enabled -forge.configgui.disableStairSlabCulling=Disable Stair/Slab culling. -forge.configgui.zoomInMissingModelTextInGui=Zoom in Missing model text in the GUI -forge.configgui.disableStairSlabCulling.tooltip=Enable this if you see through blocks touching stairs/slabs with your resource pack. -forge.configgui.alwaysSetupTerrainOffThread=Force threaded chunk rendering -forge.configgui.alwaysSetupTerrainOffThread.tooltip=Enable forge to queue all chunk updates to the Chunk Update thread. May increase FPS significantly, but may also cause weird rendering lag. Not recommended for computers without a significant number of cores available. -forge.configgui.selectiveResourceReloadEnabled=Enable Selective Resource Loading -forge.configgui.selectiveResourceReloadEnabled.tooltip=When enabled, makes specific reload tasks such as language changing quicker to run. forge.configgui.modID.tooltip=The mod ID that you want to define override settings for. forge.configgui.modID=Mod ID @@ -104,10 +39,6 @@ forge.configgui.maximumTicketCount.tooltip=This is the number of chunk loading r forge.configgui.maximumTicketCount=Mod Ticket Limit forge.configgui.playerTicketCount.tooltip=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. forge.configgui.playerTicketCount=Player Ticket Limit -forge.configgui.logCascadingWorldGeneration=Log Cascading World Gen -forge.configgui.logCascadingWorldGeneration.tooltip=Log cascading chunk generation issues during terrain population. -forge.configgui.fixVanillaCascading=Fix Vanilla Cascading -forge.configgui.fixVanillaCascading.tooltip=Fix various bugs in vanilla world gen that causes extra chunks to load. This WILL change your worldgen from vanilla. Do not report differences if this is enabled. fml.config.sample.basicDouble.tooltip=A double property with no defined bounds. fml.config.sample.basicDouble=Unbounded Double