mirror of
https://github.com/FalsePattern/FalsePatternLib.git
synced 2026-11-15 18:24:45 +00:00
the grand config refactor
This commit is contained in:
32 files changed
+3038
-190
No files matched your search
@@ -20,23 +20,25 @@
|
||||
*/
|
||||
package com.falsepattern.lib.config;
|
||||
|
||||
import com.falsepattern.lib.DeprecationDetails;
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* A modern configuration system to replace the old and obtuse forge config system.
|
||||
*
|
||||
* Note that just annotating a configuration class with {@link Config} is not enough, you must also register it using
|
||||
* {@link com.falsepattern.lib.config.ConfigurationManager#registerConfig}!
|
||||
* {@link ConfigurationManager#initialize(Class[])} or {@link ConfigurationManager#initialize(BiConsumer, Class[])}!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@StableAPI(since = "0.6.0")
|
||||
public @interface Config {
|
||||
/**
|
||||
* The mod id that this configuration is associated with.
|
||||
@@ -51,6 +53,7 @@ public @interface Config {
|
||||
/**
|
||||
* The lang file key of this configuration. Used in config GUIs.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@@ -61,6 +64,7 @@ public @interface Config {
|
||||
/**
|
||||
* The description of the configuration.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -72,6 +76,7 @@ public @interface Config {
|
||||
* If you have extra fields in the config class used for anything else other than configuring, you must annotate
|
||||
* the using this so that the config engine doesn't pick them up.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -82,6 +87,7 @@ public @interface Config {
|
||||
* The default value for a boolean field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -92,6 +98,7 @@ public @interface Config {
|
||||
/**
|
||||
* The range of possible values an int config can have.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -105,6 +112,7 @@ public @interface Config {
|
||||
* The default value for an int field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -114,12 +122,16 @@ public @interface Config {
|
||||
|
||||
/**
|
||||
* The range of possible values a float config can have.
|
||||
* Notice: float configs are deprecated! Use double configs instead!
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecationDetails(stableSince = "0.6.0",
|
||||
deprecatedSince = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface RangeFloat {
|
||||
float min() default Float.MIN_VALUE;
|
||||
float min() default -Float.MAX_VALUE;
|
||||
|
||||
float max() default Float.MAX_VALUE;
|
||||
}
|
||||
@@ -127,7 +139,11 @@ public @interface Config {
|
||||
/**
|
||||
* The default value for a float field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
* Notice: float configs are deprecated! Use double configs instead!
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecationDetails(stableSince = "0.6.0",
|
||||
deprecatedSince = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -135,10 +151,36 @@ public @interface Config {
|
||||
float value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The range of possible values a double config can have.
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface RangeDouble {
|
||||
double min() default -Double.MAX_VALUE;
|
||||
|
||||
double max() default Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for a double field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface DefaultDouble {
|
||||
double value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for a String field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -146,9 +188,27 @@ public @interface Config {
|
||||
String value();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This annotation limits the maximum number of characters present in a string configuration.
|
||||
*
|
||||
* Note: If this annotation is not present, the maximum length will be implicitly set to 256 to avoid malicious
|
||||
* synchronizations that would make clients run out of memory!
|
||||
*
|
||||
* When used with a string list, this limit will apply to each element individually, not to the size of the list as a whole.
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface StringMaxLength {
|
||||
int value();
|
||||
}
|
||||
|
||||
/**
|
||||
* A regex pattern for restricting the allowed strings.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -160,6 +220,7 @@ public @interface Config {
|
||||
* The default value for an Enum field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -171,6 +232,7 @@ public @interface Config {
|
||||
* The default value for a string array field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -178,9 +240,74 @@ public @interface Config {
|
||||
String[] value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for a double array field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface DefaultDoubleList {
|
||||
double[] value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for an int array field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface DefaultIntList {
|
||||
int[] value();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for an boolean array field. Not having a default is deprecated since 0.10, and will be strongly
|
||||
* enforced in 0.11+!
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface DefaultBooleanList {
|
||||
boolean[] value();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this annotation is present, the list in the config will be forced to have exactly the amount of elements as
|
||||
* the default value.
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface ListFixedLength {
|
||||
}
|
||||
|
||||
/**
|
||||
* This annotation limits the maximum number of elements present in an array configuration. Only effective if
|
||||
* {@link ListFixedLength} is NOT present.
|
||||
*
|
||||
* Note: If this annotation is not present, the maximum length will be implicitly set to 256 to avoid malicious
|
||||
* synchronizations that would make clients run out of memory!
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface ListMaxLength {
|
||||
int value();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The name of this config property in the config file. If not specified, the field's name will be used instead.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@@ -191,6 +318,7 @@ public @interface Config {
|
||||
/**
|
||||
* Whether the specific configuration needs a minecraft restart to be applied.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@@ -200,6 +328,7 @@ public @interface Config {
|
||||
/**
|
||||
* Whether the specific configuration needs a world/server rejoin to be applied.
|
||||
*/
|
||||
@StableAPI(since = "0.6.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@@ -207,7 +336,7 @@ public @interface Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that this configuration entry/class should be synchronized between the client and the server when
|
||||
* Signals that this configuration class should be synchronized between the client and the server when
|
||||
* joining a multiplayer instance.
|
||||
*
|
||||
* Note that synchronization ALWAYS happens FROM the server TO the client. The server should NEVER attempt to get
|
||||
@@ -216,20 +345,17 @@ public @interface Config {
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
@Target(ElementType.TYPE)
|
||||
@interface Synchronize {
|
||||
/**
|
||||
* This is a limit on how many bytes the client will accept from the server. If this limit is exceeded,
|
||||
* the client shall refuse to connect to the server. For String[]-s, the amount of bytes is the sum of all
|
||||
* strings inside the array.<br><br>
|
||||
*
|
||||
* This limitation option exists to avoid malicious servers flooding clients with data.<br><br>
|
||||
*
|
||||
* By default, the client will accept any amount of bytes.<br><br>
|
||||
*
|
||||
* This only applies for String and String[] configurations, and is ignored on the other config types.
|
||||
* For enums, this value is computed automatically.
|
||||
*/
|
||||
int maxLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to mark config fields you don't want to synchronize in a class marked with {@link Synchronize}.
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface NoSync {
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,9 @@
|
||||
*/
|
||||
package com.falsepattern.lib.config;
|
||||
|
||||
import com.falsepattern.lib.DeprecationDetails;
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.internal.impl.config.ConfigurationManagerImpl;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -28,9 +30,11 @@ import lombok.val;
|
||||
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Class for controlling the loading of configuration files.
|
||||
@@ -39,13 +43,64 @@ import java.util.List;
|
||||
@StableAPI(since = "0.6.0")
|
||||
public class ConfigurationManager {
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void initialize(Class<?>... configClasses) throws ConfigException {
|
||||
initialize((a, b) -> {}, configClasses);
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void initialize(BiConsumer<Class<?>, Field> validatorErrorCallback, Class<?>... configClasses) throws ConfigException {
|
||||
for (val clazz: configClasses) {
|
||||
ConfigurationManagerImpl.register(clazz);
|
||||
ConfigurationManagerImpl.load(clazz);
|
||||
ConfigurationManagerImpl.validateFields(validatorErrorCallback, clazz, true);
|
||||
ConfigurationManagerImpl.save(clazz);
|
||||
}
|
||||
}
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static boolean validate(boolean resetInvalid, Class<?>... configClasses)
|
||||
throws ConfigException {
|
||||
return validate((x, y) -> {}, resetInvalid, configClasses);
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static boolean validate(BiConsumer<Class<?>, Field> validatorErrorCallback, boolean resetInvalid, Class<?>... configClasses)
|
||||
throws ConfigException {
|
||||
boolean valid = true;
|
||||
for (val clazz: configClasses) {
|
||||
valid &= ConfigurationManagerImpl.validateFields(validatorErrorCallback, clazz, resetInvalid);
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void loadFromFile(Class<?>... configClasses) throws ConfigException {
|
||||
for (val clazz: configClasses) {
|
||||
ConfigurationManagerImpl.load(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void saveToFile(boolean validateAndResetInvalid, Class<?>... configClasses) throws ConfigException {
|
||||
for (val clazz: configClasses) {
|
||||
if (validateAndResetInvalid) {
|
||||
ConfigurationManagerImpl.validateFields((a, b) -> {}, clazz, true);
|
||||
}
|
||||
ConfigurationManagerImpl.save(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a configuration class to be loaded. This should be done in preInit.
|
||||
* Registers a configuration class to be loaded. This should be done early on.
|
||||
*
|
||||
* @param configClass The class to register.
|
||||
*/
|
||||
@Deprecated
|
||||
@DeprecationDetails(stableSince = "0.6.0",
|
||||
deprecatedSince = "0.10.0")
|
||||
public static void registerConfig(Class<?> configClass) throws ConfigException {
|
||||
ConfigurationManagerImpl.registerConfig(configClass);
|
||||
FalsePatternLib.getLog().warn("A mod is using the deprecated config registration method! The following exception contains the stacktrace.", new Exception());
|
||||
ConfigurationManagerImpl.registerLoadSaveConfig(configClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,6 +111,7 @@ public class ConfigurationManager {
|
||||
* @return The configuration elements.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@StableAPI(since = "0.6.0")
|
||||
public static List<IConfigElement> getConfigElements(Class<?> configClass) throws ConfigException {
|
||||
return ConfigurationManagerImpl.getConfigElements(configClass);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.config.event;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* This event is pushed on the FMLCommonHandler event bus once all the config synchronizations have finished.
|
||||
*
|
||||
* This is a client-only event, and is never triggered serverside!
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class AllConfigSyncEvent extends Event {
|
||||
|
||||
public static boolean postStart() {
|
||||
val event = new Start();
|
||||
FMLCommonHandler.instance().bus().post(event);
|
||||
return !event.isCanceled();
|
||||
}
|
||||
|
||||
public static void postEnd() {
|
||||
FMLCommonHandler.instance().bus().post(new End());
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class Start extends AllConfigSyncEvent {
|
||||
@Override
|
||||
public boolean isCancelable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class End extends AllConfigSyncEvent {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.config.event;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
/**
|
||||
* This event is pushed on the FMLCommonHandler event bus once each time a single config synchronization has finished.
|
||||
*
|
||||
* This is a client-only event, and is never triggered serverside!
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class ConfigSyncEvent extends Event {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final Class<?> configClass;
|
||||
|
||||
public static boolean postStart(Class<?> configClass) {
|
||||
val event = new Start(configClass);
|
||||
FMLCommonHandler.instance().bus().post(event);
|
||||
return !event.isCanceled();
|
||||
}
|
||||
|
||||
public static void postEndSuccess(Class<?> configClass) {
|
||||
FMLCommonHandler.instance().bus().post(new End(configClass, true, null));
|
||||
}
|
||||
|
||||
public static void postEndFailure(Class<?> configClass, Throwable error) {
|
||||
FMLCommonHandler.instance().bus().post(new End(configClass, false, error));
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class Start extends ConfigSyncEvent {
|
||||
private Start(Class<?> configClass) {
|
||||
super(configClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class End extends ConfigSyncEvent {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final boolean successful;
|
||||
/**
|
||||
* null if successful == true.
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final Throwable error;
|
||||
|
||||
private End(Class<?> configClass, boolean successful, Throwable error) {
|
||||
super(configClass);
|
||||
this.successful = successful;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.config.event;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* You can use this event to manually trigger a synchronization request. The two different flavors are used on the two
|
||||
* different game sides. If you want to trigger this on the server, use {@link #postServer}, and if on the client, use
|
||||
* {@link #postClient}
|
||||
*
|
||||
*/
|
||||
@StableAPI(since = "0.10.0")
|
||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class ConfigSyncRequestEvent extends Event {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class Client extends ConfigSyncRequestEvent {
|
||||
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class Server extends ConfigSyncRequestEvent {
|
||||
private final List<EntityPlayerMP> players;
|
||||
|
||||
public List<EntityPlayerMP> getPlayers() {
|
||||
return Collections.unmodifiableList(players);
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void postClient() {
|
||||
FMLCommonHandler.instance().bus().post(new Client());
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static void postServer(List<EntityPlayerMP> players) {
|
||||
FMLCommonHandler.instance().bus().post(new Server(new ArrayList<>(players)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.config.event;
|
||||
|
||||
import com.falsepattern.lib.StableAPI;
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.text.FormattedText;
|
||||
import com.falsepattern.lib.toasts.GuiToast;
|
||||
import com.falsepattern.lib.toasts.SimpleToast;
|
||||
import com.falsepattern.lib.toasts.icon.ToastBG;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public abstract class ConfigValidationFailureEvent extends Event {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String reason;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final Class<?> configClass;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String fieldName;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final boolean listElement;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final int listIndex;
|
||||
|
||||
public static void postNumericRangeOutOfBounds(Field field, int listIndex, String value, String min, String max) {
|
||||
FMLCommonHandler.instance().bus().post(new NumericRangeOutOfBounds(field.getDeclaringClass(), field.getName(), listIndex, value, min, max));
|
||||
}
|
||||
|
||||
public static void postSize(Field field, int requestedSize, boolean fixedSize, int maxSize, int defaultSize) {
|
||||
FMLCommonHandler.instance().bus().post(new ListSizeOutOfBounds(field.getDeclaringClass(), field.getName(), requestedSize, fixedSize, maxSize, defaultSize));
|
||||
}
|
||||
|
||||
public static void postStringSizeOutOfBounds(Field field, int listIndex, String text, int maxSize) {
|
||||
FMLCommonHandler.instance().bus().post(new StringSizeOutOfBounds(field.getDeclaringClass(), field.getName(), listIndex, text, maxSize));
|
||||
}
|
||||
|
||||
public static void fieldIsNull(Field field, int listIndex) {
|
||||
FMLCommonHandler.instance().bus().post(new FieldIsNull(field.getDeclaringClass(), field.getName(), listIndex));
|
||||
}
|
||||
|
||||
public static void postStringPatternMismatch(Field field, int listIndex, String text, String pattern) {
|
||||
FMLCommonHandler.instance().bus().post(new StringPatternMismatch(field.getDeclaringClass(), field.getName(), listIndex, text, pattern));
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class NumericRangeOutOfBounds extends ConfigValidationFailureEvent {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String value;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String min;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String max;
|
||||
|
||||
public NumericRangeOutOfBounds(Class<?> configClass, String fieldName, int listIndex, String value, String min, String max) {
|
||||
super("Number range out of bounds", configClass, fieldName, listIndex >= 0, listIndex);
|
||||
this.value = value;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customText(StringBuilder b) {
|
||||
b.append("\nValue: ").append(value)
|
||||
.append("\nMin: ").append(min)
|
||||
.append("\nMax: ").append(max);
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class ListSizeOutOfBounds extends ConfigValidationFailureEvent {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final int size;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final boolean fixedSize;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final int maxSize;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final int defaultSize;
|
||||
|
||||
private ListSizeOutOfBounds(Class<?> configClass, String fieldName, int size, boolean fixedSize, int maxSize, int defaultSize) {
|
||||
super("Array size out of bounds", configClass, fieldName, false, -1);
|
||||
this.size = size;
|
||||
this.fixedSize = fixedSize;
|
||||
this.maxSize = maxSize;
|
||||
this.defaultSize = defaultSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customText(StringBuilder b) {
|
||||
b.append("\nSize: ").append(size);
|
||||
if (fixedSize) {
|
||||
b.append("\nRequired size: ").append(defaultSize);
|
||||
}
|
||||
b.append("\nMaximum size: ").append(maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class StringSizeOutOfBounds extends ConfigValidationFailureEvent {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String text;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final int maxSize;
|
||||
private StringSizeOutOfBounds(Class<?> configClass, String fieldName, int listIndex, String text, int maxSize) {
|
||||
super("String size out of bounds", configClass, fieldName, listIndex >= 0, listIndex);
|
||||
this.text = text;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customText(StringBuilder b) {
|
||||
b.append("\nText: ").append(text)
|
||||
.append("\nSize: ").append(text.length())
|
||||
.append("\nMax size:").append(maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class FieldIsNull extends ConfigValidationFailureEvent {
|
||||
private FieldIsNull(Class<?> configClass, String fieldName, int listIndex) {
|
||||
super("Unexpected null", configClass, fieldName, listIndex >= 0, listIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customText(StringBuilder b) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@StableAPI(since = "0.10.0")
|
||||
public static class StringPatternMismatch extends ConfigValidationFailureEvent {
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String text;
|
||||
@StableAPI(since = "0.10.0")
|
||||
public final String pattern;
|
||||
|
||||
private StringPatternMismatch(Class<?> configClass, String fieldName, int listIndex, String text, String pattern) {
|
||||
super("String pattern mismatch", configClass, fieldName, listIndex >= 0, listIndex);
|
||||
this.text = text;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customText(StringBuilder b) {
|
||||
b.append("\nText: ").append(text)
|
||||
.append("\nPattern: ").append(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void toast() {
|
||||
val ann = configClass.getAnnotation(Config.class);
|
||||
val toast = new SimpleToast(ToastBG.TOAST_DARK, null,
|
||||
FormattedText.parse(EnumChatFormatting.RED + "Config validation failed").toChatText().get(0),
|
||||
FormattedText.parse(ann.modid() + ":" + ann.category()).toChatText().get(0),
|
||||
false, 2000);
|
||||
GuiToast.add(toast);
|
||||
}
|
||||
|
||||
protected abstract void customText(StringBuilder b);
|
||||
|
||||
public void logWarn() {
|
||||
val errorString = new StringBuilder("Error validating configuration field!");
|
||||
errorString.append("\nReason: ").append(reason);
|
||||
errorString.append("\nClass: ").append(configClass.getName())
|
||||
.append("\nField: ").append(fieldName);
|
||||
if (listElement) {
|
||||
errorString.append("\nArray index: ").append(listIndex);
|
||||
}
|
||||
customText(errorString);
|
||||
FalsePatternLib.getLog().error(errorString.toString());
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import cpw.mods.fml.common.*;
|
||||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.network.NetworkRegistry;
|
||||
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -46,6 +48,7 @@ import org.apache.logging.log4j.Logger;
|
||||
acceptableRemoteVersions = "*")
|
||||
public class FalsePatternLib {
|
||||
public static final String UPDATE_URL = "https://falsepattern.com/mc/versions.json";
|
||||
public static final SimpleNetworkWrapper NETWORK = NetworkRegistry.INSTANCE.newSimpleChannel(Tags.MODID);
|
||||
|
||||
@Getter private static final Logger log = LogManager.getLogger(Tags.MODNAME);
|
||||
|
||||
|
||||
@@ -38,4 +38,13 @@ public class LibraryConfig {
|
||||
@Config.LangKey("config.falsepatternlib.disableinternet")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean ENABLE_LIBRARY_DOWNLOADS;
|
||||
|
||||
@Config.Comment("How \"loud\" the config error logging should be.")
|
||||
@Config.LangKey("config.falsepatternlib.configlogging")
|
||||
@Config.DefaultEnum("Log")
|
||||
public static ValidationLogging CONFIG_ERROR_LOUDNESS;
|
||||
|
||||
public enum ValidationLogging {
|
||||
None, Log, LogAndToast
|
||||
}
|
||||
}
|
||||
+238
-167
@@ -22,34 +22,53 @@ package com.falsepattern.lib.internal.impl.config;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.config.IConfigElementProxy;
|
||||
import com.falsepattern.lib.config.event.AllConfigSyncEvent;
|
||||
import com.falsepattern.lib.config.event.ConfigSyncEvent;
|
||||
import com.falsepattern.lib.config.event.ConfigSyncRequestEvent;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.internal.config.LibraryConfig;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncPrompt;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncRequest;
|
||||
import com.falsepattern.lib.text.FormattedText;
|
||||
import com.falsepattern.lib.toasts.GuiToast;
|
||||
import com.falsepattern.lib.toasts.SimpleToast;
|
||||
import com.falsepattern.lib.toasts.icon.ToastBG;
|
||||
import com.falsepattern.lib.util.FileUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import lombok.var;
|
||||
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraft.client.entity.EntityClientPlayerMP;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
import cpw.mods.fml.client.event.ConfigChangedEvent;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* The actual implementation of ConfigurationManager. Migrated stuff here so that we don't unnecessarily expose
|
||||
@@ -61,173 +80,166 @@ import java.util.stream.Collectors;
|
||||
public class ConfigurationManagerImpl {
|
||||
private static final Map<String, Configuration> configs = new HashMap<>();
|
||||
private static final Map<Configuration, Set<Class<?>>> configToClassMap = new HashMap<>();
|
||||
private static final Map<Class<?>, ParsedConfiguration> parsedConfigMap = new HashMap<>();
|
||||
private static final ConfigurationManagerImpl instance = new ConfigurationManagerImpl();
|
||||
private static boolean initialized = false;
|
||||
private static Path configDir;
|
||||
|
||||
public static void registerConfig(Class<?> configClass) throws ConfigException {
|
||||
public static void register(Class<?> configClass) throws ConfigException {
|
||||
init();
|
||||
val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val category = Optional.of(cfg.category().trim())
|
||||
.map((cat) -> cat.length() == 0 ? null : cat)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Config class " + configClass.getName() + " has an empty category!"));
|
||||
val rawConfig = configs.computeIfAbsent(cfg.modid(), (ignored) -> {
|
||||
val c = new Configuration(configDir.resolve(cfg.modid() + ".cfg").toFile());
|
||||
if (!parsedConfigMap.containsKey(configClass)) {
|
||||
val parsedConfig = ParsedConfiguration.parseConfig(configClass);
|
||||
configToClassMap.computeIfAbsent(parsedConfig.rawConfig, (ignored) -> new HashSet<>()).add(configClass);
|
||||
parsedConfigMap.put(configClass, ParsedConfiguration.parseConfig(configClass));
|
||||
}
|
||||
}
|
||||
|
||||
static Configuration getForgeConfig(String modid) {
|
||||
return configs.computeIfAbsent(modid, (ignored) -> {
|
||||
val c = new Configuration(configDir.resolve(modid + ".cfg").toFile());
|
||||
c.load();
|
||||
return c;
|
||||
});
|
||||
configToClassMap.computeIfAbsent(rawConfig, (ignored) -> new HashSet<>()).add(configClass);
|
||||
try {
|
||||
processConfigInternal(configClass, category, rawConfig);
|
||||
rawConfig.save();
|
||||
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | NoSuchFieldException e) {
|
||||
throw new ConfigException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static List<IConfigElement> getConfigElements(Class<?> configClass) throws ConfigException {
|
||||
init();
|
||||
val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val rawConfig = Optional.ofNullable(configs.get(cfg.modid()))
|
||||
.map((conf) -> Optional.ofNullable(configToClassMap.get(conf))
|
||||
.map((l) -> l.contains(configClass))
|
||||
.orElse(false) ? conf : null)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Tried to get config elements for non-registered config class!"));
|
||||
val category = cfg.category();
|
||||
val elements = new ConfigElement<>(rawConfig.getCategory(category)).getChildElements();
|
||||
return elements.stream().map((element) -> new IConfigElementProxy(element, () -> {
|
||||
try {
|
||||
processConfigInternal(configClass, category, rawConfig);
|
||||
rawConfig.save();
|
||||
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | NoSuchFieldException |
|
||||
ConfigException e) {
|
||||
e.printStackTrace();
|
||||
public static void load(Class<?> configClass) throws ConfigException {
|
||||
if (!parsedConfigMap.containsKey(configClass)) {
|
||||
throw new ConfigException("Class " + configClass.getName() + " is not a registered configuration!");
|
||||
}
|
||||
parsedConfigMap.get(configClass).load();
|
||||
}
|
||||
|
||||
public static void save(Class<?> configClass) throws ConfigException {
|
||||
if (!parsedConfigMap.containsKey(configClass)) {
|
||||
throw new ConfigException("Class " + configClass.getName() + " is not a registered configuration!");
|
||||
}
|
||||
parsedConfigMap.get(configClass).save();
|
||||
}
|
||||
|
||||
public static boolean validateFields(BiConsumer<Class<?>, Field> invalidFieldHandler, Class<?> configClass, boolean resetInvalid) throws ConfigException {
|
||||
if (!parsedConfigMap.containsKey(configClass)) {
|
||||
throw new ConfigException("Class " + configClass.getName() + " is not a registered configuration!");
|
||||
}
|
||||
val parsed = parsedConfigMap.get(configClass);
|
||||
return parsed.validate(invalidFieldHandler, resetInvalid);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void registerLoadSaveConfig(Class<?> configClass) throws ConfigException {
|
||||
register(configClass);
|
||||
load(configClass);
|
||||
save(configClass);
|
||||
}
|
||||
|
||||
public static void sendRequest(DataOutput output) throws IOException {
|
||||
val synced = new ArrayList<Class<?>>();
|
||||
for (val entry: parsedConfigMap.entrySet()) {
|
||||
if (entry.getValue().sync) {
|
||||
synced.add(entry.getKey());
|
||||
}
|
||||
})).collect(Collectors.toList());
|
||||
}
|
||||
output.writeInt(synced.size());
|
||||
for (val clazz: synced) {
|
||||
output.writeUTF(clazz.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void processConfigInternal(Class<?> configClass, String category, Configuration rawConfig)
|
||||
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException,
|
||||
ConfigException {
|
||||
val cat = rawConfig.getCategory(category);
|
||||
if (configClass.isAnnotationPresent(Config.RequiresWorldRestart.class)) {
|
||||
cat.setRequiresWorldRestart(true);
|
||||
public static List<Class<?>> receiveRequest(DataInput input) throws IOException {
|
||||
val result = new ArrayList<Class<?>>();
|
||||
val count = input.readInt();
|
||||
val classNames = new HashSet<String>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
classNames.add(input.readUTF());
|
||||
}
|
||||
if (configClass.isAssignableFrom(Config.RequiresMcRestart.class)) {
|
||||
cat.setRequiresMcRestart(true);
|
||||
for (val entry: parsedConfigMap.keySet()) {
|
||||
if (classNames.contains(entry.getName())) {
|
||||
result.add(entry);
|
||||
}
|
||||
}
|
||||
for (val field : configClass.getDeclaredFields()) {
|
||||
if (field.getAnnotation(Config.Ignore.class) != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void sendReply(DataOutput output, List<Class<?>> requestedClasses) throws IOException {
|
||||
val syncEntries = new HashMap<>(parsedConfigMap);
|
||||
for (val entry: parsedConfigMap.entrySet()) {
|
||||
if (!entry.getValue().sync || !requestedClasses.contains(entry.getKey())) {
|
||||
syncEntries.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
output.writeInt(syncEntries.size());
|
||||
for (val entry: syncEntries.entrySet()) {
|
||||
output.writeUTF(entry.getKey().getName());
|
||||
val b = new ByteArrayOutputStream();
|
||||
val bo = new DataOutputStream(b);
|
||||
entry.getValue().transmit(bo);
|
||||
bo.close();
|
||||
val bytes = b.toByteArray();
|
||||
output.writeInt(bytes.length);
|
||||
output.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static void receiveReply(DataInput input) throws IOException {
|
||||
if (!AllConfigSyncEvent.postStart()) {
|
||||
FalsePatternLib.getLog().warn("Config synchronization was cancelled by event.");
|
||||
}
|
||||
int count = input.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String className = input.readUTF();
|
||||
int dataSize = input.readInt();
|
||||
val opt = parsedConfigMap.keySet().stream().filter((clazz) -> clazz.getName().equals(className)).findFirst();
|
||||
if (!opt.isPresent()) {
|
||||
input.skipBytes(dataSize);
|
||||
FalsePatternLib.getLog().warn("Server tried to sync config not registered on our side: " + className);
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
val comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class))
|
||||
.map(Config.Comment::value)
|
||||
.map((lines) -> String.join("\n", lines))
|
||||
.orElse("");
|
||||
val name = Optional.ofNullable(field.getAnnotation(Config.Name.class))
|
||||
.map(Config.Name::value)
|
||||
.orElse(field.getName());
|
||||
val langKey = Optional.ofNullable(field.getAnnotation(Config.LangKey.class))
|
||||
.map(Config.LangKey::value)
|
||||
.orElse(name);
|
||||
val fieldClass = field.getType();
|
||||
var boxed = false;
|
||||
if ((boxed = fieldClass.equals(Boolean.class)) || fieldClass.equals(boolean.class)) {
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class))
|
||||
.map(Config.DefaultBoolean::value)
|
||||
.orElse(boxed ? (Boolean) field.get(null) : field.getBoolean(null));
|
||||
field.setBoolean(null, rawConfig.getBoolean(name, category, defaultValue, comment, langKey));
|
||||
} else if ((boxed = fieldClass.equals(Integer.class)) || fieldClass.equals(int.class)) {
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class));
|
||||
val min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE);
|
||||
val max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE);
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class))
|
||||
.map(Config.DefaultInt::value)
|
||||
.orElse(boxed ? (Integer) field.get(null) : field.getInt(null));
|
||||
field.setInt(null, rawConfig.getInt(name, category, defaultValue, min, max, comment, langKey));
|
||||
} else if ((boxed = fieldClass.equals(Float.class)) || fieldClass.equals(float.class)) {
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeFloat.class));
|
||||
val min = range.map(Config.RangeFloat::min).orElse(Float.MIN_VALUE);
|
||||
val max = range.map(Config.RangeFloat::max).orElse(Float.MAX_VALUE);
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class))
|
||||
.map(Config.DefaultFloat::value)
|
||||
.orElse(boxed ? (Float) field.get(null) : field.getFloat(null));
|
||||
field.setFloat(null, rawConfig.getFloat(name, category, defaultValue, min, max, comment, langKey));
|
||||
} else if (fieldClass.equals(String.class)) {
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class))
|
||||
.map(Config.DefaultString::value)
|
||||
.orElse((String) field.get(null));
|
||||
val pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class))
|
||||
.map(Config.Pattern::value)
|
||||
.map(Pattern::compile)
|
||||
.orElse(null);
|
||||
field.set(null, rawConfig.getString(name, category, defaultValue, comment, langKey, pattern));
|
||||
} else if (fieldClass.isEnum()) {
|
||||
val enumValues = Arrays.stream((Object[]) fieldClass.getDeclaredMethod("values").invoke(null))
|
||||
.map((obj) -> (Enum<?>) obj)
|
||||
.collect(Collectors.toList());
|
||||
val defaultValue = (Enum<?>) Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class))
|
||||
.map(Config.DefaultEnum::value)
|
||||
.map((defName) -> extractField(fieldClass, defName))
|
||||
.map(ConfigurationManagerImpl::extractValue)
|
||||
.orElse(field.get(null));
|
||||
val possibleValues = enumValues.stream().map(Enum::name).toArray(String[]::new);
|
||||
var value = rawConfig.getString(name, category, defaultValue.name(),
|
||||
comment + "\nPossible values: " + Arrays.toString(possibleValues) +
|
||||
"\n", possibleValues, langKey);
|
||||
val clazz = opt.get();
|
||||
val config = parsedConfigMap.get(clazz);
|
||||
if (!config.sync) {
|
||||
input.skipBytes(dataSize);
|
||||
FalsePatternLib.getLog().warn("Server tried to sync config without @Synchronize annotation on our side: " + className);
|
||||
continue;
|
||||
}
|
||||
if (!ConfigSyncEvent.postStart(clazz)) {
|
||||
input.skipBytes(dataSize);
|
||||
FalsePatternLib.getLog().warn("Config synchronization was cancelled by event for: " + className);
|
||||
continue;
|
||||
}
|
||||
val bytes = new byte[dataSize];
|
||||
input.readFully(bytes);
|
||||
val b = new ByteArrayInputStream(bytes);
|
||||
val bi = new DataInputStream(b);
|
||||
try {
|
||||
config.receive(bi);
|
||||
config.validate((x, y) -> {}, true);
|
||||
ConfigSyncEvent.postEndSuccess(clazz);
|
||||
} catch (Throwable e) {
|
||||
ConfigSyncEvent.postEndFailure(clazz, e);
|
||||
}
|
||||
bi.close();
|
||||
}
|
||||
AllConfigSyncEvent.postEnd();
|
||||
}
|
||||
|
||||
try {
|
||||
if (!Arrays.asList(possibleValues).contains(value)) {
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
val enumField = fieldClass.getDeclaredField(value);
|
||||
if (!enumField.isEnumConstant()) {
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
field.set(null, enumField.get(null));
|
||||
} catch (NoSuchFieldException e) {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("Invalid value " + value + " for enum configuration field " + field.getName() +
|
||||
" of type " + fieldClass.getName() + " in config class " +
|
||||
configClass.getName() + "! Using default value of " + defaultValue + "!");
|
||||
field.set(null, defaultValue);
|
||||
}
|
||||
} else if (fieldClass.isArray() && fieldClass.getComponentType().equals(String.class)) {
|
||||
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultStringList.class))
|
||||
.map(Config.DefaultStringList::value)
|
||||
.orElse((String[]) field.get(null));
|
||||
var value = rawConfig.getStringList(name, category, defaultValue, comment, null, langKey);
|
||||
field.set(null, value);
|
||||
} else {
|
||||
throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() +
|
||||
": Unsupported type " + fieldClass.getName() +
|
||||
"! Did you forget an @Ignore annotation?");
|
||||
}
|
||||
if (field.isAnnotationPresent(Config.RequiresMcRestart.class)) {
|
||||
cat.setRequiresMcRestart(true);
|
||||
}
|
||||
if (field.isAnnotationPresent(Config.RequiresWorldRestart.class)) {
|
||||
cat.setRequiresWorldRestart(true);
|
||||
public static void loadRawConfig(Configuration rawConfig) throws ConfigException {
|
||||
rawConfig.load();
|
||||
for (val configClass: configToClassMap.get(rawConfig)) {
|
||||
val config = parsedConfigMap.get(configClass);
|
||||
try {
|
||||
config.reloadFields();
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new ConfigException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static Field extractField(Class<?> clazz, String field) {
|
||||
return clazz.getDeclaredField(field);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static Object extractValue(Field field) {
|
||||
return field.get(null);
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
public static List<IConfigElement> getConfigElements(Class<?> configClass) throws ConfigException {
|
||||
if (!parsedConfigMap.containsKey(configClass)) {
|
||||
throw new ConfigException("Class " + configClass.getName() + " is not a registered configuration!");
|
||||
}
|
||||
val config = parsedConfigMap.get(configClass);
|
||||
return config.getConfigElements();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
@@ -240,26 +252,85 @@ public class ConfigurationManagerImpl {
|
||||
|
||||
public static void registerBus() {
|
||||
FMLCommonHandler.instance().bus().register(instance);
|
||||
MinecraftForge.EVENT_BUS.register(instance);
|
||||
}
|
||||
|
||||
private static void sendSyncRequest() throws IOException {
|
||||
val event = new SyncRequest();
|
||||
event.transmit();
|
||||
FalsePatternLib.NETWORK.sendToServer(event);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@SubscribeEvent
|
||||
public void onJoinWorld(EntityJoinWorldEvent e) {
|
||||
if (e.world.isRemote && e.entity instanceof EntityClientPlayerMP) {
|
||||
sendSyncRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@SneakyThrows
|
||||
@SubscribeEvent
|
||||
public void onSyncRequestClient(ConfigSyncRequestEvent.Client e) {
|
||||
sendSyncRequest();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onSyncRequestServer(ConfigSyncRequestEvent.Server e) {
|
||||
val players = e.getPlayers();
|
||||
if (players.size() == 0) {
|
||||
FalsePatternLib.NETWORK.sendToAll(new SyncPrompt());
|
||||
} else {
|
||||
for (EntityPlayerMP player : e.getPlayers()) {
|
||||
FalsePatternLib.NETWORK.sendTo(new SyncPrompt(), player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event) {
|
||||
init();
|
||||
val config = configs.get(event.modID);
|
||||
if (config == null) {
|
||||
val rawConfig = configs.get(event.modID);
|
||||
if (rawConfig == null) {
|
||||
return;
|
||||
}
|
||||
val configClasses = configToClassMap.get(config);
|
||||
configClasses.forEach((configClass) -> {
|
||||
try {
|
||||
val category = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.map(Config::category)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Failed to get config category for class " + configClass.getName()));
|
||||
processConfigInternal(configClass, category, config);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
val configClasses = configToClassMap.get(rawConfig);
|
||||
for (val clazz: configClasses) {
|
||||
val config = parsedConfigMap.get(clazz);
|
||||
config.configChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onValidationErrorLog(ConfigValidationFailureEvent e) {
|
||||
if (LibraryConfig.CONFIG_ERROR_LOUDNESS != LibraryConfig.ValidationLogging.None) {
|
||||
e.logWarn();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onValidationErrorToast(ConfigValidationFailureEvent e) {
|
||||
if (LibraryConfig.CONFIG_ERROR_LOUDNESS == LibraryConfig.ValidationLogging.LogAndToast) {
|
||||
e.toast();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onConfigSyncFinished(ConfigSyncEvent.End e) {
|
||||
val cfg = e.configClass.getAnnotation(Config.class);
|
||||
if (e.successful) {
|
||||
GuiToast.add(new SimpleToast(ToastBG.TOAST_DARK, null,
|
||||
FormattedText.parse(EnumChatFormatting.GREEN + "Synced config").toChatText().get(0),
|
||||
FormattedText.parse(cfg.modid() + ":" + cfg.category()).toChatText().get(0),
|
||||
false, 5000));
|
||||
} else {
|
||||
GuiToast.add(new SimpleToast(ToastBG.TOAST_DARK, null,
|
||||
FormattedText.parse(EnumChatFormatting.RED + "Failed to sync config").toChatText().get(0),
|
||||
FormattedText.parse(cfg.modid() + ":" + cfg.category()).toChatText().get(0),
|
||||
false, 5000));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
*
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.AConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.BooleanConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.DoubleListConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.EnumConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.FloatConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.IntConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.IntListConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.StringConfigField;
|
||||
import com.falsepattern.lib.internal.impl.config.fields.StringListConfigField;
|
||||
import com.falsepattern.lib.util.ReflectionUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.ConfigElement;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
|
||||
import cpw.mods.fml.client.config.IConfigElement;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ParsedConfiguration {
|
||||
private static final Field propField;
|
||||
|
||||
public final Class<?> configClass;
|
||||
public final String modid;
|
||||
public final String category;
|
||||
public final Configuration rawConfig;
|
||||
public final boolean sync;
|
||||
private final Map<String, AConfigField<?>> fields = new HashMap<>();
|
||||
private final Map<String, ConfigElement<?>> elements = new HashMap<>();
|
||||
private int maxFieldNameLength;
|
||||
|
||||
static {
|
||||
try {
|
||||
propField = ConfigElement.class.getDeclaredField("prop");
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ReflectionUtil.jailBreak(propField);
|
||||
}
|
||||
|
||||
public static ParsedConfiguration parseConfig(Class<?> configClass) throws ConfigException {
|
||||
val cfg = Optional.ofNullable(configClass.getAnnotation(Config.class))
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Class " + configClass.getName() + " does not have a @Config annotation!"));
|
||||
val category = Optional.of(cfg.category().trim())
|
||||
.map((cat) -> cat.length() == 0 ? null : cat)
|
||||
.orElseThrow(() -> new ConfigException(
|
||||
"Config class " + configClass.getName() + " has an empty category!"));
|
||||
val rawConfig = ConfigurationManagerImpl.getForgeConfig(cfg.modid());
|
||||
val parsedConfig = new ParsedConfiguration(configClass, cfg.modid(), category, rawConfig, configClass.isAnnotationPresent(Config.Synchronize.class));
|
||||
try {
|
||||
parsedConfig.reloadFields();
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new ConfigException(e);
|
||||
}
|
||||
return parsedConfig;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
for (val field : fields.values()) {
|
||||
field.save();
|
||||
}
|
||||
rawConfig.save();
|
||||
}
|
||||
|
||||
//Happens when changed through the gui
|
||||
public void configChanged() {
|
||||
for (val field: fields.values()) {
|
||||
field.load();
|
||||
}
|
||||
rawConfig.save();
|
||||
}
|
||||
|
||||
public void load() throws ConfigException {
|
||||
ConfigurationManagerImpl.loadRawConfig(rawConfig);
|
||||
for (val field: fields.values()) {
|
||||
field.load();
|
||||
}
|
||||
}
|
||||
|
||||
public void receive(DataInput input) throws IOException {
|
||||
if (sync) {
|
||||
val syncFields = new HashMap<>(fields);
|
||||
for (val key: fields.keySet()) {
|
||||
if (syncFields.get(key).noSync) {
|
||||
syncFields.remove(key);
|
||||
}
|
||||
}
|
||||
while (syncFields.size() > 0) {
|
||||
val fieldName = StringConfigField.receiveString(input, maxFieldNameLength, "field name", configClass.getName());
|
||||
if (!syncFields.containsKey(fieldName)) {
|
||||
throw new IOException("Invalid sync field name received: " + fieldName + " for config class " + configClass.getName());
|
||||
}
|
||||
syncFields.remove(fieldName).receive(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
if (sync) {
|
||||
val syncFields = new HashMap<>(fields);
|
||||
for (val key: fields.keySet()) {
|
||||
if (syncFields.get(key).noSync) {
|
||||
syncFields.remove(key);
|
||||
}
|
||||
}
|
||||
for (val field: syncFields.entrySet()) {
|
||||
StringConfigField.transmitString(output, field.getKey());
|
||||
field.getValue().transmit(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reloadFields() throws ConfigException, NoSuchFieldException, IllegalAccessException {
|
||||
fields.clear();
|
||||
maxFieldNameLength = 0;
|
||||
val cat = rawConfig.getCategory(category);
|
||||
if (configClass.isAnnotationPresent(Config.RequiresWorldRestart.class)) {
|
||||
cat.setRequiresWorldRestart(true);
|
||||
}
|
||||
if (configClass.isAssignableFrom(Config.RequiresMcRestart.class)) {
|
||||
cat.setRequiresMcRestart(true);
|
||||
}
|
||||
for (val field : configClass.getDeclaredFields()) {
|
||||
if (field.getAnnotation(Config.Ignore.class) != null && (field.getModifiers() & Modifier.FINAL) != 0) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
maxFieldNameLength = Math.max(maxFieldNameLength, field.getName().length());
|
||||
val fieldClass = field.getType();
|
||||
val name = field.getName();
|
||||
if (fieldClass.equals(Boolean.class) || fieldClass.equals(boolean.class)) {
|
||||
fields.put(name, new BooleanConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.equals(Integer.class) || fieldClass.equals(int.class)) {
|
||||
fields.put(name, new IntConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.equals(Float.class) || fieldClass.equals(float.class)) {
|
||||
//noinspection deprecation
|
||||
fields.put(name, new FloatConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.equals(String.class)) {
|
||||
fields.put(name, new StringConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.isEnum()) {
|
||||
fields.put(name, new EnumConfigField<>(field, rawConfig, category));
|
||||
} else if (fieldClass.isArray() && fieldClass.getComponentType().equals(boolean.class)) {
|
||||
fields.put(name, new StringListConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.isArray() && fieldClass.getComponentType().equals(int.class)) {
|
||||
fields.put(name, new IntListConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.isArray() && fieldClass.getComponentType().equals(double.class)) {
|
||||
fields.put(name, new DoubleListConfigField(field, rawConfig, category));
|
||||
} else if (fieldClass.isArray() && fieldClass.getComponentType().equals(String.class)) {
|
||||
fields.put(name, new StringListConfigField(field, rawConfig, category));
|
||||
} else {
|
||||
throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() +
|
||||
": Unsupported type " + fieldClass.getName() +
|
||||
"! Did you forget an @Ignore annotation?");
|
||||
}
|
||||
if (field.isAnnotationPresent(Config.RequiresMcRestart.class)) {
|
||||
cat.setRequiresMcRestart(true);
|
||||
}
|
||||
if (field.isAnnotationPresent(Config.RequiresWorldRestart.class)) {
|
||||
cat.setRequiresWorldRestart(true);
|
||||
}
|
||||
val prop = fields.get(name).getProperty();
|
||||
val configElement = elements.computeIfAbsent(name, (name2) -> new ConfigElement<>(prop));
|
||||
propField.set(configElement, prop);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<IConfigElement> getConfigElements() {
|
||||
return new ArrayList<>(elements.values());
|
||||
}
|
||||
|
||||
public boolean validate(BiConsumer<Class<?>, Field> invalidFieldHandler, boolean resetInvalid) {
|
||||
boolean valid = true;
|
||||
for (val field: fields.values()) {
|
||||
if (!field.validateField()) {
|
||||
if (resetInvalid) {
|
||||
field.setToDefault();
|
||||
}
|
||||
invalidFieldHandler.accept(configClass, field.getJavaField());
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class AConfigField<T> {
|
||||
public final boolean noSync;
|
||||
protected final Field field;
|
||||
protected final Configuration configuration;
|
||||
protected final String category;
|
||||
protected final String name;
|
||||
protected final String langKey;
|
||||
protected final Property.Type type;
|
||||
protected final Property property;
|
||||
protected String comment;
|
||||
|
||||
protected AConfigField(Field field, Configuration configuration, String category, Property.Type type) {
|
||||
this(field, configuration, category, type, false);
|
||||
}
|
||||
|
||||
protected AConfigField(Field field, Configuration configuration, String category, Property.Type type, boolean isList) {
|
||||
this.field = field;
|
||||
this.configuration = configuration;
|
||||
this.category = category;
|
||||
comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class))
|
||||
.map(Config.Comment::value)
|
||||
.map((lines) -> String.join("\n", lines))
|
||||
.orElse("");
|
||||
name = Optional.ofNullable(field.getAnnotation(Config.Name.class))
|
||||
.map(Config.Name::value)
|
||||
.orElse(field.getName());
|
||||
langKey =
|
||||
Optional.ofNullable(field.getAnnotation(Config.LangKey.class)).map(Config.LangKey::value).orElse(name);
|
||||
this.type = type;
|
||||
if (isList) {
|
||||
property = configuration.get(category, name, new String[0], comment, type);
|
||||
} else {
|
||||
property = configuration.get(category, name, "", comment, type);
|
||||
}
|
||||
property.setLanguageKey(langKey);
|
||||
noSync = field.isAnnotationPresent(Config.NoSync.class);
|
||||
}
|
||||
|
||||
protected abstract T getField();
|
||||
|
||||
protected abstract void putField(T value);
|
||||
|
||||
protected abstract T getConfig();
|
||||
|
||||
protected abstract void putConfig(T value);
|
||||
|
||||
protected abstract T getDefault();
|
||||
|
||||
public void save() {
|
||||
if (!validateField()) {
|
||||
setToDefault();
|
||||
}
|
||||
putConfig(getField());
|
||||
}
|
||||
|
||||
public void load() {
|
||||
putField(getConfig());
|
||||
if (!validateField()) {
|
||||
setToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public void setToDefault() {
|
||||
putField(getDefault());
|
||||
putConfig(getDefault());
|
||||
}
|
||||
|
||||
public Property getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public abstract boolean validateField();
|
||||
|
||||
public abstract void transmit(DataOutput output) throws IOException;
|
||||
|
||||
public abstract void receive(DataInput input) throws IOException;
|
||||
|
||||
public Field getJavaField() {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class AListConfigField<T> extends AConfigField<T> {
|
||||
protected final boolean fixedLength;
|
||||
protected final int maxLength;
|
||||
|
||||
protected AListConfigField(Field field, Configuration configuration, String category, Property.Type type)
|
||||
throws ConfigException {
|
||||
super(field, configuration, category, type, true);
|
||||
fixedLength = field.isAnnotationPresent(Config.ListFixedLength.class);
|
||||
maxLength = Optional.ofNullable(field.getAnnotation(Config.ListMaxLength.class))
|
||||
.map(Config.ListMaxLength::value)
|
||||
.orElse(256);
|
||||
if (maxLength < 0) {
|
||||
throw new ConfigException(
|
||||
"Negative length list configurations are not supported!\n" + "Field name: " + field.getName() +
|
||||
", class: " + field.getDeclaringClass().getName());
|
||||
}
|
||||
property.setIsListLengthFixed(fixedLength);
|
||||
property.setMaxListLength(maxLength);
|
||||
property.comment += "\n[fixed length: " + (fixedLength ? "yes" : "no") + ", max length: " + maxLength + "]";
|
||||
}
|
||||
|
||||
protected abstract int length(T arr);
|
||||
|
||||
protected abstract T arrayCopy(T arr);
|
||||
|
||||
protected abstract void transmitElements(DataOutput output, T arr) throws IOException;
|
||||
|
||||
protected abstract void receiveElements(DataInput input, T arr) throws IOException;
|
||||
|
||||
protected abstract T createArray(int length);
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected T getField() {
|
||||
return arrayCopy((T) field.get(null));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(T value) {
|
||||
field.set(null, arrayCopy(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
val f = getField();
|
||||
if (f == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
if ((fixedLength && length(getDefault()) != length(f)) || (maxLength >= 0 && length(f) > maxLength)) {
|
||||
ConfigValidationFailureEvent.postSize(field, length(f), fixedLength, maxLength, length(getDefault()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
val f = getField();
|
||||
output.writeInt(length(f));
|
||||
transmitElements(output, f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
int length = input.readInt();
|
||||
if (length > maxLength || fixedLength && length(getDefault()) != length) {
|
||||
throw new IOException("Error while retrieving config value for field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() + ":\n" + "Illegal array length received!");
|
||||
}
|
||||
val arr = createArray(length);
|
||||
receiveElements(input, arr);
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BooleanConfigField extends AConfigField<Boolean> {
|
||||
private final boolean primitive;
|
||||
private final boolean defaultValue;
|
||||
|
||||
public BooleanConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.BOOLEAN);
|
||||
primitive = field.getType().isPrimitive();
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class))
|
||||
.map(Config.DefaultBoolean::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultBoolean annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return field.getType().isPrimitive() ? field.getBoolean(null)
|
||||
: (Boolean) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValue(defaultValue);
|
||||
if (!property.isBooleanValue()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[default: " + defaultValue + "]";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected Boolean getField() {
|
||||
return primitive ? field.getBoolean(null) : (Boolean) field.get(null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(Boolean value) {
|
||||
if (primitive) {
|
||||
field.setBoolean(null, value);
|
||||
} else {
|
||||
field.set(null, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean getConfig() {
|
||||
return property.getBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(Boolean value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!primitive && field.get(null) == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
output.writeBoolean(getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(input.readBoolean());
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BooleanListConfigField extends AListConfigField<boolean[]> {
|
||||
private final boolean[] defaultValue;
|
||||
|
||||
protected BooleanListConfigField(Field field, Configuration configuration, String category) throws ConfigException {
|
||||
super(field, configuration, category, Property.Type.BOOLEAN);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBooleanList.class))
|
||||
.map(Config.DefaultBooleanList::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultBooleanList annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return (boolean[]) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValues(defaultValue);
|
||||
if (!property.isBooleanList()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[default: " + Arrays.toString(defaultValue) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int length(boolean[] arr) {
|
||||
return arr.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean[] arrayCopy(boolean[] arr) {
|
||||
return Arrays.copyOf(arr, arr.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transmitElements(DataOutput output, boolean[] arr) throws IOException {
|
||||
val transfer = new byte[(arr.length + 7) >>> 3];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
transfer[i >>> 3] |= arr[i] ? 1 << (i & 0x7) : 0;
|
||||
}
|
||||
for (val i : transfer) {
|
||||
output.writeByte(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receiveElements(DataInput input, boolean[] arr) throws IOException {
|
||||
val transfer = new byte[(arr.length + 7) >>> 3];
|
||||
for (int i = 0; i < transfer.length; i++) {
|
||||
transfer[i] = input.readByte();
|
||||
}
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = (transfer[i >>> 3] & (1 << (i & 0x7))) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean[] createArray(int length) {
|
||||
return new boolean[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean[] getConfig() {
|
||||
return property.getBooleanList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(boolean[] value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean[] getDefault() {
|
||||
return Arrays.copyOf(defaultValue, defaultValue.length);
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DoubleConfigField extends AConfigField<Double> {
|
||||
private final boolean primitive;
|
||||
private final double defaultValue;
|
||||
private final double min;
|
||||
private final double max;
|
||||
|
||||
public DoubleConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.DOUBLE);
|
||||
primitive = field.getType().isPrimitive();
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeDouble.class));
|
||||
min = range.map(Config.RangeDouble::min).orElse(-Double.MAX_VALUE);
|
||||
max = range.map(Config.RangeDouble::max).orElse(Double.MAX_VALUE);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultDouble.class))
|
||||
.map(Config.DefaultDouble::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultDouble annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return field.getType().isPrimitive() ? field.getInt(null)
|
||||
: (Double) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValue(defaultValue);
|
||||
property.setMinValue(min);
|
||||
property.setMaxValue(max);
|
||||
if (!property.isDoubleValue()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[range: " + min + " ~ " + max + ", default: " + defaultValue + "]";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected Double getField() {
|
||||
return primitive ? field.getDouble(null) : (Double) field.get(null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(Double value) {
|
||||
if (primitive) {
|
||||
field.setDouble(null, value);
|
||||
} else {
|
||||
field.set(null, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double getConfig() {
|
||||
return property.getDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(Double value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!primitive && field.get(null) == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
val value = (double) getField();
|
||||
if (value >= min && value <= max) {
|
||||
return true;
|
||||
}
|
||||
ConfigValidationFailureEvent.postNumericRangeOutOfBounds(field, -1, Double.toString(value), Double.toString(min), Double.toString(max));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
output.writeDouble(getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(input.readDouble());
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DoubleListConfigField extends AListConfigField<double[]> {
|
||||
private final double min;
|
||||
private final double max;
|
||||
private final double[] defaultValue;
|
||||
|
||||
public DoubleListConfigField(Field field, Configuration configuration, String category) throws ConfigException {
|
||||
super(field, configuration, category, Property.Type.INTEGER);
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeDouble.class));
|
||||
min = range.map(Config.RangeDouble::min).orElse(-Double.MAX_VALUE);
|
||||
max = range.map(Config.RangeDouble::max).orElse(Double.MAX_VALUE);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultDoubleList.class))
|
||||
.map(Config.DefaultDoubleList::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultDoubleList annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return (double[]) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValues(defaultValue);
|
||||
property.setMinValue(min);
|
||||
property.setMaxValue(max);
|
||||
if (!property.isIntList()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[range: " + min + " ~ " + max + ", default: " + Arrays.toString(defaultValue) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int length(double[] arr) {
|
||||
return arr.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double[] arrayCopy(double[] arr) {
|
||||
return Arrays.copyOf(arr, arr.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transmitElements(DataOutput output, double[] arr) throws IOException {
|
||||
for (val i : arr) {
|
||||
output.writeDouble(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receiveElements(DataInput input, double[] arr) throws IOException {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = input.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double[] createArray(int length) {
|
||||
return new double[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!super.validateField()) {
|
||||
return false;
|
||||
}
|
||||
double[] doubles = getField();
|
||||
boolean valid = true;
|
||||
for (int j = 0; j < doubles.length; j++) {
|
||||
double d = doubles[j];
|
||||
if (d < min || d > max) {
|
||||
ConfigValidationFailureEvent.postNumericRangeOutOfBounds(field, j, Double.toString(d), Double.toString(min), Double.toString(max));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double[] getConfig() {
|
||||
return property.getDoubleList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(double[] value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double[] getDefault() {
|
||||
return Arrays.copyOf(defaultValue, defaultValue.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class EnumConfigField<T extends Enum<T>> extends AConfigField<T> {
|
||||
private final int maxLength;
|
||||
private final Class<T> enumClass;
|
||||
private final T defaultValue;
|
||||
private final BiMap<String, T> enumNameMap = HashBiMap.create();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EnumConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.STRING);
|
||||
enumClass = (Class<T>) field.getType();
|
||||
for (val e : enumClass.getEnumConstants()) {
|
||||
enumNameMap.put(e.name(), e);
|
||||
}
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class))
|
||||
.map(Config.DefaultEnum::value)
|
||||
.map((defName) -> enumNameMap.values()
|
||||
.stream()
|
||||
.filter((e) -> e.name().equals(defName))
|
||||
.findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Default value \"" + defName + "\" was not found in enum " + enumClass.getName())))
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultEnum annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return enumClass.cast(field.get(null));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
maxLength = enumNameMap.keySet().stream().mapToInt(String::length).max().orElse(0);
|
||||
property.setDefaultValue(defaultValue.name());
|
||||
property.setValidValues(enumNameMap.keySet().toArray(new String[0]));
|
||||
if (!enumNameMap.containsValue(getConfig())) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[default: " + defaultValue + ", possible values: " +
|
||||
Arrays.toString(enumNameMap.keySet().toArray(new String[0])) + "]";
|
||||
}
|
||||
|
||||
public static void transmitString(DataOutput output, String value) throws IOException {
|
||||
output.writeInt(value.length());
|
||||
output.writeChars(value);
|
||||
}
|
||||
|
||||
public static String receiveString(DataInput input, int maxLength, String fieldName, String className)
|
||||
throws IOException {
|
||||
val length = input.readInt();
|
||||
if (length > maxLength || length < 0) {
|
||||
throw new IOException(
|
||||
"Error while retrieving config value for field " + fieldName + " in class " + className + ":\n" +
|
||||
"Illegal string length received!");
|
||||
}
|
||||
val arr = new char[length];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = input.readChar();
|
||||
}
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
private T getEnumByName(String name) {
|
||||
if (!enumNameMap.containsKey(name)) {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("Invalid value " + name + " for enum configuration field " + field.getName() +
|
||||
" of type " + enumClass.getName() + " in config class " +
|
||||
field.getDeclaringClass().getName() + "! Using default value of " +
|
||||
defaultValue.name() + "!");
|
||||
return defaultValue;
|
||||
}
|
||||
return enumNameMap.get(name);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected T getField() {
|
||||
return enumClass.cast(field.get(null));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(T value) {
|
||||
field.set(null, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T getConfig() {
|
||||
return getEnumByName(property.getString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(T value) {
|
||||
property.set(value.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (getField() == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
transmitString(output, getField().name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(getEnumByName(receiveString(input, maxLength, field.getName(), field.getDeclaringClass().getName())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.util.MathUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
public class FloatConfigField extends AConfigField<Float> {
|
||||
private final boolean primitive;
|
||||
private final float defaultValue;
|
||||
private final boolean hasMinMax;
|
||||
private final float min;
|
||||
private final float max;
|
||||
|
||||
public FloatConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.STRING);
|
||||
FalsePatternLib.getLog()
|
||||
.warn("Warning: float configuration properties are DEPRECATED! Use doubles instead!\n" +
|
||||
"Field name: " + field.getName() + ", location: " + field.getDeclaringClass().getName());
|
||||
primitive = field.getType().isPrimitive();
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeFloat.class));
|
||||
hasMinMax = range.isPresent();
|
||||
min = hasMinMax ? range.map(Config.RangeFloat::min).orElse(-Float.MAX_VALUE) : 0;
|
||||
max = hasMinMax ? range.map(Config.RangeFloat::max).orElse(Float.MAX_VALUE) : 0;
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class))
|
||||
.map(Config.DefaultFloat::value)
|
||||
.orElseGet(() -> {
|
||||
try {
|
||||
return field.getType().isPrimitive() ? field.getFloat(null)
|
||||
: (Float) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValue(defaultValue);
|
||||
property.setMinValue(min);
|
||||
property.setMaxValue(max);
|
||||
property.comment += "\n[range: " + min + " ~ " + max + ", default: " + defaultValue + "]";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected Float getField() {
|
||||
return primitive ? field.getFloat(null) : (Integer) field.get(null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(Float value) {
|
||||
if (primitive) {
|
||||
field.setFloat(null, value);
|
||||
} else {
|
||||
field.set(null, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Float getConfig() {
|
||||
try {
|
||||
return MathUtil.clamp(Float.parseFloat(property.getString()), min, max);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(Float value) {
|
||||
property.set(Float.toString(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Float getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!primitive && field.get(null) == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
if (hasMinMax) {
|
||||
val value = (float) getField();
|
||||
if (value >= min && value <= max) {
|
||||
return true;
|
||||
}
|
||||
ConfigValidationFailureEvent.postNumericRangeOutOfBounds(field, -1, Float.toString(value), Float.toString(min), Float.toString(max));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
output.writeFloat(getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(input.readFloat());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
public class IntConfigField extends AConfigField<Integer> {
|
||||
private final boolean primitive;
|
||||
private final int defaultValue;
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
public IntConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.INTEGER);
|
||||
primitive = field.getType().isPrimitive();
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class));
|
||||
min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE);
|
||||
max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class))
|
||||
.map(Config.DefaultInt::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultInt annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return field.getType().isPrimitive() ? field.getInt(null)
|
||||
: (Integer) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValue(defaultValue);
|
||||
property.setMinValue(min);
|
||||
property.setMaxValue(max);
|
||||
if (!property.isIntValue()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[range: " + min + " ~ " + max + ", default: " + defaultValue + "]";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected Integer getField() {
|
||||
return primitive ? field.getInt(null) : (Integer) field.get(null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(Integer value) {
|
||||
if (primitive) {
|
||||
field.setInt(null, value);
|
||||
} else {
|
||||
field.set(null, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer getConfig() {
|
||||
return property.getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(Integer value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!primitive && field.get(null) == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, -1);
|
||||
return false;
|
||||
}
|
||||
val value = (int) getField();
|
||||
if (value >= min && value <= max) {
|
||||
return true;
|
||||
}
|
||||
ConfigValidationFailureEvent.postNumericRangeOutOfBounds(field, -1, Integer.toString(value), Integer.toString(min), Integer.toString(max));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
output.writeInt(getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(input.readInt());
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class IntListConfigField extends AListConfigField<int[]> {
|
||||
private final int min;
|
||||
private final int max;
|
||||
private final int[] defaultValue;
|
||||
|
||||
public IntListConfigField(Field field, Configuration configuration, String category) throws ConfigException {
|
||||
super(field, configuration, category, Property.Type.INTEGER);
|
||||
val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class));
|
||||
min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE);
|
||||
max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultIntList.class))
|
||||
.map(Config.DefaultIntList::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultIntList annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return (int[]) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
property.setDefaultValues(defaultValue);
|
||||
property.setMinValue(min);
|
||||
property.setMaxValue(max);
|
||||
if (!property.isIntList()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[range: " + min + " ~ " + max + ", default: " + Arrays.toString(defaultValue) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int length(int[] arr) {
|
||||
return arr.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] arrayCopy(int[] arr) {
|
||||
return Arrays.copyOf(arr, arr.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transmitElements(DataOutput output, int[] arr) throws IOException {
|
||||
for (val i : arr) {
|
||||
output.writeInt(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receiveElements(DataInput input, int[] arr) throws IOException {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = input.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] createArray(int length) {
|
||||
return new int[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!super.validateField()) {
|
||||
return false;
|
||||
}
|
||||
int[] ints = getField();
|
||||
boolean valid = true;
|
||||
for (int j = 0; j < ints.length; j++) {
|
||||
int i = ints[j];
|
||||
if (i < min || i > max) {
|
||||
ConfigValidationFailureEvent.postNumericRangeOutOfBounds(field, j, Integer.toString(i), Integer.toString(min), Integer.toString(max));
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getConfig() {
|
||||
return property.getIntList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(int[] value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getDefault() {
|
||||
return Arrays.copyOf(defaultValue, defaultValue.length);
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.event.ConfigValidationFailureEvent;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class StringConfigField extends AConfigField<String> {
|
||||
private final int maxLength;
|
||||
private final Pattern pattern;
|
||||
private final String defaultValue;
|
||||
|
||||
public StringConfigField(Field field, Configuration configuration, String category) {
|
||||
super(field, configuration, category, Property.Type.STRING);
|
||||
pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class))
|
||||
.map((ptr) -> Pattern.compile(ptr.value()))
|
||||
.orElse(null);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class))
|
||||
.map(Config.DefaultString::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultDouble annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return (String) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
maxLength = Optional.ofNullable(field.getAnnotation(Config.StringMaxLength.class))
|
||||
.map(Config.StringMaxLength::value)
|
||||
.orElse(256);
|
||||
property.setDefaultValue(defaultValue);
|
||||
if (!property.isDoubleValue()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment +=
|
||||
"\n[max length: " + maxLength + (pattern != null ? ", pattern: \"" + pattern.pattern() + "\"" : "") +
|
||||
", default: \"" + defaultValue + "\"]";
|
||||
}
|
||||
|
||||
public static boolean validateString(String value, int maxLength, Pattern pattern, Field field, int listIndex) {
|
||||
if (value == null) {
|
||||
ConfigValidationFailureEvent.fieldIsNull(field, listIndex);
|
||||
return false;
|
||||
}
|
||||
if (value.length() <= maxLength) {
|
||||
ConfigValidationFailureEvent.postStringSizeOutOfBounds(field, listIndex, value, maxLength);
|
||||
return false;
|
||||
}
|
||||
if (pattern != null && !pattern.matcher(value).matches()) {
|
||||
ConfigValidationFailureEvent.postStringPatternMismatch(field, listIndex, value, pattern.pattern());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void transmitString(DataOutput output, String value) throws IOException {
|
||||
output.writeInt(value.length());
|
||||
output.writeChars(value);
|
||||
}
|
||||
|
||||
public static String receiveString(DataInput input, int maxLength, String valueName, String className)
|
||||
throws IOException {
|
||||
val length = input.readInt();
|
||||
if (length > maxLength || length < 0) {
|
||||
throw new IOException("Error while retrieving value for " + valueName + " in class " + className + ":\n" +
|
||||
"Illegal string length received!");
|
||||
}
|
||||
val arr = new char[length];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = input.readChar();
|
||||
}
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected String getField() {
|
||||
return (String) field.get(null);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
protected void putField(String value) {
|
||||
field.set(null, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConfig() {
|
||||
return property.getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(String value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
return validateString(getField(), maxLength, pattern, field, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transmit(DataOutput output) throws IOException {
|
||||
transmitString(output, getField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(DataInput input) throws IOException {
|
||||
putField(receiveString(input, maxLength, field.getName(), field.getDeclaringClass().getName()));
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.fields;
|
||||
|
||||
import com.falsepattern.lib.config.Config;
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.common.config.Property;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class StringListConfigField extends AListConfigField<String[]> {
|
||||
private final String[] defaultValue;
|
||||
private final Pattern pattern;
|
||||
private final int maxStringLength;
|
||||
|
||||
public StringListConfigField(Field field, Configuration configuration, String category) throws ConfigException {
|
||||
super(field, configuration, category, Property.Type.STRING);
|
||||
pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class))
|
||||
.map((ptr) -> Pattern.compile(ptr.value()))
|
||||
.orElse(null);
|
||||
defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultStringList.class))
|
||||
.map(Config.DefaultStringList::value)
|
||||
.orElseGet(() -> {
|
||||
FalsePatternLib.getLog()
|
||||
.warn("The field " + field.getName() + " in class " +
|
||||
field.getDeclaringClass().getName() +
|
||||
" has no DefaultStringList annotation!\nThis will be a crash in FalsePatternLib 0.11, update your code!");
|
||||
try {
|
||||
return (String[]) field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
maxStringLength = Optional.ofNullable(field.getAnnotation(Config.StringMaxLength.class))
|
||||
.map(Config.StringMaxLength::value)
|
||||
.orElse(256);
|
||||
property.setDefaultValues(defaultValue);
|
||||
if (!property.isList()) {
|
||||
setToDefault();
|
||||
}
|
||||
property.comment += "\n[max string length: " + maxLength +
|
||||
(pattern != null ? ", pattern: \"" + pattern.pattern() + "\"" : "") + ", default: \"" +
|
||||
stringify(defaultValue) + "\"]";
|
||||
}
|
||||
|
||||
private static String stringify(String[] arr) {
|
||||
val result = new StringBuilder("[");
|
||||
if (arr.length > 0) {
|
||||
result.append('"').append(arr[0]).append('"');
|
||||
for (int i = 1; i < arr.length; i++) {
|
||||
result.append(", \"").append(arr[i]).append('"');
|
||||
}
|
||||
}
|
||||
return result.append(']').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int length(String[] arr) {
|
||||
return arr.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] arrayCopy(String[] arr) {
|
||||
return Arrays.copyOf(arr, arr.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void transmitElements(DataOutput output, String[] arr) throws IOException {
|
||||
for (val str : arr) {
|
||||
StringConfigField.transmitString(output, str);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receiveElements(DataInput input, String[] arr) throws IOException {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = StringConfigField.receiveString(input, maxStringLength, field.getName(),
|
||||
field.getDeclaringClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateField() {
|
||||
if (!super.validateField()) {
|
||||
return false;
|
||||
}
|
||||
String[] strings = getField();
|
||||
boolean valid = true;
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
String str = strings[i];
|
||||
if (!StringConfigField.validateString(str, maxStringLength, pattern, field, i)) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] createArray(int length) {
|
||||
return new String[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getConfig() {
|
||||
return property.getStringList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putConfig(String[] value) {
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getDefault() {
|
||||
return Arrays.copyOf(defaultValue, defaultValue.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.val;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public abstract class CompressedMessage implements IMessage {
|
||||
private byte[] compressed;
|
||||
|
||||
public CompressedMessage() {
|
||||
compressed = null;
|
||||
}
|
||||
|
||||
protected abstract void transmit(DataOutput output) throws IOException;
|
||||
|
||||
protected abstract void receive(DataInput input) throws IOException;
|
||||
|
||||
public void transmit() throws IOException {
|
||||
val output = new ByteArrayOutputStream();
|
||||
val deflateOut = new DeflaterOutputStream(output, new Deflater(Deflater.BEST_COMPRESSION, false));
|
||||
val dataOut = new DataOutputStream(deflateOut);
|
||||
transmit(dataOut);
|
||||
dataOut.close();
|
||||
compressed = output.toByteArray();
|
||||
}
|
||||
|
||||
public void receive() throws IOException {
|
||||
val input = new ByteArrayInputStream(compressed);
|
||||
val deflateIn = new InflaterInputStream(input, new Inflater(false));
|
||||
val dataIn = new DataInputStream(deflateIn);
|
||||
receive(dataIn);
|
||||
dataIn.close();
|
||||
compressed = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
int length = buf.readInt();
|
||||
compressed = new byte[length];
|
||||
buf.readBytes(compressed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(compressed.length);
|
||||
buf.writeBytes(compressed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public class SyncPrompt implements IMessage {
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import com.falsepattern.lib.config.event.ConfigSyncRequestEvent;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
public class SyncPromptHandler implements IMessageHandler<SyncPrompt, IMessage> {
|
||||
@Override
|
||||
public IMessage onMessage(SyncPrompt message, MessageContext ctx) {
|
||||
if (ctx.side == Side.CLIENT) {
|
||||
ConfigSyncRequestEvent.postClient();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import com.falsepattern.lib.internal.impl.config.ConfigurationManagerImpl;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class SyncReply extends CompressedMessage {
|
||||
public List<Class<?>> matchingClassesOnOurSide;
|
||||
|
||||
@Override
|
||||
protected void transmit(DataOutput output) throws IOException {
|
||||
ConfigurationManagerImpl.sendReply(output, matchingClassesOnOurSide);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receive(DataInput input) throws IOException {
|
||||
ConfigurationManagerImpl.receiveReply(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SyncReplyHandler implements IMessageHandler<SyncReply, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(SyncReply message, MessageContext ctx) {
|
||||
if (ctx.side == Side.SERVER) {
|
||||
//Do not sync client to server
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
message.receive();
|
||||
} catch (IOException e) {
|
||||
FalsePatternLib.getLog().error("Failed to sync config", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import com.falsepattern.lib.internal.impl.config.ConfigurationManagerImpl;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class SyncRequest extends CompressedMessage {
|
||||
public List<Class<?>> matchingClassesOnOurSide;
|
||||
|
||||
@Override
|
||||
protected void transmit(DataOutput output) throws IOException {
|
||||
ConfigurationManagerImpl.sendRequest(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receive(DataInput input) throws IOException {
|
||||
matchingClassesOnOurSide = ConfigurationManagerImpl.receiveRequest(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (C) 2022 FalsePattern
|
||||
* All Rights Reserved
|
||||
* <p>
|
||||
* The above copyright notice, this permission notice and the word "SNEED"
|
||||
* shall be included in all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* This program 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* <p>
|
||||
* This program 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 General Public License for more details.
|
||||
* <p>
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.falsepattern.lib.internal.impl.config.net;
|
||||
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import lombok.val;
|
||||
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SyncRequestHandler implements IMessageHandler<SyncRequest, IMessage> {
|
||||
@Override
|
||||
public IMessage onMessage(SyncRequest message, MessageContext ctx) {
|
||||
if (ctx.side == Side.CLIENT) {
|
||||
//Do not sync client to server
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
message.receive();
|
||||
val reply = new SyncReply();
|
||||
reply.matchingClassesOnOurSide = message.matchingClassesOnOurSide;
|
||||
reply.transmit();
|
||||
FalsePatternLib.NETWORK.sendTo(reply, ctx.getServerHandler().playerEntity);
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
FalsePatternLib.getLog().error("Failed to sync config", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,15 @@
|
||||
*/
|
||||
package com.falsepattern.lib.internal.proxy;
|
||||
|
||||
import com.falsepattern.lib.config.ConfigException;
|
||||
import com.falsepattern.lib.config.ConfigurationManager;
|
||||
import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.internal.Tags;
|
||||
import com.falsepattern.lib.internal.config.ToastConfig;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncPrompt;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncPromptHandler;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncReply;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncReplyHandler;
|
||||
import com.falsepattern.lib.internal.impl.toast.GuiToastImpl;
|
||||
import com.falsepattern.lib.updates.UpdateChecker;
|
||||
import lombok.val;
|
||||
@@ -55,6 +62,11 @@ public class ClientProxy extends CommonProxy {
|
||||
@Override
|
||||
public void preInit(FMLPreInitializationEvent e) {
|
||||
super.preInit(e);
|
||||
try {
|
||||
ConfigurationManager.initialize(ToastConfig.class);
|
||||
} catch (ConfigException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,20 @@ import com.falsepattern.lib.internal.FalsePatternLib;
|
||||
import com.falsepattern.lib.internal.config.LibraryConfig;
|
||||
import com.falsepattern.lib.internal.config.ToastConfig;
|
||||
import com.falsepattern.lib.internal.impl.config.ConfigurationManagerImpl;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncPrompt;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncPromptHandler;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncReply;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncReplyHandler;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncRequest;
|
||||
import com.falsepattern.lib.internal.impl.config.net.SyncRequestHandler;
|
||||
import com.falsepattern.lib.updates.ModUpdateInfo;
|
||||
import com.falsepattern.lib.updates.UpdateChecker;
|
||||
|
||||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
|
||||
import lombok.val;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -43,15 +51,17 @@ public class CommonProxy {
|
||||
protected CompletableFuture<List<ModUpdateInfo>> updatesFuture;
|
||||
|
||||
public void construct(FMLConstructionEvent e) {
|
||||
FalsePatternLib.NETWORK.registerMessage(SyncRequestHandler.class, SyncRequest.class, 0, Side.SERVER);
|
||||
FalsePatternLib.NETWORK.registerMessage(SyncReplyHandler.class, SyncReply.class, 1, Side.CLIENT);
|
||||
FalsePatternLib.NETWORK.registerMessage(SyncPromptHandler.class, SyncPrompt.class, 2, Side.CLIENT);
|
||||
}
|
||||
|
||||
public void preInit(FMLPreInitializationEvent e) {
|
||||
ConfigurationManagerImpl.registerBus();
|
||||
try {
|
||||
ConfigurationManager.registerConfig(LibraryConfig.class);
|
||||
ConfigurationManager.registerConfig(ToastConfig.class);
|
||||
ConfigurationManager.initialize(LibraryConfig.class);
|
||||
} catch (ConfigException ex) {
|
||||
FalsePatternLib.getLog().error("Failed to register config!", ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
if (LibraryConfig.ENABLE_UPDATE_CHECKER) {
|
||||
FalsePatternLib.getLog().info("Launching asynchronous update check.");
|
||||
|
||||
@@ -4,6 +4,8 @@ config.falsepatternlib.toastoffset=Toast Y Offset
|
||||
config.falsepatternlib.toastoffset.tooltip=The amount of empty space from the top of the screen in pixels
|
||||
config.falsepatternlib.toastalign=Toast Alignment
|
||||
config.falsepatternlib.toastalign.tooltip=Which side of the screen should toasts show up on
|
||||
config.falsepatternlib.configlogging=Config error loudness
|
||||
config.falsepatternlib.configlogging.tooltip=How loud the config error logging should be. None disables all built-in config validation error logging
|
||||
config.falsepatternlib.updatecheck=Enable update checks
|
||||
config.falsepatternlib.updatecheck.tooltip=Used to control whether FalsePatternLib should check for outdated mods.
|
||||
config.falsepatternlib.disableinternet=FalsePatternLib Offline Mode
|
||||
|
||||
Reference in new issue
Block a user