Beginning work on redesigning Config API.

This commit is contained in:
LexManos 2018-09-17 20:40:42 -07:00
parent 02c31cc867
commit 6814cbf0df
7 changed files with 719 additions and 300 deletions

View File

@ -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<Item> event)
{
for (MissingMappings.Mapping<Item> 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();
}
*/
}

View File

@ -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<String> propOrder = new ArrayList<String>();
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<String>();
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<String>();
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();
}
}

View File

@ -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<String> 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<String> parentPath, List<String> parentPathUnmodifiable, CorrectionListener listener, boolean dryRun)
{
int count = 0;
Map<String, Object> specMap = spec.valueMap();
Map<String, Object> configMap = config.valueMap();
for (Map.Entry<String, Object> 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<Map.Entry<String, Object>> ittr = configMap.entrySet().iterator(); ittr.hasNext();)
{
Map.Entry<String, Object> 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<String> path, Object defaultValue) {
return define(path, defaultValue, o -> o != null && defaultValue.getClass().isAssignableFrom(o.getClass()));
}
public Builder define(String path, Object defaultValue, Predicate<Object> validator) {
return define(split(path), defaultValue, validator);
}
public Builder define(List<String> path, Object defaultValue, Predicate<Object> validator) {
Objects.requireNonNull(defaultValue, "Default value can not be null");
return define(path, () -> defaultValue, validator);
}
public Builder define(String path, Supplier<?> defaultSupplier, Predicate<Object> validator) {
return define(split(path), defaultSupplier, validator);
}
public Builder define(List<String> path, Supplier<?> defaultSupplier, Predicate<Object> validator) {
return define(path, defaultSupplier, validator, Object.class);
}
public Builder define(List<String> path, Supplier<?> defaultSupplier, Predicate<Object> 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 <V extends Comparable<? super V>> Builder defineInRange(String path, V defaultValue, V min, V max, Class<V> clazz) {
return defineInRange(split(path), defaultValue, min, max, clazz);
}
public <V extends Comparable<? super V>> Builder defineInRange(List<String> path, V defaultValue, V min, V max, Class<V> clazz) {
return defineInRange(path, (Supplier<V>)() -> defaultValue, min, max, clazz);
}
public <V extends Comparable<? super V>> Builder defineInRange(String path, Supplier<V> defaultSupplier, V min, V max, Class<V> clazz) {
return defineInRange(split(path), defaultSupplier, min, max, clazz);
}
public <V extends Comparable<? super V>> Builder defineInRange(List<String> path, Supplier<V> defaultSupplier, V min, V max, Class<V> clazz)
{
Range<V> 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<String> path, Object defaultValue, Collection<?> acceptableValues) {
defineInList(path, () -> defaultValue, acceptableValues);
}
public void defineInList(List<String> path, Supplier<?> defaultSupplier, Collection<?> acceptableValues) {
define(path, defaultSupplier, acceptableValues::contains);
}
//Enum
public <V extends Enum<V>> Builder defineEnum(String path, V defaultValue) {
return defineEnum(split(path), defaultValue);
}
public <V extends Enum<V>> Builder defineEnum(List<String> path, V defaultValue) {
return defineEnum(path, defaultValue, defaultValue.getDeclaringClass().getEnumConstants());
}
public <V extends Enum<V>> Builder defineEnum(String path, V defaultValue, @SuppressWarnings("unchecked") V... acceptableValues) {
return defineEnum(split(path), defaultValue, acceptableValues);
}
public <V extends Enum<V>> Builder defineEnum(List<String> path, V defaultValue, @SuppressWarnings("unchecked") V... acceptableValues) {
return defineEnum(path, defaultValue, Arrays.asList(acceptableValues));
}
public <V extends Enum<V>> Builder defineEnum(String path, V defaultValue, Collection<V> acceptableValues) {
return defineEnum(split(path), defaultValue, acceptableValues);
}
public <V extends Enum<V>> Builder defineEnum(List<String> path, V defaultValue, Collection<V> acceptableValues) {
return defineEnum(path, defaultValue, acceptableValues::contains);
}
public <V extends Enum<V>> Builder defineEnum(String path, V defaultValue, Predicate<Object> validator) {
return defineEnum(split(path), defaultValue, validator);
}
public <V extends Enum<V>> Builder defineEnum(List<String> path, V defaultValue, Predicate<Object> validator) {
return defineEnum(path, () -> defaultValue, validator, defaultValue.getDeclaringClass());
}
public <V extends Enum<V>> Builder defineEnum(String path, Supplier<V> defaultSupplier, Predicate<Object> validator, Class<V> clazz) {
return defineEnum(split(path), defaultSupplier, validator, clazz);
}
public <V extends Enum<V>> Builder defineEnum(List<String> path, Supplier<V> defaultSupplier, Predicate<Object> validator, Class<V> clazz) {
return define(path, defaultSupplier, validator, clazz);
}
//boolean
public Builder define(String path, boolean defaultValue) {
return define(split(path), defaultValue);
}
public Builder define(List<String> path, boolean defaultValue) {
return define(path, (Supplier<Boolean>)() -> defaultValue);
}
public Builder define(String path, Supplier<Boolean> defaultSupplier) {
return define(split(path), defaultSupplier);
}
public Builder define(List<String> path, Supplier<Boolean> 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<String> path, double defaultValue, double min, double max) {
return defineInRange(path, (Supplier<Double>)() -> defaultValue, min, max);
}
public Builder defineInRange(String path, Supplier<Double> defaultSupplier, double min, double max) {
return defineInRange(split(path), defaultSupplier, min, max);
}
public Builder defineInRange(List<String> path, Supplier<Double> 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<String> path, int defaultValue, int min, int max) {
return defineInRange(path, (Supplier<Integer>)() -> defaultValue, min, max);
}
public Builder defineInRange(String path, Supplier<Integer> defaultSupplier, int min, int max) {
return defineInRange(split(path), defaultSupplier, min, max);
}
public Builder defineInRange(List<String> path, Supplier<Integer> 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<String> path, long defaultValue, long min, long max) {
return defineInRange(path, (Supplier<Long>)() -> defaultValue, min, max);
}
public Builder defineInRange(String path, Supplier<Long> defaultSupplier, long min, long max) {
return defineInRange(split(path), defaultSupplier, min, max);
}
public Builder defineInRange(List<String> path, Supplier<Long> 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 <V extends Comparable<? super V>> void setRange(Range<V> value)
{
this.range = value;
this.setClazz(value.getClazz());
}
@SuppressWarnings("unchecked")
public <V extends Comparable<? super V>> Range<V> getRange() { return (Range<V>)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<V extends Comparable<? super V>> implements Predicate<Object>
{
private final Class<V> clazz;
private final V min;
private final V max;
private Range(Class<V> clazz, V min, V max)
{
this.clazz = clazz;
this.min = min;
this.max = max;
}
public Class<V> 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<Object> validator;
private Object _default = null;
private ValueSpec(Supplier<?> supplier, Predicate<Object> 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 <V extends Comparable<? super V>> Range<V> getRange() { return (Range<V>)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<String> split(String path)
{
return Lists.newArrayList(DOT_SPLITTER.split(path));
}
}

View File

@ -46,11 +46,11 @@ public class CompoundIngredient extends Ingredient
private IntList itemIds;
private final boolean isSimple;
protected CompoundIngredient(Stream<Ingredient> children)
protected CompoundIngredient(Collection<Ingredient> 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

View File

@ -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())

View File

@ -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"
}

View File

@ -1,40 +1,3 @@
commands.forge.usage=Use /forge <subcommand>
commands.forge.usage.tracking=Use /forge track <type> <duration>. 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 <x> <y> <z> <chunkCount> [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 <entity> <dimension> [<x> <y> <z>]
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 <te|entity> <duration>
commands.forge.tracking.reset.usage=Use /forge track reset <te|entity>
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