Skip to content

Commit

Permalink
Make the Comp annotation easier to use (#236)
Browse files Browse the repository at this point in the history
* place key directly in enum

* convert comp

* convert old format into new comp format

* convert requirement into unique on comp

* join via serial comma

* rename method to parseComparisonRequirements

* convert unique to lang keys, improve quality

* remove default values from comp

* ensure text isnt empty before adding

* allow removing types and provide examples

* remove types in valid situations

* remove use of Integer.MAX_VALUE in comp

* adjust magmatic smeltery text

* move used types to enum

* increase javadocs for Comp

* remove unneeded types arrays

* change default value to not be 0

* get first used type instead of just "first"

* update new compat with new comp elements

* convert deprecated elements of recent pyrotech

* update examples file for prodigytech
  • Loading branch information
WaitingIdly authored Oct 3, 2024
1 parent a536e88 commit 6134afe
Show file tree
Hide file tree
Showing 311 changed files with 1,225 additions and 1,021 deletions.
4 changes: 2 additions & 2 deletions examples/postInit/prodigytech.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ mods.prodigytech.explosion_furnace.recipeBuilder()
// Explosion Furnace Additives:
// Turn an item into an explosive or into a dampener when inserted into the Explosion Furnace.

// mods.prodigytech.explosion_furnace_additives.removeAllDampeners()
// mods.prodigytech.explosion_furnace_additives.removeAllExplosives()
mods.prodigytech.explosion_furnace_additives.removeDampener(ore('dustAsh'))
mods.prodigytech.explosion_furnace_additives.removeExplosive(ore('gunpowder'))
// mods.prodigytech.explosion_furnace_additives.removeAllDampeners()
// mods.prodigytech.explosion_furnace_additives.removeAllExplosives()

mods.prodigytech.explosion_furnace_additives.addDampener(item('minecraft:stone'), 50)
mods.prodigytech.explosion_furnace_additives.addExplosive(item('minecraft:cobblestone'), 50)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,102 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.EnumSet;

/**
* Used by {@link Property Properties} to determine what are valid values for the {@link Property}.
* Frequently used in an array containing two entries, indicating minimum and maximum bounds.
* Used for comparisons by {@link Property Properties} to determine what are valid values for the {@link Property}.
* <p>
* Fully written out, it uses the array {@link #types()} to store the types being tracked,
* and the corresponding element to store what the value being compared against is.
* <p>
* However, to improve the ease of use, some information can be assumed by default and are thus optional.
* <p>
* If {@link #types()} is empty, elements that do not match the default value will be checked.
* This means that in most cases {@link #types()} does not need to be declared.
* <br>
* The only exception is if any of {@link #gt()}, {@link #gte()}, {@link #eq()}, {@link #lte()}, {@link #lt()},
* {@link #not()}, or {@link #unique()} elements match the default value,
* which is {@link Integer#MIN_VALUE} for the {@link #gt()}, {@link #gte()}, {@link #eq()}, {@link #lte()}, and {@link #lt()} elements and
* an empty string ({@code ""}) for both {@link #not()} and {@link #unique()} elements.
* In this situation, {@link #types()} will need to contain all relevant {@link Type Types}.
*
* @see Property#valid()
* @see Property#comp()
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ /* No targets allowed */})
public @interface Comp {

/**
* @return the method of comparison
* @deprecated use {@link #types()} instead
*/
@Deprecated
Type type() default Type.EQ;

/**
* @return the value that {@link #type()} compares with
* @deprecated use {@link #lt()}, {@link #lte()}, {@link #gte()}, {@link #gt()}, {@link #eq()}, {@link #not()}, or {@link #unique()} instead
*/
String value();
@Deprecated
String value() default "";

/**
* @return an array of types to compare with. In most cases, this can be assumed.
*/
Type[] types() default {};

/**
* The value represent less than.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#LT} to the {@link #types()} element.
*
* @return if enabled, the value used to represent less than
*/
int lt() default Integer.MIN_VALUE;

/**
* The value represent less than or equal to.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#LTE} to the {@link #types()} element.
*
* @return if enabled, the value used to represent less than or equal to
*/
int lte() default Integer.MIN_VALUE;

/**
* The value represent greater than or equal to.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#GTE} to the {@link #types()} element.
*
* @return if enabled, the value used to represent greater than or equal to
*/
int gte() default Integer.MIN_VALUE;

/**
* The value represent greater than.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#GT} to the {@link #types()} element.
*
* @return if enabled, the value used to represent greater than
*/
int gt() default Integer.MIN_VALUE;

/**
* The value represent equal to.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#EQ} to the {@link #types()} element.
*
* @return if enabled, the value used to represent equal to
*/
int eq() default Integer.MIN_VALUE;

/**
* The value represent not equal to.
* Enabled either via being set to a non-default value, or by adding {@link Comp.Type#NOT} to the {@link #types()} element.
*
* @return if enabled, the value used to represent not equal to
*/
String not() default "";

/**
* @return if {@link #types()} contains {@link Comp.Type#UNI}, the lang key used to represent the unique description
*/
String unique() default "";

/**
* Used to determine the type of comparison. Contains a symbol representation and a localization key.
Expand Down Expand Up @@ -63,24 +139,49 @@
* <th>!=</th>
* <th>groovyscript.wiki.not</th>
* </tr>
* <tr>
* <th>UNI</th>
* <th>!?</th>
* <th>groovyscript.wiki.unique</th>
* </tr>
* </table>
*/
enum Type {
GT(">", "greater_than"),
GTE(">=", "greater_than_or_equal_to"),
EQ("==", "equal_to"),
LTE("<=", "less_than_or_equal_to"),
LT("<", "less_than"),
NOT("!=", "not");

private static final String baseLocalizationPath = "groovyscript.wiki.";
GT(">", "groovyscript.wiki.greater_than"),
GTE(">=", "groovyscript.wiki.greater_than_or_equal_to"),
EQ("==", "groovyscript.wiki.equal_to"),
LTE("<=", "groovyscript.wiki.less_than_or_equal_to"),
LT("<", "groovyscript.wiki.less_than"),
NOT("!=", "groovyscript.wiki.not"),
UNI("!?", "groovyscript.wiki.unique");

private final String symbol;
private final String key;

Type(String symbol, String key) {
this.symbol = symbol;
this.key = baseLocalizationPath + key;
this.key = key;
}

/**
* Creates an EnumSet based on the given {@link Comp}.
* If {@link Comp#types()} has any elements, the types contained will be used.
* Otherwise, any non-default values for the individual elements will be used.
*
* @param comp the {@link Comp} instance to be parsed
* @return a set containing the types that are used in the Comp
*/
public static EnumSet<Type> getUsedTypes(Comp comp) {
if (comp.types().length > 0) return EnumSet.of(comp.types()[0], comp.types());
var usedTypes = EnumSet.noneOf(Comp.Type.class);
if (comp.gt() != Integer.MIN_VALUE) usedTypes.add(Comp.Type.GT);
if (comp.gte() != Integer.MIN_VALUE) usedTypes.add(Comp.Type.GTE);
if (comp.eq() != Integer.MIN_VALUE) usedTypes.add(Comp.Type.EQ);
if (comp.lte() != Integer.MIN_VALUE) usedTypes.add(Comp.Type.LTE);
if (comp.lt() != Integer.MIN_VALUE) usedTypes.add(Comp.Type.LT);
if (!comp.not().isEmpty()) usedTypes.add(Comp.Type.NOT);
if (!comp.unique().isEmpty()) usedTypes.add(Comp.Type.UNI);
return usedTypes;
}

public String getSymbol() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
* </li>
* <li>{@link #property()} either contains nothing if {@link Property} was created attached to a field, or the relevant {@link Field#getName()} string.</li>
* <li>{@link #defaultValue()} a string containing the default value of the property. If empty, defaults to {@code null}.</li>
* <li>{@link #valid()} is an array of {@link Comp} that indicates the requirements of the {@link Property} to pass validation.</li>
* <li>{@link #requirement()} is a localization key that states the requirements for the property to pass validation provided the requirements are too
* complex to represent via {@link #valid()}.</li>
* <li>{@link #comp()} is a {@link Comp} that indicates the requirements of the {@link Property} to pass validation.</li>
* <li>{@link #ignoresInheritedMethods()} if this {@link Property} annotation requires any methods targeting the {@link Property} to not be inherited methods.</li>
* <li>{@link #needsOverride()} if this {@link Property} annotation needs another {@link Property} annotation with this element set to {@code true} to function.
* Used in wrapper classes, such as {@link com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder AbstractRecipeBuilder}, where some or all of the fields may not be needed in subclasses.</li>
Expand Down Expand Up @@ -79,48 +77,107 @@
String defaultValue() default "";

/**
* The primary way to document properties, supplemented by {@link #requirement()}.
* @deprecated {@link #comp()}
*/
@Deprecated
Comp[] valid() default {};

/**
* The primary way to document properties.
* The three main ways this element is used is to refer to:
* <br>- a number: Would indicate comparing directly against the number.
* <br>- an array or list: Would indicate comparing against the length of the array/list.
* <br>- another object: Would use to indicate {@code not null} is required.
* <p>
* In almost all cases, the {@link Comp#types()} element can be assumed due to the values of the desired
* elements being set to a non-default value. For the int elements, the default value is {@link Integer#MIN_VALUE},
* and for the String elements, the default value is an empty string.
* <p>
* Here is a quick shortcut table to better understand what the logic is:
*
* <table>
* <tr>
* <th>validation</th>
* <th>code</th>
* <th>logic</th>
* </tr>
* <tr>
* <td><code>N/A</code></td>
* <td><code>@Comp</code></td>
* <td>no validation is applied</td>
* </tr>
* <tr>
* <td><code>x == 1</code></td>
* <td><code>valid = @Comp("1")</code></td>
* <td><code>@Comp({@link Comp#types types} = {@link Comp.Type#EQ EQ}, {@link Comp#eq eq} = 1)</code></td>
* <td>types checks eq, eq is set to 1</td>
* </tr>
* <tr>
* <td><code>x != 1</code></td>
* <td><code>valid = @Comp(value = "1", type = Comp.Type.NOT)</code></td>
* <td><code>x == 1</code></td>
* <td><code>@Comp({@link Comp#eq eq} = 1)</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>x != null</code></td>
* <td><code>valid = @Comp(value = "null", type = Comp.Type.NOT)</code></td>
* <td><code>x > 0</code></td>
* <td><code>@Comp({@link Comp#types types} = {@link Comp.Type#GT GT}, {@link Comp#gt gt} = 0)</code></td>
* <td>types checks gt, gt is set to 0</td>
* </tr>
* <tr>
* <td><code>x > 0</code></td>
* <td><code>valid = @Comp(value = "0", type = Comp.Type.GT)</code></td>
* <td><code>@Comp({@link Comp#gt gt} = 0)</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>x >= 0</code></td>
* <td><code>@Comp({@link Comp#types types} = {@link Comp.Type#GTE GTE}, {@link Comp#gte gte} = 0)</code></td>
* <td>types checks gte, gte is set to 0</td>
* </tr>
* <tr>
* <td><code>x != 1</code></td>
* <td><code>@Comp({@link Comp#types types} = {@link Comp.Type#NOT NOT}, {@link Comp#not not} = "1")</code></td>
* <td>types checks not, not is set to "1"</td>
* </tr>
* <tr>
* <td><code>x != null</code></td>
* <td><code>@Comp({@link Comp#not not} = "null")</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>x >= 0 && x <= 5</code></td>
* <td><code>valid = {{@literal @}Comp(value = "0", type = Comp.Type.GTE), @Comp(value = "5", type = Comp.Type.LTE)}</code></td>
* <td><code>@Comp({@link Comp#types types} = {{@link Comp.Type#GTE GTE}, {@link Comp.Type#LTE LTE}}, {@link Comp#gte gte} = 0, {@link Comp#lte lte} = 5)</code></td>
* <td>types checks gte and lte, gte is set to 0 and lte is set to 5</td>
* </tr>
* <tr>
* <td><code>x > 0 && x <= 2</code></td>
* <td><code>@Comp({@link Comp#gt gt} = 0, {@link Comp#lte lte} = 2)</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>complex logic</code></td>
* <td><code>@Comp({@link Comp#unique unique} = "complex logic")</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>x >= 0 && complex logic</code></td>
* <td><code>@Comp({@link Comp#gte gte} = 0, {@link Comp#unique unique} = "complex logic")</code></td>
* <td>^1</td>
* </tr>
* <tr>
* <td><code>x >= 1 && x <= 9 && complex logic</code></td>
* <td><code>@Comp({@link Comp#gte gte} = 1, {@link Comp#lte lte} = 9, {@link Comp#unique unique} = "complex logic")</code></td>
* <td>^1</td>
* </tr>
* </table>
*
* @return an array of {@link Comp} entries indicating valid values for the property to be.
* ^1 = if types is empty, any non-default values are used
*
* @return a {@link Comp} indicating valid values for the property to be.
*/
Comp[] valid() default {};
Comp comp() default @Comp;

/**
* A localization key to declare validation requirements that are too complex to represent in {@link #valid()}.
*
* @return a string describing the valid value(s) for the field to be to pass validation
* @deprecated use {@link #comp()} instead, via {@code @Comp(types = Comp.Type.UNI, unique = "lang-key-here")}
*/
@Deprecated
String requirement() default "";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ public boolean removeByOutput(ItemStack output) {
});
}

@Property(property = "input", valid = @Comp("1"))
@Property(property = "output", valid = @Comp("1"))
@Property(property = "input", comp = @Comp(eq = 1))
@Property(property = "output", comp = @Comp(eq = 1))
public static class RecipeBuilder extends AbstractRecipeBuilder<LensConversionRecipe> {

@Property(defaultValue = "1", valid = @Comp(type = Comp.Type.GT, value = "0"))
@Property(defaultValue = "1", comp = @Comp(gt = 0))
private int energyUse = 1;
@Property(defaultValue = "ActuallyAdditionsAPI.lensDefaultConversion", valid = @Comp(value = "null", type = Comp.Type.NOT))
@Property(defaultValue = "ActuallyAdditionsAPI.lensDefaultConversion", comp = @Comp(not = "null"))
private Lens type = ActuallyAdditionsAPI.lensDefaultConversion;

@RecipeBuilderMethodDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public boolean removeByOutput(ItemStack output) {
});
}

@Property(property = "output", valid = @Comp("1"))
@Property(property = "output", comp = @Comp(eq = 1))
public static class RecipeBuilder extends AbstractRecipeBuilder<BallOfFurReturn> {

@Property(valid = @Comp(type = Comp.Type.GTE, value = "0"))
@Property(comp = @Comp(gte = 0))
private int weight;

@RecipeBuilderMethodDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ public boolean removeByOutput(ItemStack output) {
});
}

@Property(property = "input", valid = @Comp("1"))
@Property(property = "output", valid = @Comp("1"))
@Property(property = "input", comp = @Comp(eq = 1))
@Property(property = "output", comp = @Comp(eq = 1))
public static class RecipeBuilder extends AbstractRecipeBuilder<CompostRecipe> {

@Property(property = "inputDisplay", valid = @Comp(type = Comp.Type.NOT, value = "null"))
@Property(property = "inputDisplay", comp = @Comp(not = "null"))
private IBlockState inputDisplay;
@Property(property = "outputDisplay", valid = @Comp(type = Comp.Type.NOT, value = "null"))
@Property(property = "outputDisplay", comp = @Comp(not = "null"))
private IBlockState outputDisplay;

@RecipeBuilderMethodDescription
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ public boolean removeByOutput(ItemStack output) {
});
}

@Property(property = "input", valid = @Comp("1"))
@Property(property = "output", valid = {@Comp(type = Comp.Type.GTE, value = "1"), @Comp(type = Comp.Type.LTE, value = "2")})
@Property(property = "input", comp = @Comp(eq = 1))
@Property(property = "output", comp = @Comp(gte = 1, lte = 2))
public static class RecipeBuilder extends AbstractRecipeBuilder<CrusherRecipe> {

@Property(valid = {@Comp(type = Comp.Type.GTE, value = "0"), @Comp(type = Comp.Type.LTE, value = "100")})
@Property(comp = @Comp(gte = 0, lte = 100))
private int chance;

@RecipeBuilderMethodDescription
Expand Down
Loading

0 comments on commit 6134afe

Please sign in to comment.