From 2c796090410af62210574cad5b86a37d5d4ddfdc Mon Sep 17 00:00:00 2001 From: Pablo Herrera Date: Fri, 1 Nov 2024 19:23:04 +0100 Subject: [PATCH] Support no-update structure placing (#1419) Signed-off-by: Pablo Herrera --- .../java/tc/oc/pgm/action/ActionParser.java | 4 +- .../tc/oc/pgm/action/actions/FillAction.java | 12 +++-- .../action/actions/PasteStructureAction.java | 11 ++-- .../ControlPointBlockDisplay.java | 32 +++++------ .../tc/oc/pgm/snapshot/BudgetWorldEdit.java | 8 +-- .../tc/oc/pgm/snapshot/WorldSnapshot.java | 8 +-- .../tc/oc/pgm/structure/DynamicStructure.java | 4 +- .../structure/DynamicStructureDefinition.java | 8 +++ .../java/tc/oc/pgm/structure/Structure.java | 13 +++-- .../tc/oc/pgm/structure/StructureModule.java | 44 +++++++-------- .../tc/oc/pgm/util/xml/XMLFluentParser.java | 45 +++++++++++++--- .../tc/oc/pgm/util/math/AddedFunctions.java | 49 +++++++++++++++++ .../java/tc/oc/pgm/util/math/Formula.java | 53 +++---------------- 13 files changed, 168 insertions(+), 123 deletions(-) create mode 100644 util/src/main/java/tc/oc/pgm/util/math/AddedFunctions.java diff --git a/core/src/main/java/tc/oc/pgm/action/ActionParser.java b/core/src/main/java/tc/oc/pgm/action/ActionParser.java index 298bddeb42..056887bd2d 100644 --- a/core/src/main/java/tc/oc/pgm/action/ActionParser.java +++ b/core/src/main/java/tc/oc/pgm/action/ActionParser.java @@ -368,6 +368,7 @@ public FillAction parseFill(Element el, Class scope) throws InvalidXMLExcepti parser.region(el, "region").blockBounded().orSelf(), XMLUtils.parseBlockMaterialData(Node.fromRequiredAttr(el, "material")), parser.filter(el, "filter").orNull(), + parser.parseBool(el, "update").orTrue(), parser.parseBool(el, "events").orFalse()); } @@ -414,7 +415,8 @@ public > PasteStructureAction parseStructure( var zFormula = parser.formula(scope, el, "z").required(); var structure = parser.reference(StructureDefinition.class, el, "structure").required(); + var update = parser.parseBool(el, "update").orTrue(); - return new PasteStructureAction<>(scope, xFormula, yFormula, zFormula, structure); + return new PasteStructureAction<>(scope, xFormula, yFormula, zFormula, structure, update); } } diff --git a/core/src/main/java/tc/oc/pgm/action/actions/FillAction.java b/core/src/main/java/tc/oc/pgm/action/actions/FillAction.java index f238ca00a8..d4c7752819 100644 --- a/core/src/main/java/tc/oc/pgm/action/actions/FillAction.java +++ b/core/src/main/java/tc/oc/pgm/action/actions/FillAction.java @@ -15,14 +15,20 @@ public class FillAction extends AbstractAction { private final Region region; private final BlockMaterialData materialData; private final @Nullable Filter filter; + private final boolean update; private final boolean events; public FillAction( - Region region, BlockMaterialData materialData, @Nullable Filter filter, boolean events) { + Region region, + BlockMaterialData materialData, + @Nullable Filter filter, + boolean update, + boolean events) { super(Match.class); this.region = region; this.materialData = materialData; this.filter = filter; + this.update = update; this.events = events; } @@ -32,7 +38,7 @@ public void trigger(Match match) { if (filter != null && filter.query(new BlockQuery(block)).isDenied()) continue; if (!events) { - materialData.applyTo(block, true); + materialData.applyTo(block, update); } else { BlockState newState = block.getState(); materialData.applyTo(newState); @@ -40,7 +46,7 @@ public void trigger(Match match) { BlockFormEvent event = new BlockFormEvent(block, newState); match.callEvent(event); if (event.isCancelled()) continue; - newState.update(true, true); + newState.update(true, update); } } } diff --git a/core/src/main/java/tc/oc/pgm/action/actions/PasteStructureAction.java b/core/src/main/java/tc/oc/pgm/action/actions/PasteStructureAction.java index e2e2175992..22bf992488 100644 --- a/core/src/main/java/tc/oc/pgm/action/actions/PasteStructureAction.java +++ b/core/src/main/java/tc/oc/pgm/action/actions/PasteStructureAction.java @@ -12,25 +12,26 @@ public class PasteStructureAction> extends AbstractActio private final Formula yformula; private final Formula zformula; private final FeatureReference structureReference; + private final boolean update; public PasteStructureAction( Class scope, Formula xformula, Formula yformula, Formula zformula, - FeatureReference structureReference) { + FeatureReference structureReference, + boolean update) { super(scope); this.xformula = xformula; this.yformula = yformula; this.zformula = zformula; this.structureReference = structureReference; + this.update = update; } @Override public void trigger(T t) { - BlockVector placeLocation = new BlockVector( - xformula.applyAsDouble(t), yformula.applyAsDouble(t), zformula.applyAsDouble(t)); - - structureReference.get().getStructure(t.getMatch()).placeAbsolute(placeLocation); + var loc = new BlockVector(xformula.apply(t), yformula.apply(t), zformula.apply(t)); + structureReference.get().getStructure(t.getMatch()).placeAbsolute(loc, update); } } diff --git a/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointBlockDisplay.java b/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointBlockDisplay.java index e258bf343a..774865cd3b 100644 --- a/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointBlockDisplay.java +++ b/core/src/main/java/tc/oc/pgm/controlpoint/ControlPointBlockDisplay.java @@ -46,26 +46,26 @@ public ControlPointBlockDisplay(Match match, ControlPoint controlPoint) { if (progressDisplayRegion == null) { this.progressDisplayRegion = null; } else { - this.progressDisplayRegion = - FiniteBlockRegion.fromWorld( - progressDisplayRegion, match.getWorld(), visualMaterials, match.getMap().getProto()); + this.progressDisplayRegion = FiniteBlockRegion.fromWorld( + progressDisplayRegion, + match.getWorld(), + visualMaterials, + match.getMap().getProto()); snapshot.saveRegion(progressDisplayRegion); } if (controllerDisplayRegion == null) { this.controllerDisplayRegion = null; } else { - Filter controllerDisplayFilter = - this.progressDisplayRegion == null - ? visualMaterials - : AllFilter.of(visualMaterials, new InverseFilter(progressDisplayRegion)); - - this.controllerDisplayRegion = - FiniteBlockRegion.fromWorld( - controllerDisplayRegion, - match.getWorld(), - controllerDisplayFilter, - match.getMap().getProto()); + Filter controllerDisplayFilter = this.progressDisplayRegion == null + ? visualMaterials + : AllFilter.of(visualMaterials, new InverseFilter(progressDisplayRegion)); + + this.controllerDisplayRegion = FiniteBlockRegion.fromWorld( + controllerDisplayRegion, + match.getWorld(), + controllerDisplayFilter, + match.getMap().getProto()); snapshot.saveRegion(controllerDisplayRegion); } } @@ -76,7 +76,7 @@ public ControlPointBlockDisplay(Match match, ControlPoint controlPoint) { public void setController(Competitor controllingTeam) { if (this.controllingTeam != controllingTeam && this.controllerDisplayRegion != null) { if (controllingTeam == null) { - snapshot.placeBlocks(this.controllerDisplayRegion, null); + snapshot.placeBlocks(this.controllerDisplayRegion, null, false); } else { COLOR_UTILS.setColor( match.getWorld(), @@ -97,7 +97,7 @@ private void setBlock(BlockVector pos, Competitor team) { if (team != null) { COLOR_UTILS.setColor(block, team.getDyeColor()); } else { - snapshot.getOriginalMaterial(pos).applyTo(block, true); + snapshot.getOriginalMaterial(pos).applyTo(block, false); } } } diff --git a/core/src/main/java/tc/oc/pgm/snapshot/BudgetWorldEdit.java b/core/src/main/java/tc/oc/pgm/snapshot/BudgetWorldEdit.java index f7575ac821..085a489709 100644 --- a/core/src/main/java/tc/oc/pgm/snapshot/BudgetWorldEdit.java +++ b/core/src/main/java/tc/oc/pgm/snapshot/BudgetWorldEdit.java @@ -29,10 +29,10 @@ class BudgetWorldEdit { * @param region region where the blocks were when they got saved * @param offset the offset to add when placing blocks */ - public void placeBlocks(Region region, BlockVector offset) { + public void placeBlocks(Region region, BlockVector offset, boolean update) { if (offset == null) offset = NO_OFFSET; for (BlockData blockData : snapshot.getMaterials(region)) { - blockData.applyTo(blockData.getBlock(world, offset), true); + blockData.applyTo(blockData.getBlock(world, offset), update); } } @@ -42,12 +42,12 @@ public void placeBlocks(Region region, BlockVector offset) { * @param region The region to remove blocks from * @param offset an offset to add to the region coordinates if the blocks were offset when placed */ - public void removeBlocks(Region region, BlockVector offset) { + public void removeBlocks(Region region, BlockVector offset, boolean update) { if (offset == null) offset = NO_OFFSET; for (BlockData blockData : snapshot.getMaterials(region)) { Block block = blockData.getBlock(world, offset); // Ignore if already air - if (!block.getType().equals(Material.AIR)) block.setType(Material.AIR); + if (!block.getType().equals(Material.AIR)) block.setType(Material.AIR, update); } } } diff --git a/core/src/main/java/tc/oc/pgm/snapshot/WorldSnapshot.java b/core/src/main/java/tc/oc/pgm/snapshot/WorldSnapshot.java index 955d1cf6fe..e897b81aa7 100644 --- a/core/src/main/java/tc/oc/pgm/snapshot/WorldSnapshot.java +++ b/core/src/main/java/tc/oc/pgm/snapshot/WorldSnapshot.java @@ -83,12 +83,12 @@ public void saveRegion(Region region) { region.getChunkPositions().forEach(cv -> this.saveSnapshot(cv, null)); } - public void placeBlocks(Region region, BlockVector offset) { - worldEdit.placeBlocks(region, offset); + public void placeBlocks(Region region, BlockVector offset, boolean update) { + worldEdit.placeBlocks(region, offset, update); } - public void removeBlocks(Region region, BlockVector offset) { - worldEdit.removeBlocks(region, offset); + public void removeBlocks(Region region, BlockVector offset, boolean update) { + worldEdit.removeBlocks(region, offset, update); } /** diff --git a/core/src/main/java/tc/oc/pgm/structure/DynamicStructure.java b/core/src/main/java/tc/oc/pgm/structure/DynamicStructure.java index 67fa1ef4cf..fd70d81a96 100644 --- a/core/src/main/java/tc/oc/pgm/structure/DynamicStructure.java +++ b/core/src/main/java/tc/oc/pgm/structure/DynamicStructure.java @@ -45,7 +45,7 @@ public DynamicStructureDefinition getDefinition() { public void place() { if (placed) return; placed = true; - structure.place(offset); + structure.place(offset, definition.shouldUpdate()); } /** Remove the structure from the world */ @@ -53,6 +53,6 @@ public void clear() { if (!placed) return; placed = false; - snapshot.placeBlocks(region, new BlockVector()); + snapshot.placeBlocks(region, new BlockVector(), definition.shouldUpdate()); } } diff --git a/core/src/main/java/tc/oc/pgm/structure/DynamicStructureDefinition.java b/core/src/main/java/tc/oc/pgm/structure/DynamicStructureDefinition.java index 1713c5d14f..c360341756 100644 --- a/core/src/main/java/tc/oc/pgm/structure/DynamicStructureDefinition.java +++ b/core/src/main/java/tc/oc/pgm/structure/DynamicStructureDefinition.java @@ -17,18 +17,21 @@ public class DynamicStructureDefinition extends SelfIdentifyingFeatureDefinition private final Filter passive; private final @Nullable BlockVector position; private final @NotNull BlockVector offset; + private final boolean update; DynamicStructureDefinition( String id, StructureDefinition structure, Filter trigger, Filter passive, + boolean update, @Nullable BlockVector position, @Nullable BlockVector offset) { super(id); this.structure = assertNotNull(structure); this.trigger = assertNotNull(trigger); this.passive = assertNotNull(passive); + this.update = update; this.position = position; this.offset = offset == null ? new BlockVector() : offset; } @@ -60,6 +63,11 @@ public Filter getPassive() { return passive; } + /** @return If this dynamic should generate block updates when placing */ + public boolean shouldUpdate() { + return update; + } + /** * The offset to use when placing/clearing the structure. Can not be used if the position * attribute is used. diff --git a/core/src/main/java/tc/oc/pgm/structure/Structure.java b/core/src/main/java/tc/oc/pgm/structure/Structure.java index 07fa8ad2ef..004cf961c3 100644 --- a/core/src/main/java/tc/oc/pgm/structure/Structure.java +++ b/core/src/main/java/tc/oc/pgm/structure/Structure.java @@ -2,7 +2,6 @@ import org.bukkit.Material; import org.bukkit.util.BlockVector; -import org.bukkit.util.Vector; import tc.oc.pgm.api.feature.Feature; import tc.oc.pgm.api.match.Match; import tc.oc.pgm.api.region.Region; @@ -28,7 +27,7 @@ public Structure(StructureDefinition definition, Match match, WorldSnapshot snap match.getMap().getProto()); snapshot.saveRegion(region); - if (definition.clearSource()) snapshot.removeBlocks(region, new BlockVector()); + if (definition.clearSource()) snapshot.removeBlocks(region, new BlockVector(), false); } @Override @@ -45,12 +44,12 @@ public Region getRegion() { return region; } - public void place(BlockVector offset) { - snapshot.placeBlocks(region, offset); + public void place(BlockVector offset, boolean update) { + snapshot.placeBlocks(region, offset, update); } - public void placeAbsolute(BlockVector vector) { - place(new BlockVector( - new Vector(0, 0, 0).subtract(getRegion().getBounds().getBlockMin()).add(vector))); + public void placeAbsolute(BlockVector vector, boolean update) { + vector.subtract(getRegion().getBounds().getBlockMin()); + place(vector, update); } } diff --git a/core/src/main/java/tc/oc/pgm/structure/StructureModule.java b/core/src/main/java/tc/oc/pgm/structure/StructureModule.java index 7c574f42a3..9364cf2107 100644 --- a/core/src/main/java/tc/oc/pgm/structure/StructureModule.java +++ b/core/src/main/java/tc/oc/pgm/structure/StructureModule.java @@ -9,7 +9,6 @@ import java.util.UUID; import java.util.logging.Logger; import org.bukkit.util.BlockVector; -import org.bukkit.util.Vector; import org.jdom2.Document; import org.jdom2.Element; import org.jetbrains.annotations.Nullable; @@ -23,14 +22,9 @@ import tc.oc.pgm.api.module.exception.ModuleLoadException; import tc.oc.pgm.filters.FilterMatchModule; import tc.oc.pgm.filters.matcher.StaticFilter; -import tc.oc.pgm.filters.parse.DynamicFilterValidation; -import tc.oc.pgm.filters.parse.FilterParser; -import tc.oc.pgm.regions.BlockBoundedValidation; -import tc.oc.pgm.regions.RegionParser; import tc.oc.pgm.snapshot.SnapshotMatchModule; import tc.oc.pgm.util.Version; import tc.oc.pgm.util.xml.InvalidXMLException; -import tc.oc.pgm.util.xml.Node; import tc.oc.pgm.util.xml.XMLUtils; public class StructureModule implements MapModule { @@ -65,18 +59,16 @@ public StructureModule parse(MapFactory factory, Logger logger, Document doc) Version proto = factory.getProto(); if (proto.isOlderThan(MapProtos.FILTER_FEATURES)) return null; - FilterParser filters = factory.getFilters(); - RegionParser regions = factory.getRegions(); + var parser = factory.getParser(); final Map structures = new HashMap<>(); for (Element el : XMLUtils.flattenElements(doc.getRootElement(), "structures", "structure")) { - final StructureDefinition definition = - new StructureDefinition( - XMLUtils.getRequiredAttribute(el, "id").getValue(), - XMLUtils.parseVector(el.getAttribute("origin"), (Vector) null), - regions.parseProperty(el, "region", BlockBoundedValidation.INSTANCE), - XMLUtils.parseBoolean(el.getAttribute("air"), false), - XMLUtils.parseBoolean(el.getAttribute("clear"), true)); + final StructureDefinition definition = new StructureDefinition( + parser.string(el, "id").attr().required(), + parser.vector(el, "origin").attr().orNull(), + parser.region(el, "region").blockBounded().required(), + parser.parseBool(el, "air").attr().orFalse(), + parser.parseBool(el, "clear").attr().orTrue()); structures.put(definition.getId(), definition); factory.getFeatures().addFeature(el, definition); @@ -84,31 +76,31 @@ public StructureModule parse(MapFactory factory, Logger logger, Document doc) final List dynamics = new ArrayList<>(); for (Element el : XMLUtils.flattenElements(doc.getRootElement(), "structures", "dynamic")) { - String id = el.getAttributeValue("id"); - if (id == null) id = UUID.randomUUID().toString(); + String id = + parser.string(el, "id").attr().optional(() -> UUID.randomUUID().toString()); - BlockVector position = XMLUtils.parseBlockVector(Node.fromAttr(el, "location")); - BlockVector offset = XMLUtils.parseBlockVector(Node.fromAttr(el, "offset")); + BlockVector position = parser.blockVector(el, "location").attr().orNull(); + BlockVector offset = parser.blockVector(el, "offset").attr().orNull(); if (position != null && offset != null) throw new InvalidXMLException( "attributes 'location' and 'offset' cannot be used together", el); - final StructureDefinition structure = - structures.get(XMLUtils.getRequiredAttribute(el, "structure").getValue()); + var structure = structures.get(parser.string(el, "structure").attr().required()); Filter trigger, filter; if (proto.isOlderThan(MapProtos.DYNAMIC_FILTERS)) { // Legacy maps use "filter" as their trigger - trigger = filters.parseRequiredProperty(el, "filter", DynamicFilterValidation.MATCH); + trigger = parser.filter(el, "filter").dynamic(Match.class).required(); filter = StaticFilter.ALLOW; } else { - trigger = filters.parseRequiredProperty(el, "trigger", DynamicFilterValidation.MATCH); - filter = filters.parseProperty(el, "filter", StaticFilter.ALLOW); + trigger = parser.filter(el, "trigger").dynamic(Match.class).required(); + filter = parser.filter(el, "filter").orAllow(); } + var update = parser.parseBool(el, "update").orTrue(); - DynamicStructureDefinition definition = - new DynamicStructureDefinition(id, structure, trigger, filter, position, offset); + DynamicStructureDefinition definition = new DynamicStructureDefinition( + id, structure, trigger, filter, update, position, offset); dynamics.add(definition); factory.getFeatures().addFeature(el, definition); } diff --git a/core/src/main/java/tc/oc/pgm/util/xml/XMLFluentParser.java b/core/src/main/java/tc/oc/pgm/util/xml/XMLFluentParser.java index 9e525ff0b5..0564fe1795 100644 --- a/core/src/main/java/tc/oc/pgm/util/xml/XMLFluentParser.java +++ b/core/src/main/java/tc/oc/pgm/util/xml/XMLFluentParser.java @@ -1,5 +1,7 @@ package tc.oc.pgm.util.xml; +import org.bukkit.util.BlockVector; +import org.bukkit.util.Vector; import org.jdom2.Element; import tc.oc.pgm.action.Action; import tc.oc.pgm.action.ActionParser; @@ -63,19 +65,46 @@ protected T parse(String text) throws TextException { }; } - public FilterBuilder filter(Element el, String... prop) throws InvalidXMLException { + public PrimitiveBuilder.Generic string(Element el, String... prop) { + return new PrimitiveBuilder.Generic<>(el, prop) { + @Override + protected String parse(String text) throws TextException { + return text; + } + }; + } + + public Builder.Generic vector(Element el, String... prop) { + return new Builder.Generic<>(el, prop) { + @Override + protected Vector parse(Node node) throws InvalidXMLException { + return XMLUtils.parseVector(node); + } + }; + } + + public Builder.Generic blockVector(Element el, String... prop) { + return new Builder.Generic<>(el, prop) { + @Override + protected BlockVector parse(Node node) throws InvalidXMLException { + return XMLUtils.parseBlockVector(node); + } + }; + } + + public FilterBuilder filter(Element el, String... prop) { return new FilterBuilder(filters, el, prop); } - public RegionBuilder region(Element el, String... prop) throws InvalidXMLException { + public RegionBuilder region(Element el, String... prop) { return new RegionBuilder(regions, el, prop); } - public ItemBuilder item(Element el, String... prop) throws InvalidXMLException { + public ItemBuilder item(Element el, String... prop) { return new ItemBuilder(kits, el, prop); } - public Builder.Generic kit(Element el, String... prop) throws InvalidXMLException { + public Builder.Generic kit(Element el, String... prop) { return new Builder.Generic<>(el, prop) { @Override protected Kit parse(Node node) throws InvalidXMLException { @@ -87,16 +116,16 @@ protected Kit parse(Node node) throws InvalidXMLException { } public ReferenceBuilder reference( - Class clazz, Element el, String... prop) throws InvalidXMLException { + Class clazz, Element el, String... prop) { return new ReferenceBuilder(features, clazz, el, prop); } - public VariableBuilder variable(Element el, String... prop) throws InvalidXMLException { + public VariableBuilder variable(Element el, String... prop) { return new VariableBuilder<>(features, el, prop); } public > Builder.Generic> action( - Class clazz, Element el, String... prop) throws InvalidXMLException { + Class clazz, Element el, String... prop) { return new Builder.Generic<>(el, prop) { @Override protected Action parse(Node node) throws InvalidXMLException { @@ -112,7 +141,7 @@ public ActionParser getActionParser() { } public > Builder, ?> formula( - Class clazz, Element el, String... prop) throws InvalidXMLException { + Class clazz, Element el, String... prop) { return new Builder.Generic<>(el, prop) { @Override protected Formula parse(Node node) { diff --git a/util/src/main/java/tc/oc/pgm/util/math/AddedFunctions.java b/util/src/main/java/tc/oc/pgm/util/math/AddedFunctions.java new file mode 100644 index 0000000000..6028396345 --- /dev/null +++ b/util/src/main/java/tc/oc/pgm/util/math/AddedFunctions.java @@ -0,0 +1,49 @@ +package tc.oc.pgm.util.math; + +import java.util.List; +import net.objecthunter.exp4j.function.Function; + +class AddedFunctions { + public static final List ALL = List.of( + new Function("bound", 3) { + @Override + public double apply(double... doubles) { + double val = doubles[0]; + double min = doubles[1]; + double max = doubles[2]; + return Math.max(min, Math.min(val, max)); + } + }, + new Function("random", 0) { + @Override + public double apply(double... doubles) { + return Math.random(); + } + }, + new Function("max") { + @Override + public double apply(double... doubles) { + double max = doubles[0]; + for (int i = 1; i < doubles.length; i++) max = Math.max(max, doubles[i]); + return max; + } + + @Override + public boolean isValidArgCount(int count) { + return count >= 1; + } + }, + new Function("min") { + @Override + public double apply(double... doubles) { + double min = doubles[0]; + for (int i = 1; i < doubles.length; i++) min = Math.min(min, doubles[i]); + return min; + } + + @Override + public boolean isValidArgCount(int count) { + return count >= 1; + } + }); +} diff --git a/util/src/main/java/tc/oc/pgm/util/math/Formula.java b/util/src/main/java/tc/oc/pgm/util/math/Formula.java index 3aab3ef4d9..ef182c4514 100644 --- a/util/src/main/java/tc/oc/pgm/util/math/Formula.java +++ b/util/src/main/java/tc/oc/pgm/util/math/Formula.java @@ -11,52 +11,6 @@ import tc.oc.pgm.util.bukkit.BukkitUtils; public interface Formula extends ToDoubleFunction { - - Function BOUND = new Function("bound", 3) { - @Override - public double apply(double... doubles) { - double val = doubles[0]; - double min = doubles[1]; - double max = doubles[2]; - return Math.max(min, Math.min(val, max)); - } - }; - - Function RANDOM = new Function("random", 0) { - @Override - public double apply(double... doubles) { - return Math.random(); - } - }; - - Function MAX = new Function("max") { - @Override - public double apply(double... doubles) { - double max = doubles[0]; - for (int i = 1; i < doubles.length; i++) max = Math.max(max, doubles[i]); - return max; - } - - @Override - public boolean isValidArgCount(int count) { - return count >= 1; - } - }; - - Function MIN = new Function("min") { - @Override - public double apply(double... doubles) { - double min = doubles[0]; - for (int i = 1; i < doubles.length; i++) min = Math.min(min, doubles[i]); - return min; - } - - @Override - public boolean isValidArgCount(int count) { - return count >= 1; - } - }; - /** * Create a formula for a config, if there's a misconfiguration it logs and uses fallback * @@ -84,7 +38,7 @@ static Formula of(String expression, ContextFactory context) throws IllegalArgumentException { Expression exp = new ExpressionBuilder(expression) .variables(context.getVariables()) - .functions(BOUND, RANDOM, MAX, MIN) + .functions(AddedFunctions.ALL) .functions(context.getArrays().stream() .map(str -> new Function(str, 1) { @Override @@ -99,6 +53,11 @@ public double apply(double... doubles) { return new ExpFormula<>(exp, context); } + /** Shorthand for {@link #applyAsDouble} */ + default double apply(T value) { + return applyAsDouble(value); + } + class ExpFormula implements Formula { private final Expression expression; private final ContextFactory context;