/* * Minecraft Forge * Copyright (c) 2016. * * 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 */ /** * This software is provided under the terms of the Minecraft Forge Public * License v1.0. */ package net.minecraftforge.common.config; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import com.google.common.base.Strings; import com.google.common.collect.Lists; import net.minecraftforge.fml.client.config.ConfigGuiType; import net.minecraftforge.fml.client.config.DummyConfigElement.DummyCategoryElement; import net.minecraftforge.fml.client.config.GuiConfigEntries.IConfigEntry; import net.minecraftforge.fml.client.config.GuiEditArrayEntries.IArrayEntry; import net.minecraftforge.fml.client.config.IConfigElement; /** * This class bridges the gap between the FML config GUI classes and the Forge Configuration classes. */ public class ConfigElement implements IConfigElement { private Property prop; private Property.Type type; private boolean isProperty; private ConfigCategory category; private boolean categoriesFirst = true; public ConfigElement(ConfigCategory category) { this.category = category; isProperty = false; } public ConfigElement(Property prop) { this.prop = prop; this.type = prop.getType(); this.isProperty = true; } public ConfigElement listCategoriesFirst(boolean categoriesFirst) { this.categoriesFirst = categoriesFirst; return this; } @Override public List<IConfigElement> getChildElements() { if (!isProperty) { List<IConfigElement> elements = new ArrayList<IConfigElement>(); Iterator<ConfigCategory> ccI = category.getChildren().iterator(); Iterator<Property> pI = category.getOrderedValues().iterator(); @SuppressWarnings("unused") int index = 0; if (categoriesFirst) while (ccI.hasNext()) { ConfigElement temp = new ConfigElement(ccI.next()); if (temp.showInGui()) // don't bother adding elements that shouldn't show elements.add(temp); } while (pI.hasNext()) { ConfigElement temp = new ConfigElement(pI.next()); if (temp.showInGui()) elements.add(temp); } if (!categoriesFirst) while (ccI.hasNext()) { ConfigElement temp = new ConfigElement(ccI.next()); if (temp.showInGui()) elements.add(temp); } return elements; } return null; } @Override public String getName() { return isProperty ? prop.getName() : category.getName(); } @Override public boolean isProperty() { return isProperty; } @Override public Class<? extends IConfigEntry> getConfigEntryClass() { return isProperty ? prop.getConfigEntryClass() : category.getConfigEntryClass(); } @Override public Class<? extends IArrayEntry> getArrayEntryClass() { return isProperty ? prop.getArrayEntryClass() : null; } @Override public String getQualifiedName() { return isProperty ? prop.getName() : category.getQualifiedName(); } @Override public ConfigGuiType getType() { return isProperty ? getType(this.prop) : ConfigGuiType.CONFIG_CATEGORY; } public static ConfigGuiType getType(Property prop) { return prop.getType() == Property.Type.BOOLEAN ? ConfigGuiType.BOOLEAN : prop.getType() == Property.Type.DOUBLE ? ConfigGuiType.DOUBLE : prop.getType() == Property.Type.INTEGER ? ConfigGuiType.INTEGER : prop.getType() == Property.Type.COLOR ? ConfigGuiType.COLOR : prop.getType() == Property.Type.MOD_ID ? ConfigGuiType.MOD_ID : ConfigGuiType.STRING; } @Override public boolean isList() { return isProperty && prop.isList(); } @Override public boolean isListLengthFixed() { return isProperty && prop.isListLengthFixed(); } @Override public int getMaxListLength() { return isProperty ? prop.getMaxListLength() : -1; } @Override public String getComment() { return isProperty ? prop.getComment() : category.getComment(); } @Override public boolean isDefault() { return !isProperty || prop.isDefault(); } @Override public void setToDefault() { if (isProperty) prop.setToDefault(); } @Override public boolean requiresWorldRestart() { return isProperty ? prop.requiresWorldRestart() : category.requiresWorldRestart(); } @Override public boolean showInGui() { return isProperty ? prop.showInGui() : category.showInGui(); } @Override public boolean requiresMcRestart() { return isProperty ? prop.requiresMcRestart() : category.requiresMcRestart(); } @Override public String[] getValidValues() { return isProperty ? prop.getValidValues() : null; } @Override public String getLanguageKey() { return isProperty ? prop.getLanguageKey() : category.getLanguagekey(); } @Override public Object getDefault() { return isProperty ? prop.getDefault() : null; } @Override public Object[] getDefaults() { if (isProperty) { String[] aVal = prop.getDefaults(); if (type == Property.Type.BOOLEAN) { Boolean[] ba = new Boolean[aVal.length]; for(int i = 0; i < aVal.length; i++) ba[i] = Boolean.valueOf(aVal[i]); return ba; } else if (type == Property.Type.DOUBLE) { Double[] da = new Double[aVal.length]; for(int i = 0; i < aVal.length; i++) da[i] = Double.valueOf(aVal[i].toString()); return da; } else if (type == Property.Type.INTEGER) { Integer[] ia = new Integer[aVal.length]; for(int i = 0; i < aVal.length; i++) ia[i] = Integer.valueOf(aVal[i].toString()); return ia; } else return aVal; } return null; } @Override public Pattern getValidationPattern() { return isProperty ? prop.getValidationPattern() : null; } @Override public Object get() { return isProperty ? prop.getString() : null; } @Override public Object[] getList() { if (isProperty) { String[] aVal = prop.getStringList(); if (type == Property.Type.BOOLEAN) { Boolean[] ba = new Boolean[aVal.length]; for(int i = 0; i < aVal.length; i++) ba[i] = Boolean.valueOf(aVal[i]); return ba; } else if (type == Property.Type.DOUBLE) { Double[] da = new Double[aVal.length]; for(int i = 0; i < aVal.length; i++) da[i] = Double.valueOf(aVal[i].toString()); return da; } else if (type == Property.Type.INTEGER) { Integer[] ia = new Integer[aVal.length]; for(int i = 0; i < aVal.length; i++) ia[i] = Integer.valueOf(aVal[i].toString()); return ia; } else return aVal; } return null; } @Override public void set(Object value) { if (isProperty) { if (type == Property.Type.BOOLEAN) prop.set(Boolean.parseBoolean(value.toString())); else if (type == Property.Type.DOUBLE) prop.set(Double.parseDouble(value.toString())); else if (type == Property.Type.INTEGER) prop.set(Integer.parseInt(value.toString())); else prop.set(value.toString()); } } @Override public void set(Object[] aVal) { if (isProperty) { if (type == Property.Type.BOOLEAN) { boolean[] ba = new boolean[aVal.length]; for(int i = 0; i < aVal.length; i++) ba[i] = Boolean.valueOf(aVal[i].toString()); prop.set(ba); } else if (type == Property.Type.DOUBLE) { double[] da = new double[aVal.length]; for(int i = 0; i < aVal.length; i++) da[i] = Double.valueOf(aVal[i].toString()); prop.set(da); } else if (type == Property.Type.INTEGER) { int[] ia = new int[aVal.length]; for(int i = 0; i < aVal.length; i++) ia[i] = Integer.valueOf(aVal[i].toString()); prop.set(ia); } else { String[] is = new String[aVal.length]; for(int i = 0; i < aVal.length; i++) is[i] = aVal[i].toString(); prop.set(is); } } } @Override public Object getMinValue() { return isProperty ? prop.getMinValue() : null; } @Override public Object getMaxValue() { return isProperty ? prop.getMaxValue() : null; } /** * Provides a ConfigElement derived from the annotation-based config system * @param configClass the class which contains the configuration * @return A ConfigElement based on the described category. */ public static IConfigElement from(Class<?> configClass) { Config annotation = configClass.getAnnotation(Config.class); if (annotation == null) throw new RuntimeException(String.format("The class '%s' has no @Config annotation!", configClass.getName())); Configuration config = ConfigManager.getConfiguration(annotation.modid(), annotation.name()); if (config == null) { String error = String.format("The configuration '%s' of mod '%s' isn't loaded with the ConfigManager!", annotation.name(), annotation.modid()); throw new RuntimeException(error); } String name = Strings.isNullOrEmpty(annotation.name()) ? annotation.modid() : annotation.name(); String langKey = name; Config.LangKey langKeyAnnotation = configClass.getAnnotation(Config.LangKey.class); if (langKeyAnnotation != null) { langKey = langKeyAnnotation.value(); } if (annotation.category().isEmpty()) { List<IConfigElement> elements = Lists.newArrayList(); Set<String> catNames = config.getCategoryNames(); for (String catName : catNames) { if (catName.isEmpty()) continue; ConfigCategory category = config.getCategory(catName); DummyCategoryElement element = new DummyCategoryElement(category.getName(), category.getLanguagekey(), new ConfigElement(category).getChildElements()); element.setRequiresMcRestart(category.requiresMcRestart()); element.setRequiresWorldRestart(category.requiresWorldRestart()); elements.add(element); } return new DummyCategoryElement(name, langKey, elements); } else { ConfigCategory category = config.getCategory(annotation.category()); DummyCategoryElement element = new DummyCategoryElement(name, langKey, new ConfigElement(category).getChildElements()); element.setRequiresMcRestart(category.requiresMcRestart()); element.setRequiresWorldRestart(category.requiresWorldRestart()); return element; } } }