)new EnumPropertyContainer(property.value(), property.description(), handleGetter, handleSetter, handleListener);
+ }
+ else {
+ return new FieldPropertyContainer<>(property.value(), property.description(), handleGetter, handleSetter, handleListener);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/annotation/Property.java b/src/main/java/fr/shyrogan/swiftbird/annotation/Property.java
new file mode 100644
index 0000000..cde2506
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/annotation/Property.java
@@ -0,0 +1,28 @@
+package fr.shyrogan.swiftbird.annotation;
+
+import com.leafclient.swiftbird.PropertyContainer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a {@link java.lang.reflect.Field} to allow {@link com.leafclient.swiftbird.Swiftbird} to wrap it into a
+ * {@link PropertyContainer}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Property {
+
+ /**
+ * @return the label of the {@link PropertyContainer} marked by this annotation.
+ */
+ String value();
+
+ /**
+ * @return the description of the {@link PropertyContainer} marked by this annotation.
+ */
+ String description() default "";
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/annotation/listener/Listener.java b/src/main/java/fr/shyrogan/swiftbird/annotation/listener/Listener.java
new file mode 100644
index 0000000..144e744
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/annotation/listener/Listener.java
@@ -0,0 +1,27 @@
+package fr.shyrogan.swiftbird.annotation.listener;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used by {@link com.leafclient.swiftbird.Swiftbird} to specify a property listener.
+ *
+ *
+ * A property listener respect this form (T represent our property type):
+ * T listenerName(T previousValue, T futureValue)
+ * The returned value allows the listener to change the future value.
+ *
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Listener {
+
+ /**
+ * @return listener method's name
+ * @see Listener
+ */
+ String value();
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/annotation/number/Clamp.java b/src/main/java/fr/shyrogan/swiftbird/annotation/number/Clamp.java
new file mode 100644
index 0000000..f3cae4d
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/annotation/number/Clamp.java
@@ -0,0 +1,28 @@
+package fr.shyrogan.swiftbird.annotation.number;
+
+import com.leafclient.swiftbird.PropertyContainer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a {@link fr.shyrogan.swiftbird.annotation.Property} annotated field to provide a minimum
+ * and maximum value to that property. This only works with primitive numbers.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Clamp {
+
+ /**
+ * @return the minimum value of marked property
+ */
+ double minimum();
+
+ /**
+ * @return the maximum value of marked property
+ */
+ double maximum();
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/annotation/number/Increment.java b/src/main/java/fr/shyrogan/swiftbird/annotation/number/Increment.java
new file mode 100644
index 0000000..84a93a7
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/annotation/number/Increment.java
@@ -0,0 +1,23 @@
+package fr.shyrogan.swiftbird.annotation.number;
+
+import com.leafclient.swiftbird.PropertyContainer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a {@link fr.shyrogan.swiftbird.annotation.Property} annotated field to provide a step value to this property.
+ * This only works with primitive numbers.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Increment {
+
+ /**
+ * @return the step value of marked property
+ */
+ double value();
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/setting/FieldPropertyContainer.java b/src/main/java/fr/shyrogan/swiftbird/setting/FieldPropertyContainer.java
new file mode 100644
index 0000000..48e0d30
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/setting/FieldPropertyContainer.java
@@ -0,0 +1,69 @@
+package fr.shyrogan.swiftbird.setting;
+
+import com.leafclient.swiftbird.PropertyContainer;
+
+import java.lang.invoke.MethodHandle;
+
+@SuppressWarnings("unchecked")
+public class FieldPropertyContainer implements PropertyContainer {
+
+ private final String label, description;
+ private transient final MethodHandle valueGetter, valueSetter, listener;
+
+ public FieldPropertyContainer(String label, String description, MethodHandle valueGetter, MethodHandle valueSetter, MethodHandle listener) {
+ this.label = label;
+ this.description = description;
+ this.valueGetter = valueGetter;
+ this.valueSetter = valueSetter;
+ this.listener = listener;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Returns the current value of this {@link PropertyContainer} by getting using the {@link this#valueGetter}.
+ *
+ * @return Current value
+ */
+ @Override
+ public T getValue() {
+ try {
+ return (T) valueGetter.invoke();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Modifies the value of the field using the {@link this#valueSetter}
+ * @param value New value
+ *
+ * @return This setting for fluent syntax
+ */
+ @Override
+ public void setValue(T value) {
+ try {
+ if(listener != null)
+ valueSetter.invoke((T) listener.invoke(getValue(), value));
+ else
+ valueSetter.invoke(value);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/setting/number/NumberPropertyContainer.java b/src/main/java/fr/shyrogan/swiftbird/setting/number/NumberPropertyContainer.java
new file mode 100644
index 0000000..0e7a522
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/setting/number/NumberPropertyContainer.java
@@ -0,0 +1,83 @@
+package fr.shyrogan.swiftbird.setting.number;
+
+import com.leafclient.struct.maths.Range;
+import fr.shyrogan.swiftbird.setting.FieldPropertyContainer;
+
+import java.lang.invoke.MethodHandle;
+
+import static com.leafclient.struct.maths.MathOperationsHelper.add;
+import static com.leafclient.struct.maths.MathOperationsHelper.round;
+import static com.leafclient.struct.maths.MathOperationsHelper.multiplication;
+import static com.leafclient.struct.maths.MathOperationsHelper.cast;
+
+public final class NumberPropertyContainer extends FieldPropertyContainer {
+
+ private final Range range;
+ private final T step;
+
+ public NumberPropertyContainer(String label, String description, Range range, T step, MethodHandle valueGetter, MethodHandle valueSetter, MethodHandle listener) {
+ super(label, description, valueGetter, valueSetter, listener);
+ this.range = range;
+ this.step = step;
+ }
+
+ /**
+ * Sets the value to a value coerced into {@link this#range} stepped
+ * to {@link this#step}
+ *
+ * @param value New value
+ * @return Setting for a fluent syntax
+ */
+ @Override
+ public void setValue(T value) {
+ super.setValue(range.coerce(round(value, step)));
+ }
+
+ /**
+ * Increases the current value by {@link this#step} * factor.
+ * If the value has no step value this operation is not supported
+ * @see fr.shyrogan.swiftbird.annotation.number.Increment
+ *
+ * @param factor Specified factor
+ */
+ public void increment(int factor) {
+ if(step == null)
+ return;
+
+ setValue(
+ add(
+ getValue(),
+ multiplication(
+ step,
+ cast(factor, getValue())
+ )
+ )
+ );
+ }
+
+ /**
+ * Decreases the current value by {@link this#step} * factor.
+ * If the value has no step value this operation is not supported.
+ * @see fr.shyrogan.swiftbird.annotation.number.Increment
+ *
+ * @param factor Specified factor
+ */
+ public void reduce(int factor) {
+ increment(-factor);
+ }
+
+ /**
+ * @return `true` if this value is not clamped
+ */
+ public boolean isIncrementable() {
+ return step != null;
+ }
+
+ /**
+ * @return `true` if this value is not clamped
+ */
+ public boolean isInfinite() {
+ return range == null;
+ }
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/setting/primitive/BooleanPropertyContainer.java b/src/main/java/fr/shyrogan/swiftbird/setting/primitive/BooleanPropertyContainer.java
new file mode 100644
index 0000000..ef5a929
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/setting/primitive/BooleanPropertyContainer.java
@@ -0,0 +1,35 @@
+package fr.shyrogan.swiftbird.setting.primitive;
+
+import com.leafclient.struct.structure.Toggleable;
+import fr.shyrogan.swiftbird.setting.FieldPropertyContainer;
+
+import java.lang.invoke.MethodHandle;
+
+/**
+ * The boolean implementation for {@link FieldPropertyContainer}.
+ */
+public final class BooleanPropertyContainer extends FieldPropertyContainer implements Toggleable {
+
+ public BooleanPropertyContainer(String label, String description, MethodHandle valueGetter, MethodHandle valueSetter, MethodHandle listener) {
+ super(label, description, valueGetter, valueSetter, listener);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean isRunning() {
+ return getValue();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void setRunning(boolean value) {
+ setValue(value);
+ }
+
+
+
+}
diff --git a/src/main/java/fr/shyrogan/swiftbird/setting/primitive/EnumPropertyContainer.java b/src/main/java/fr/shyrogan/swiftbird/setting/primitive/EnumPropertyContainer.java
new file mode 100644
index 0000000..0203dec
--- /dev/null
+++ b/src/main/java/fr/shyrogan/swiftbird/setting/primitive/EnumPropertyContainer.java
@@ -0,0 +1,27 @@
+package fr.shyrogan.swiftbird.setting.primitive;
+
+import fr.shyrogan.swiftbird.setting.FieldPropertyContainer;
+
+import java.lang.invoke.MethodHandle;
+
+/**
+ * The enum implementation for {@link FieldPropertyContainer}.
+ */
+@SuppressWarnings("unchecked")
+public final class EnumPropertyContainer> extends FieldPropertyContainer {
+
+ public EnumPropertyContainer(String label, String description, MethodHandle valueGetter, MethodHandle valueSetter, MethodHandle listener) {
+ super(label, description, valueGetter, valueSetter, listener);
+ }
+
+ /**
+ * Returns the enum constants of this value
+ *
+ * @return Enum constants
+ */
+ public T[] getEnumConstants() {
+ return (T[])getValue().getClass()
+ .getEnumConstants();
+ }
+
+}
diff --git a/src/test/java/ConfigurableObject.java b/src/test/java/ConfigurableObject.java
new file mode 100644
index 0000000..656ae2f
--- /dev/null
+++ b/src/test/java/ConfigurableObject.java
@@ -0,0 +1,29 @@
+import fr.shyrogan.swiftbird.annotation.Property;
+import fr.shyrogan.swiftbird.annotation.listener.Listener;
+import fr.shyrogan.swiftbird.annotation.number.Clamp;
+
+public class ConfigurableObject {
+
+ @Property(value = "Cheese", description = "Do you like jazz?")
+ private boolean cheese = false;
+
+ @Property(value = "Name", description = "IDK")
+ @Listener("onChange")
+ private Result value = Result.PERFECT;
+
+ @Property("Uh")
+ @Clamp(minimum = 0F, maximum = 50F)
+ private float uh = 6F;
+
+ public Result onChange(Result current, Result future) {
+ System.out.println("current: " + current);
+ System.out.println("future: " + future);
+ return future;
+ }
+
+ public enum Result {
+ PERFECT,
+ UH_OH;
+ }
+
+}
diff --git a/src/test/java/Settings.java b/src/test/java/Settings.java
new file mode 100644
index 0000000..f4e159f
--- /dev/null
+++ b/src/test/java/Settings.java
@@ -0,0 +1,15 @@
+import com.leafclient.swiftbird.Swiftbird;
+import org.junit.Test;
+
+public class Settings {
+
+ private static Swiftbird swiftbird = Swiftbird.create();
+ private static ConfigurableObject configurableObject = new ConfigurableObject();
+
+ @Test
+ public void simpleLookUp() {
+ swiftbird.in(configurableObject)
+ .forEach(setting -> System.out.println(setting.getLabel() + " " + setting.getValue()));
+ }
+
+}