Files
fabric-carpet/src/main/java/carpet/settings/ParsedRule.java
T
2020-05-15 20:00:27 -03:00

260 lines
7.9 KiB
Java

package carpet.settings;
import carpet.CarpetServer;
import carpet.utils.Translations;
import carpet.utils.Messenger;
import com.google.common.collect.ImmutableList;
import net.minecraft.server.command.ServerCommandSource;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import static carpet.utils.Translations.tr;
public final class ParsedRule<T> implements Comparable<ParsedRule> {
public final Field field;
public final String name;
public final String description;
public final ImmutableList<String> extraInfo;
public final ImmutableList<String> categories;
public final ImmutableList<String> options;
public boolean isStrict;
public boolean isClient;
public final Class<T> type;
public final List<Validator<T>> validators;
public final T defaultValue;
public final String defaultAsString;
ParsedRule(Field field, Rule rule)
{
this.field = field;
this.name = rule.name().isEmpty() ? field.getName() : rule.name();
this.type = (Class<T>) field.getType();
this.description = rule.desc();
this.isStrict = rule.strict();
this.extraInfo = ImmutableList.copyOf(rule.extra());
this.categories = ImmutableList.copyOf(rule.category());
this.validators = new ArrayList<>();
for (Class v : rule.validate())
this.validators.add((Validator<T>) callConstructor(v));
if (categories.contains(RuleCategory.COMMAND))
{
this.validators.add(callConstructor(Validator._COMMAND.class));
if (this.type == String.class)
{
this.isStrict = false;
this.validators.add((Validator<T>) callConstructor(Validator._COMMAND_LEVEL_VALIDATOR.class));
}
}
this.isClient = categories.contains(RuleCategory.CLIENT);
if (this.isClient)
{
this.validators.add(callConstructor(Validator._CLIENT.class));
}
this.defaultValue = get();
this.defaultAsString = convertToString(this.defaultValue);
if (rule.options().length > 0)
{
this.options = ImmutableList.copyOf(rule.options());
}
else if (this.type == boolean.class || (this.type == String.class && categories.contains(RuleCategory.COMMAND)))
{
this.options = ImmutableList.of("true", "false");
}
else if (this.type.isEnum())
{
this.options = Arrays.stream(this.type.getEnumConstants()).map(e -> ((Enum) e).name().toLowerCase(Locale.ROOT)).collect(ImmutableList.toImmutableList());
}
else
{
this.options = ImmutableList.of();
}
if (isStrict && !this.options.isEmpty())
{
if (this.type == boolean.class || this.type == int.class || this.type == double.class || this.type == float.class)
{
this.validators.add(callConstructor(Validator._STRICT_IGNORECASE.class));
}
else
{
this.validators.add(callConstructor(Validator._STRICT.class));
}
}
}
private <T> T callConstructor(Class<T> cls)
{
try
{
Constructor<T> constr = cls.getDeclaredConstructor();
constr.setAccessible(true);
return constr.newInstance();
}
catch (ReflectiveOperationException e)
{
throw new RuntimeException(e);
}
}
public ParsedRule<T> set(ServerCommandSource source, String value)
{
if (CarpetServer.settingsManager != null && CarpetServer.settingsManager.locked)
return null;
if (type == String.class)
{
return set(source, (T) value, value);
}
else if (type == boolean.class)
{
return set(source, (T) (Object) Boolean.parseBoolean(value), value);
}
else if (type == int.class)
{
return set(source, (T) (Object) Integer.parseInt(value), value);
}
else if (type == double.class)
{
return set(source, (T) (Object) Double.parseDouble(value), value);
}
else if (type.isEnum())
{
String ucValue = value.toUpperCase(Locale.ROOT);
return set(source, (T) (Object) Enum.valueOf((Class<? extends Enum>) type, ucValue), value);
}
else
{
Messenger.m(source, "r Unknown type " + type.getSimpleName());
return null;
}
}
ParsedRule<T> set(ServerCommandSource source, T value, String stringValue)
{
try
{
for (Validator<T> validator : this.validators)
{
value = validator.validate(source, this, value, stringValue);
if (value == null)
{
if (source != null)
{
Messenger.m(source, "r Wrong value for " + name + ": " + stringValue);
if (validator.description() != null)
Messenger.m(source, "r " + validator.description());
}
return null;
}
}
if (!value.equals(get()) || source == null)
{
this.field.set(null, value);
if (source != null) CarpetServer.settingsManager.notifyRuleChanged(source, this, stringValue);
}
}
catch (IllegalAccessException e)
{
Messenger.m(source, "r Unable to access setting for "+name);
return null;
}
return this;
}
public T get()
{
try
{
return (T) this.field.get(null);
}
catch (IllegalAccessException e)
{
throw new IllegalStateException(e);
}
}
public String getAsString()
{
return convertToString(get());
}
public boolean getBoolValue()
{
if (type == boolean.class) return (Boolean) get();
if (type.isAssignableFrom(Number.class)) return ((Number) get()).doubleValue() > 0;
return false;
}
public boolean isDefault()
{
return defaultValue.equals(get());
}
public void resetToDefault(ServerCommandSource source)
{
set(source, defaultValue, defaultAsString);
}
private static String convertToString(Object value)
{
if (value instanceof Enum) return ((Enum) value).name().toLowerCase(Locale.ROOT);
return value.toString();
}
@Override
public boolean equals(Object obj)
{
return obj.getClass() == ParsedRule.class && ((ParsedRule) obj).name.equals(this.name);
}
@Override
public int hashCode()
{
return this.name.hashCode();
}
@Override
public int compareTo(ParsedRule o)
{
return this.name.compareTo(o.name);
}
@Override
public String toString()
{
return this.name + ": " + getAsString();
}
private String translationKey()
{
return String.format("rule.%s.name", name);
}
public String translatedName(){
String key = translationKey();
return Translations.hasTranslation(key) ? tr(key) + String.format(" (%s)", name): name;
}
public String translatedDescription()
{
return tr(String.format("rule.%s.desc", (name)), description);
}
public List<String> translatedExtras()
{
if (!Translations.hasTranslations()) return extraInfo;
String keyBase = String.format("rule.%s.extra.", name);
List<String> extras = new ArrayList<>();
int i = 0;
while (Translations.hasTranslation(keyBase+i))
{
extras.add(Translations.tr(keyBase+i));
}
return (extras.isEmpty()) ? extraInfo : extras;
}
}