diff --git a/build.gradle b/build.gradle index 9960a87..3c295f2 100644 --- a/build.gradle +++ b/build.gradle @@ -109,6 +109,7 @@ tasks.register("spotbugs", SpotBugsTask) { task -> spotless { java { removeUnusedImports() + palantirJavaFormat('2.47.0').style("GOOGLE") trimTrailingWhitespace() formatAnnotations() } diff --git a/src/main/java/me/melontini/commander/api/command/Command.java b/src/main/java/me/melontini/commander/api/command/Command.java index dd334f7..672ae14 100644 --- a/src/main/java/me/melontini/commander/api/command/Command.java +++ b/src/main/java/me/melontini/commander/api/command/Command.java @@ -14,20 +14,22 @@ import net.minecraft.util.Identifier; */ public interface Command { - MapCodec CODEC = (MapCodec) ConditionedCommand.CODEC; + MapCodec CODEC = (MapCodec) ConditionedCommand.CODEC; + boolean execute(EventContext context); + + CommandType type(); + + default DataResult validate(EventType type) { + return DataResult.success(null); + } + + /** + * Executable command proxy. This interface is to be used when you nest additional commands in your base command. + */ + interface Conditioned { boolean execute(EventContext context); - CommandType type(); - - default DataResult validate(EventType type) { - return DataResult.success(null); - } - - /** - * Executable command proxy. This interface is to be used when you nest additional commands in your base command. - */ - interface Conditioned { - boolean execute(EventContext context); - DataResult validate(EventType type); - } + + DataResult validate(EventType type); + } } diff --git a/src/main/java/me/melontini/commander/api/command/CommandType.java b/src/main/java/me/melontini/commander/api/command/CommandType.java index caf9dbc..6f301e6 100644 --- a/src/main/java/me/melontini/commander/api/command/CommandType.java +++ b/src/main/java/me/melontini/commander/api/command/CommandType.java @@ -6,9 +6,9 @@ import net.minecraft.util.Identifier; public interface CommandType { - static CommandType register(Identifier identifier, MapCodec codec) { - return CommandTypes.register(identifier, () -> codec); - } + static CommandType register(Identifier identifier, MapCodec codec) { + return CommandTypes.register(identifier, () -> codec); + } - MapCodec codec(); + MapCodec codec(); } diff --git a/src/main/java/me/melontini/commander/api/command/Selector.java b/src/main/java/me/melontini/commander/api/command/Selector.java index 34e0593..92a5c0f 100644 --- a/src/main/java/me/melontini/commander/api/command/Selector.java +++ b/src/main/java/me/melontini/commander/api/command/Selector.java @@ -1,6 +1,8 @@ package me.melontini.commander.api.command; import com.mojang.serialization.Codec; +import java.util.Optional; +import java.util.function.Function; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.impl.command.ConditionedSelector; import me.melontini.commander.impl.event.data.types.SelectorTypes; @@ -9,32 +11,29 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.Optional; -import java.util.function.Function; - /** * Base selector function. Selectors transform input {@link LootContext} parameters into {@link ServerCommandSource}. *

Selectors must be registered with {@link Selector#register(Identifier, Selector)}

*/ public interface Selector extends Function { - Codec CODEC = (Codec) ConditionedSelector.CODEC; + Codec CODEC = (Codec) ConditionedSelector.CODEC; - static Selector register(Identifier identifier, Selector selector) { - return SelectorTypes.register(identifier, selector); - } + static Selector register(Identifier identifier, Selector selector) { + return SelectorTypes.register(identifier, selector); + } - @Override - default @Nullable ServerCommandSource apply(LootContext context) { - return this.select(context); - } + @Override + default @Nullable ServerCommandSource apply(LootContext context) { + return this.select(context); + } - @Nullable ServerCommandSource select(LootContext context); + @Nullable ServerCommandSource select(LootContext context); - /** - * Executable selector proxy. - */ - interface Conditioned { - Optional select(EventContext context); - } + /** + * Executable selector proxy. + */ + interface Conditioned { + Optional select(EventContext context); + } } diff --git a/src/main/java/me/melontini/commander/api/event/EventContext.java b/src/main/java/me/melontini/commander/api/event/EventContext.java index 04232a6..6524fec 100644 --- a/src/main/java/me/melontini/commander/api/event/EventContext.java +++ b/src/main/java/me/melontini/commander/api/event/EventContext.java @@ -1,31 +1,33 @@ package me.melontini.commander.api.event; +import java.util.IdentityHashMap; import me.melontini.commander.impl.event.EventContextImpl; import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.IdentityHashMap; - public interface EventContext { - @Contract("_ -> new") - static EventContext.@NotNull Builder builder(EventType type) { - return new EventContextImpl.Builder(type); - } + @Contract("_ -> new") + static EventContext.@NotNull Builder builder(EventType type) { + return new EventContextImpl.Builder(type); + } + + EventType type(); + + @NotNull T getParameter(EventKey key); + + @NotNull LootContext lootContext(); - EventType type(); + void setReturnValue(Object value); - @NotNull T getParameter(EventKey key); - @NotNull LootContext lootContext(); + T getReturnValue(T def); - void setReturnValue(Object value); - T getReturnValue(T def); + EventContext with(IdentityHashMap, Object> parameters); - EventContext with(IdentityHashMap, Object> parameters); + interface Builder { + Builder addParameter(EventKey key, T value); - interface Builder { - Builder addParameter(EventKey key, T value); - EventContext build(); - } + EventContext build(); + } } diff --git a/src/main/java/me/melontini/commander/api/event/EventKey.java b/src/main/java/me/melontini/commander/api/event/EventKey.java index d21bd11..3c19ac1 100644 --- a/src/main/java/me/melontini/commander/api/event/EventKey.java +++ b/src/main/java/me/melontini/commander/api/event/EventKey.java @@ -1,5 +1,6 @@ package me.melontini.commander.api.event; +import java.util.concurrent.atomic.AtomicReference; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -10,20 +11,19 @@ import net.minecraft.util.Identifier; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.atomic.AtomicReference; - @Getter @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @Accessors(fluent = true) public final class EventKey { - public static final EventKey LOOT_CONTEXT = create(Commander.id("loot_context")); - public static final EventKey> RETURN_VALUE = create(Commander.id("return_value")); + public static final EventKey LOOT_CONTEXT = create(Commander.id("loot_context")); + public static final EventKey> RETURN_VALUE = + create(Commander.id("return_value")); - private final Identifier id; + private final Identifier id; - @Contract("_ -> new") - public static @NotNull EventKey create(Identifier id) { - return new EventKey<>(id); - } + @Contract("_ -> new") + public static @NotNull EventKey create(Identifier id) { + return new EventKey<>(id); + } } diff --git a/src/main/java/me/melontini/commander/api/event/EventType.java b/src/main/java/me/melontini/commander/api/event/EventType.java index 6bd083f..74bb4dd 100644 --- a/src/main/java/me/melontini/commander/api/event/EventType.java +++ b/src/main/java/me/melontini/commander/api/event/EventType.java @@ -1,16 +1,15 @@ package me.melontini.commander.api.event; +import static me.melontini.commander.impl.Commander.id; + import com.mojang.serialization.Codec; +import java.util.List; +import java.util.function.Function; import me.melontini.commander.impl.event.EventTypeImpl; import me.melontini.dark_matter.api.base.util.Context; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.function.Function; - -import static me.melontini.commander.impl.Commander.id; - /** * Event types define basic information about events, like the return type, additional parameters and the finalizer. * @@ -19,22 +18,25 @@ import static me.melontini.commander.impl.Commander.id; */ public interface EventType extends Context { - /** - * Dummy event type. Can be used to execute commands outside of events, or to replace subscriptions in JSON. - */ - EventType NULL = EventType.builder().extension(null, subscriptions -> null).build(id("none")); + /** + * Dummy event type. Can be used to execute commands outside of events, or to replace subscriptions in JSON. + */ + EventType NULL = EventType.builder().extension(null, subscriptions -> null).build(id("none")); + + Context.Key> EXTENSION = Context.key("extension"); + Context.Key>, ?>> FINALIZER = Context.key("finalizer"); + Context.Key> CANCEL_TERM = Context.key("cancel_term"); + + static EventType.Builder builder() { + return new EventTypeImpl.Builder(); + } - Context.Key> EXTENSION = Context.key("extension"); - Context.Key>, ?>> FINALIZER = Context.key("finalizer"); - Context.Key> CANCEL_TERM = Context.key("cancel_term"); + interface Builder { + Builder extension( + @Nullable Codec extension, Function>, C> finalizer); - static EventType.Builder builder() { - return new EventTypeImpl.Builder(); - } + Builder cancelTerm(Codec returnCodec); - interface Builder { - Builder extension(@Nullable Codec extension, Function>, C> finalizer); - Builder cancelTerm(Codec returnCodec); - EventType build(Identifier identifier); - } + EventType build(Identifier identifier); + } } diff --git a/src/main/java/me/melontini/commander/api/event/Subscription.java b/src/main/java/me/melontini/commander/api/event/Subscription.java index 3b37d3d..8b73aa1 100644 --- a/src/main/java/me/melontini/commander/api/event/Subscription.java +++ b/src/main/java/me/melontini/commander/api/event/Subscription.java @@ -1,19 +1,20 @@ package me.melontini.commander.api.event; +import java.util.List; import me.melontini.commander.api.command.Command; import me.melontini.commander.impl.event.data.DynamicEventManager; import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.Nullable; -import java.util.List; - public interface Subscription { - static @Nullable T getData(MinecraftServer server, EventType type) { - return DynamicEventManager.getData(server, type); - } + static @Nullable T getData(MinecraftServer server, EventType type) { + return DynamicEventManager.getData(server, type); + } + + EventType type(); + + E parameters(); - EventType type(); - E parameters(); - List list(); + List list(); } diff --git a/src/main/java/me/melontini/commander/api/expression/Arithmetica.java b/src/main/java/me/melontini/commander/api/expression/Arithmetica.java index 21c031a..4ca4f68 100644 --- a/src/main/java/me/melontini/commander/api/expression/Arithmetica.java +++ b/src/main/java/me/melontini/commander/api/expression/Arithmetica.java @@ -3,13 +3,12 @@ package me.melontini.commander.api.expression; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import java.util.function.ToDoubleFunction; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.function.ToDoubleFunction; - /** * A simple {@code context -> double} functions, which is encoded as either a double or an expression. *

Can be used as a substitute for {@link Codec#DOUBLE} if {@link LootContext} is available

@@ -18,64 +17,68 @@ import java.util.function.ToDoubleFunction; */ public interface Arithmetica extends ToDoubleFunction { - Codec CODEC = ExtraCodecs.either(Codec.DOUBLE, Codec.STRING).comapFlatMap((either) -> either.map(b -> DataResult.success(constant(b)), s -> Expression.parse(s).map(Arithmetica::of)), Arithmetica::toSource); + Codec CODEC = ExtraCodecs.either(Codec.DOUBLE, Codec.STRING) + .comapFlatMap( + (either) -> either.map( + b -> DataResult.success(constant(b)), s -> Expression.parse(s).map(Arithmetica::of)), + Arithmetica::toSource); - default long asLong(LootContext context) { - return (long) this.applyAsDouble(context); - } + default long asLong(LootContext context) { + return (long) this.applyAsDouble(context); + } - default int asInt(LootContext context) { - return (int) this.applyAsDouble(context); - } + default int asInt(LootContext context) { + return (int) this.applyAsDouble(context); + } - default float asFloat(LootContext context) { - return (float) this.applyAsDouble(context); - } + default float asFloat(LootContext context) { + return (float) this.applyAsDouble(context); + } - default double asDouble(LootContext context) { - return this.applyAsDouble(context); - } + default double asDouble(LootContext context) { + return this.applyAsDouble(context); + } - Either toSource(); + Either toSource(); - @Contract("_ -> new") - static @NotNull Arithmetica constant(double d) { - Either either = Either.left(d); - return new Arithmetica() { - @Override - public Either toSource() { - return either; - } + @Contract("_ -> new") + static @NotNull Arithmetica constant(double d) { + Either either = Either.left(d); + return new Arithmetica() { + @Override + public Either toSource() { + return either; + } - @Override - public double applyAsDouble(LootContext context) { - return d; - } + @Override + public double applyAsDouble(LootContext context) { + return d; + } - @Override - public String toString() { - return "Arithmetica{double=" + d + "}"; - } - }; - } + @Override + public String toString() { + return "Arithmetica{double=" + d + "}"; + } + }; + } - static @NotNull Arithmetica of(Expression expression) { - Either either = Either.right(expression.original()); - return new Arithmetica() { - @Override - public Either toSource() { - return either; - } + static @NotNull Arithmetica of(Expression expression) { + Either either = Either.right(expression.original()); + return new Arithmetica() { + @Override + public Either toSource() { + return either; + } - @Override - public double applyAsDouble(LootContext context) { - return expression.apply(context).getAsDecimal().doubleValue(); - } + @Override + public double applyAsDouble(LootContext context) { + return expression.apply(context).getAsDecimal().doubleValue(); + } - @Override - public String toString() { - return "Arithmetica{expression=" + expression + "}"; - } - }; - } + @Override + public String toString() { + return "Arithmetica{expression=" + expression + "}"; + } + }; + } } diff --git a/src/main/java/me/melontini/commander/api/expression/BooleanExpression.java b/src/main/java/me/melontini/commander/api/expression/BooleanExpression.java index 681173c..86afe11 100644 --- a/src/main/java/me/melontini/commander/api/expression/BooleanExpression.java +++ b/src/main/java/me/melontini/commander/api/expression/BooleanExpression.java @@ -16,51 +16,55 @@ import org.jetbrains.annotations.NotNull; */ public interface BooleanExpression { - Codec CODEC = ExtraCodecs.either(Codec.BOOL, Codec.STRING).comapFlatMap((either) -> either.map(b -> DataResult.success(constant(b)), s -> Expression.parse(s).map(BooleanExpression::of)), BooleanExpression::toSource); + Codec CODEC = ExtraCodecs.either(Codec.BOOL, Codec.STRING) + .comapFlatMap( + (either) -> either.map(b -> DataResult.success(constant(b)), s -> Expression.parse(s) + .map(BooleanExpression::of)), + BooleanExpression::toSource); - boolean asBoolean(LootContext context); + boolean asBoolean(LootContext context); - Either toSource(); + Either toSource(); - @Contract("_ -> new") - static @NotNull BooleanExpression constant(boolean b) { - Either either = Either.left(b); - return new BooleanExpression() { - @Override - public Either toSource() { - return either; - } + @Contract("_ -> new") + static @NotNull BooleanExpression constant(boolean b) { + Either either = Either.left(b); + return new BooleanExpression() { + @Override + public Either toSource() { + return either; + } - @Override - public boolean asBoolean(LootContext context) { - return b; - } + @Override + public boolean asBoolean(LootContext context) { + return b; + } - @Override - public String toString() { - return "BooleanExpression{boolean=" + b + "}"; - } - }; - } + @Override + public String toString() { + return "BooleanExpression{boolean=" + b + "}"; + } + }; + } - @Contract("_ -> new") - static @NotNull BooleanExpression of(Expression expression) { - Either either = Either.right(expression.original()); - return new BooleanExpression() { - @Override - public Either toSource() { - return either; - } + @Contract("_ -> new") + static @NotNull BooleanExpression of(Expression expression) { + Either either = Either.right(expression.original()); + return new BooleanExpression() { + @Override + public Either toSource() { + return either; + } - @Override - public boolean asBoolean(LootContext context) { - return expression.eval(context).getAsBoolean(); - } + @Override + public boolean asBoolean(LootContext context) { + return expression.eval(context).getAsBoolean(); + } - @Override - public String toString() { - return "BooleanExpression{expression=" + expression.original() + "}"; - } - }; - } + @Override + public String toString() { + return "BooleanExpression{expression=" + expression.original() + "}"; + } + }; + } } diff --git a/src/main/java/me/melontini/commander/api/expression/BrigadierMacro.java b/src/main/java/me/melontini/commander/api/expression/BrigadierMacro.java index a4099f6..a7f0cca 100644 --- a/src/main/java/me/melontini/commander/api/expression/BrigadierMacro.java +++ b/src/main/java/me/melontini/commander/api/expression/BrigadierMacro.java @@ -2,35 +2,37 @@ package me.melontini.commander.api.expression; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import java.util.Map; +import java.util.function.Function; import me.melontini.commander.impl.expression.macro.PatternParser; import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.Map; -import java.util.function.Function; - /** * A special type of string function with support for {@code ${{}}} macros. *

The main purpose is to enable command macros in {@code commander:commands}, but can be used anywhere else.

*/ public interface BrigadierMacro extends Function { - Codec CODEC = Codec.STRING.comapFlatMap(BrigadierMacro::parse, BrigadierMacro::original); + Codec CODEC = + Codec.STRING.comapFlatMap(BrigadierMacro::parse, BrigadierMacro::original); + + static DataResult parse(String input) { + return PatternParser.parse(input); + } + + @Override + default String apply(LootContext context) { + return this.build(context); + } - static DataResult parse(String input) { - return PatternParser.parse(input); - } + default String build(LootContext context) { + return this.build(context, null); + } - @Override - default String apply(LootContext context) { - return this.build(context); - } + @ApiStatus.Experimental + String build(LootContext context, @Nullable Map params); - default String build(LootContext context) { - return this.build(context, null); - } - @ApiStatus.Experimental - String build(LootContext context, @Nullable Map params); - String original(); + String original(); } diff --git a/src/main/java/me/melontini/commander/api/expression/Expression.java b/src/main/java/me/melontini/commander/api/expression/Expression.java index 00e2dc2..021d94f 100644 --- a/src/main/java/me/melontini/commander/api/expression/Expression.java +++ b/src/main/java/me/melontini/commander/api/expression/Expression.java @@ -2,58 +2,65 @@ package me.melontini.commander.api.expression; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; -import me.melontini.commander.impl.expression.EvalUtils; -import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; -import net.minecraft.loot.context.LootContext; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - import java.math.BigDecimal; import java.time.Duration; import java.time.Instant; import java.util.Map; import java.util.function.Function; +import me.melontini.commander.impl.expression.EvalUtils; +import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; +import net.minecraft.loot.context.LootContext; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; public interface Expression extends Function { - Codec CODEC = Codec.STRING.comapFlatMap(Expression::parse, Expression::original); + Codec CODEC = Codec.STRING.comapFlatMap(Expression::parse, Expression::original); - static DataResult parse(String expression) { - return (DataResult) (Object) EvalUtils.parseExpression(expression); - } + static DataResult parse(String expression) { + return (DataResult) (Object) EvalUtils.parseExpression(expression); + } - @Override - default Result apply(LootContext context) { - return this.eval(context); - } + @Override + default Result apply(LootContext context) { + return this.eval(context); + } + + default Result eval(LootContext context) { + return this.eval(context, null); + } + + @ApiStatus.Experimental + Result eval(LootContext context, @Nullable Map parameters); + + String original(); + + interface Result { - default Result eval(LootContext context) { - return this.eval(context, null); + static Result convert(Object o) { + return (Result) (Object) ReflectiveValueConverter.convert(o); } - @ApiStatus.Experimental - Result eval(LootContext context, @Nullable Map parameters); + BigDecimal getAsDecimal(); - String original(); + boolean getAsBoolean(); - interface Result { + String getAsString(); - static Result convert(Object o) { - return (Result) (Object) ReflectiveValueConverter.convert(o); - } + Instant getAsInstant(); - BigDecimal getAsDecimal(); - boolean getAsBoolean(); - String getAsString(); - Instant getAsInstant(); - Duration getAsDuration(); + Duration getAsDuration(); - boolean isDecimalValue(); - boolean isBooleanValue(); - boolean isStringValue(); - boolean isInstantValue(); - boolean isDurationValue(); + boolean isDecimalValue(); - Object getValue(); - } + boolean isBooleanValue(); + + boolean isStringValue(); + + boolean isInstantValue(); + + boolean isDurationValue(); + + Object getValue(); + } } diff --git a/src/main/java/me/melontini/commander/api/expression/LootContextParameterRegistry.java b/src/main/java/me/melontini/commander/api/expression/LootContextParameterRegistry.java index 099b33b..b241ad7 100644 --- a/src/main/java/me/melontini/commander/api/expression/LootContextParameterRegistry.java +++ b/src/main/java/me/melontini/commander/api/expression/LootContextParameterRegistry.java @@ -11,9 +11,9 @@ import org.jetbrains.annotations.NotNull; @ApiStatus.Experimental public class LootContextParameterRegistry { - public static void register(LootContextParameter @NotNull ... parameters) { - for (LootContextParameter parameter : parameters) { - ExtractionTypes.register(parameter); - } + public static void register(LootContextParameter @NotNull ... parameters) { + for (LootContextParameter parameter : parameters) { + ExtractionTypes.register(parameter); } + } } diff --git a/src/main/java/me/melontini/commander/api/expression/extensions/CustomFields.java b/src/main/java/me/melontini/commander/api/expression/extensions/CustomFields.java index 3e9fb74..92fb8e1 100644 --- a/src/main/java/me/melontini/commander/api/expression/extensions/CustomFields.java +++ b/src/main/java/me/melontini/commander/api/expression/extensions/CustomFields.java @@ -1,36 +1,35 @@ package me.melontini.commander.api.expression.extensions; +import java.util.function.Function; import lombok.experimental.UtilityClass; import me.melontini.commander.impl.expression.extensions.ReflectiveMapStructure; import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; import org.jetbrains.annotations.ApiStatus; -import java.util.function.Function; - @ApiStatus.Experimental @UtilityClass public class CustomFields { - /** - * Allows adding virtual fields to objects. This works only if the object is not handled by object converters.
- * For better UX, it's best to return types which are handled by converters. - */ - public static void addVirtualField(Class cls, String name, Function accessor) { - ReflectiveMapStructure.addField(cls, name, accessor); - } + /** + * Allows adding virtual fields to objects. This works only if the object is not handled by object converters.
+ * For better UX, it's best to return types which are handled by converters. + */ + public static void addVirtualField(Class cls, String name, Function accessor) { + ReflectiveMapStructure.addField(cls, name, accessor); + } - /** - * Registers an {@link ObjectConverter} to convert objects to types supported by expressions.
- * This is useful for wrappers and complex map-like objects. - */ - public static void registerConverter(ObjectConverter converter) { - ReflectiveValueConverter.registerConverter(Integer.MAX_VALUE, converter); - } + /** + * Registers an {@link ObjectConverter} to convert objects to types supported by expressions.
+ * This is useful for wrappers and complex map-like objects. + */ + public static void registerConverter(ObjectConverter converter) { + ReflectiveValueConverter.registerConverter(Integer.MAX_VALUE, converter); + } - /** - * @see CustomFields#registerConverter(ObjectConverter) - */ - public static void registerConverter(int priority, ObjectConverter converter) { - ReflectiveValueConverter.registerConverter(priority, converter); - } + /** + * @see CustomFields#registerConverter(ObjectConverter) + */ + public static void registerConverter(int priority, ObjectConverter converter) { + ReflectiveValueConverter.registerConverter(priority, converter); + } } diff --git a/src/main/java/me/melontini/commander/api/expression/extensions/ObjectConverter.java b/src/main/java/me/melontini/commander/api/expression/extensions/ObjectConverter.java index af97703..d504056 100644 --- a/src/main/java/me/melontini/commander/api/expression/extensions/ObjectConverter.java +++ b/src/main/java/me/melontini/commander/api/expression/extensions/ObjectConverter.java @@ -1,49 +1,50 @@ package me.melontini.commander.api.expression.extensions; +import java.util.function.Function; import me.melontini.commander.api.expression.Expression; import org.jetbrains.annotations.ApiStatus; -import java.util.function.Function; - @ApiStatus.Experimental public interface ObjectConverter { - static ObjectConverter ofClasses(Function function, Class... classes) { - return new ObjectConverter() { - @Override - public Expression.Result convert(Object object) { - return function.apply(object); - } - - @Override - public boolean canConvert(Object object) { - for (Class aClass : classes) { - if (aClass.isInstance(object)) return true; - } - return false; - } - }; - } - - static ObjectConverter ofClass(Class cls, Function function) { - return new ObjectConverter() { - @Override - public Expression.Result convert(Object object) { - return function.apply((C) object); - } - - @Override - public boolean canConvert(Object object) { - return cls.isInstance(object); - } - }; - } - - Expression.Result convert(Object object); - boolean canConvert(Object object); - - default IllegalArgumentException illegalArgument(Object object) { - return new IllegalArgumentException( - "Unsupported data type '" + object.getClass().getName() + "'"); - } + static ObjectConverter ofClasses( + Function function, Class... classes) { + return new ObjectConverter() { + @Override + public Expression.Result convert(Object object) { + return function.apply(object); + } + + @Override + public boolean canConvert(Object object) { + for (Class aClass : classes) { + if (aClass.isInstance(object)) return true; + } + return false; + } + }; + } + + static ObjectConverter ofClass(Class cls, Function function) { + return new ObjectConverter() { + @Override + public Expression.Result convert(Object object) { + return function.apply((C) object); + } + + @Override + public boolean canConvert(Object object) { + return cls.isInstance(object); + } + }; + } + + Expression.Result convert(Object object); + + boolean canConvert(Object object); + + default IllegalArgumentException illegalArgument(Object object) { + return new IllegalArgumentException( + "Unsupported data type '" + object.getClass().getName() + "'"); + } } diff --git a/src/main/java/me/melontini/commander/api/expression/extensions/ProxyMap.java b/src/main/java/me/melontini/commander/api/expression/extensions/ProxyMap.java index f7e81b9..4fb72ad 100644 --- a/src/main/java/me/melontini/commander/api/expression/extensions/ProxyMap.java +++ b/src/main/java/me/melontini/commander/api/expression/extensions/ProxyMap.java @@ -1,79 +1,79 @@ package me.melontini.commander.api.expression.extensions; +import java.util.Collection; +import java.util.Map; +import java.util.Set; import me.melontini.commander.api.expression.Expression; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Map; -import java.util.Set; - @ApiStatus.Experimental public abstract class ProxyMap implements Map { - protected abstract boolean containsKey(String key); - protected abstract Object getValue(String key); - - @Override - public final Expression.Result get(Object key) { - if (!(key instanceof String s)) return Expression.Result.convert(null); - return Expression.Result.convert(getValue(s)); - } - - @Override - public final boolean containsKey(Object key) { - if (!(key instanceof String s)) return false; - return this.containsKey(s); - } - - @Override - public int size() { - throw new IllegalStateException(); - } - - @Override - public boolean isEmpty() { - throw new IllegalStateException(); - } - - @Override - public boolean containsValue(Object value) { - throw new IllegalStateException(); - } - - @Nullable @Override - public Expression.Result put(String key, Expression.Result value) { - throw new IllegalStateException(); - } - - @Override - public Expression.Result remove(Object key) { - throw new IllegalStateException(); - } - - @Override - public void putAll(@NotNull Map m) { - throw new IllegalStateException(); - } - - @Override - public void clear() { - throw new IllegalStateException(); - } - - @NotNull @Override - public Set keySet() { - throw new IllegalStateException(); - } - - @NotNull @Override - public Collection values() { - throw new IllegalStateException(); - } - - @NotNull @Override - public Set> entrySet() { - throw new IllegalStateException(); - } + protected abstract boolean containsKey(String key); + + protected abstract Object getValue(String key); + + @Override + public final Expression.Result get(Object key) { + if (!(key instanceof String s)) return Expression.Result.convert(null); + return Expression.Result.convert(getValue(s)); + } + + @Override + public final boolean containsKey(Object key) { + if (!(key instanceof String s)) return false; + return this.containsKey(s); + } + + @Override + public int size() { + throw new IllegalStateException(); + } + + @Override + public boolean isEmpty() { + throw new IllegalStateException(); + } + + @Override + public boolean containsValue(Object value) { + throw new IllegalStateException(); + } + + @Nullable @Override + public Expression.Result put(String key, Expression.Result value) { + throw new IllegalStateException(); + } + + @Override + public Expression.Result remove(Object key) { + throw new IllegalStateException(); + } + + @Override + public void putAll(@NotNull Map m) { + throw new IllegalStateException(); + } + + @Override + public void clear() { + throw new IllegalStateException(); + } + + @NotNull @Override + public Set keySet() { + throw new IllegalStateException(); + } + + @NotNull @Override + public Collection values() { + throw new IllegalStateException(); + } + + @NotNull @Override + public Set> entrySet() { + throw new IllegalStateException(); + } } diff --git a/src/main/java/me/melontini/commander/api/util/EventExecutors.java b/src/main/java/me/melontini/commander/api/util/EventExecutors.java index a44a508..4c39eb9 100644 --- a/src/main/java/me/melontini/commander/api/util/EventExecutors.java +++ b/src/main/java/me/melontini/commander/api/util/EventExecutors.java @@ -1,5 +1,8 @@ package me.melontini.commander.api.util; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; import lombok.experimental.UtilityClass; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.event.EventContext; @@ -14,67 +17,72 @@ import net.minecraft.util.ActionResult; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; - @UtilityClass public class EventExecutors { - public static void runVoid(EventType type, World world, Supplier supplier) { - if (world.isClient()) return; + public static void runVoid(EventType type, World world, Supplier supplier) { + if (world.isClient()) return; - List subscribers = Objects.requireNonNull(Subscription.getData(MakeSure.notNull(world.getServer()), type), () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); - if (subscribers.isEmpty()) return; + List subscribers = Objects.requireNonNull( + Subscription.getData(MakeSure.notNull(world.getServer()), type), + () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); + if (subscribers.isEmpty()) return; - EventContext context = EventContext.builder(type) - .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) - .build(); - for (Command.Conditioned subscriber : subscribers) subscriber.execute(context); - } + EventContext context = EventContext.builder(type) + .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) + .build(); + for (Command.Conditioned subscriber : subscribers) subscriber.execute(context); + } - public static boolean runBoolean(EventType type, boolean def, World world, Supplier supplier) { - if (world.isClient()) return def; + public static boolean runBoolean( + EventType type, boolean def, World world, Supplier supplier) { + if (world.isClient()) return def; - List subscribers = Objects.requireNonNull(Subscription.getData(MakeSure.notNull(world.getServer()), type), () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); - if (subscribers.isEmpty()) return def; + List subscribers = Objects.requireNonNull( + Subscription.getData(MakeSure.notNull(world.getServer()), type), + () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); + if (subscribers.isEmpty()) return def; - EventContext context = EventContext.builder(type) - .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) - .build(); - for (Command.Conditioned subscriber : subscribers) { - subscriber.execute(context); - boolean val = Boolean.TRUE.equals(context.getReturnValue(def)); - if (val != def) return val; - } - return def; + EventContext context = EventContext.builder(type) + .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) + .build(); + for (Command.Conditioned subscriber : subscribers) { + subscriber.execute(context); + boolean val = Boolean.TRUE.equals(context.getReturnValue(def)); + if (val != def) return val; } + return def; + } - public static boolean runBoolean(EventType type, World world, Supplier supplier) { - return runBoolean(type, true, world, supplier); - } + public static boolean runBoolean(EventType type, World world, Supplier supplier) { + return runBoolean(type, true, world, supplier); + } - public static > T runEnum(EventType type, @Nullable T def, World world, Supplier supplier) { - if (world.isClient()) return def; + public static > T runEnum( + EventType type, @Nullable T def, World world, Supplier supplier) { + if (world.isClient()) return def; - List subscribers = Objects.requireNonNull(Subscription.getData(MakeSure.notNull(world.getServer()), type), () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); - if (subscribers.isEmpty()) return def; + List subscribers = Objects.requireNonNull( + Subscription.getData(MakeSure.notNull(world.getServer()), type), + () -> "Failed to get subscribers for event %s!".formatted(EventTypes.getId(type))); + if (subscribers.isEmpty()) return def; - var context = EventContext.builder(type) - .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) - .build(); - for (Command.Conditioned subscriber : subscribers) { - subscriber.execute(context); - T r = context.getReturnValue(def); - if (r != def) return r; - } - return def; + var context = EventContext.builder(type) + .addParameter(EventKey.LOOT_CONTEXT, supplier.get()) + .build(); + for (Command.Conditioned subscriber : subscribers) { + subscriber.execute(context); + T r = context.getReturnValue(def); + if (r != def) return r; } + return def; + } - public static ActionResult runActionResult(EventType type, World world, Supplier supplier) { - return runEnum(type, ActionResult.PASS, world, supplier); - } + public static ActionResult runActionResult( + EventType type, World world, Supplier supplier) { + return runEnum(type, ActionResult.PASS, world, supplier); + } - public static TriState runTriState(EventType type, World world, Supplier supplier) { - return runEnum(type, TriState.DEFAULT, world, supplier); - } + public static TriState runTriState(EventType type, World world, Supplier supplier) { + return runEnum(type, TriState.DEFAULT, world, supplier); + } } diff --git a/src/main/java/me/melontini/commander/impl/Commander.java b/src/main/java/me/melontini/commander/impl/Commander.java index 554d0f0..d57a594 100644 --- a/src/main/java/me/melontini/commander/impl/Commander.java +++ b/src/main/java/me/melontini/commander/impl/Commander.java @@ -1,8 +1,17 @@ package me.melontini.commander.impl; +import static net.minecraft.loot.context.LootContextParameters.*; + import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import lombok.Cleanup; import lombok.Getter; import lombok.Setter; @@ -43,143 +52,155 @@ import net.minecraft.util.Identifier; import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; - -import static net.minecraft.loot.context.LootContextParameters.*; - @Accessors(fluent = true) @Log4j2 public class Commander { - public static final PrependingLogger LOGGER = PrependingLogger.get(); - public static final LootNumberProviderType ARITHMETICA_PROVIDER = LootNumberProviderTypes.register("commander:arithmetica", ExtraCodecs.toJsonSerializer(ArithmeticaLootNumberProvider.CODEC.codec())); - public static final LootConditionType EXPRESSION_CONDITION = Registry.register(Registries.LOOT_CONDITION_TYPE, id("expression"), new LootConditionType(ExtraCodecs.toJsonSerializer(ExpressionLootCondition.CODEC.codec()))); - - private static final Path BASE_PATH = Path.of(System.getProperty("user.home")).resolve(".commander"); - public static final String MINECRAFT_VERSION = getVersion(); - public static final Path COMMANDER_PATH = BASE_PATH.resolve(MINECRAFT_VERSION); - - public static final AttachmentType DATA_ATTACHMENT = AttachmentRegistry.builder() - .initializer(NbtCompound::new).persistent(NbtCodecs.COMPOUND_CODEC).buildAndRegister(id("persistent")); - - public static final DynamicCommandExceptionType EXPRESSION_EXCEPTION = new DynamicCommandExceptionType(object -> TextUtil.literal("Failed to evaluate: " + object)); - - @Getter - private AmbiguousRemapper mappingKeeper; - @Getter @Setter - private @Nullable MinecraftServer currentServer; - - public static Identifier id(String path) { - return new Identifier("commander", path); - } - - private static Supplier instance = () -> { - throw new NullPointerException("Commander instance requested too early!"); - }; - - public static void init() { - var cmd = new Commander(); - cmd.onInitialize(); - instance = () -> cmd; - } - - public static Commander get() { - return instance.get(); - } - - public void onInitialize() { - try { - var oldPath = FabricLoader.getInstance().getGameDir().resolve(".commander"); - if (Files.exists(oldPath)) { - if (!Files.exists(BASE_PATH)) Files.move(oldPath, BASE_PATH); - else { - Files.walkFileTree(oldPath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return super.visitFile(file, attrs); - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return super.postVisitDirectory(dir, exc); - } - }); - } + public static final PrependingLogger LOGGER = PrependingLogger.get(); + public static final LootNumberProviderType ARITHMETICA_PROVIDER = + LootNumberProviderTypes.register( + "commander:arithmetica", + ExtraCodecs.toJsonSerializer(ArithmeticaLootNumberProvider.CODEC.codec())); + public static final LootConditionType EXPRESSION_CONDITION = Registry.register( + Registries.LOOT_CONDITION_TYPE, + id("expression"), + new LootConditionType(ExtraCodecs.toJsonSerializer(ExpressionLootCondition.CODEC.codec()))); + + private static final Path BASE_PATH = + Path.of(System.getProperty("user.home")).resolve(".commander"); + public static final String MINECRAFT_VERSION = getVersion(); + public static final Path COMMANDER_PATH = BASE_PATH.resolve(MINECRAFT_VERSION); + + public static final AttachmentType DATA_ATTACHMENT = + AttachmentRegistry.builder() + .initializer(NbtCompound::new) + .persistent(NbtCodecs.COMPOUND_CODEC) + .buildAndRegister(id("persistent")); + + public static final DynamicCommandExceptionType EXPRESSION_EXCEPTION = + new DynamicCommandExceptionType(object -> TextUtil.literal("Failed to evaluate: " + object)); + + @Getter + private AmbiguousRemapper mappingKeeper; + + @Getter + @Setter + private @Nullable MinecraftServer currentServer; + + public static Identifier id(String path) { + return new Identifier("commander", path); + } + + private static Supplier instance = () -> { + throw new NullPointerException("Commander instance requested too early!"); + }; + + public static void init() { + var cmd = new Commander(); + cmd.onInitialize(); + instance = () -> cmd; + } + + public static Commander get() { + return instance.get(); + } + + public void onInitialize() { + try { + var oldPath = FabricLoader.getInstance().getGameDir().resolve(".commander"); + if (Files.exists(oldPath)) { + if (!Files.exists(BASE_PATH)) Files.move(oldPath, BASE_PATH); + else { + Files.walkFileTree(oldPath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.delete(file); + return super.visitFile(file, attrs); } - } catch (IOException e) { - log.error("Failed to move old .commander folder!", e); - } - if (!Files.exists(COMMANDER_PATH)) { - Exceptions.run(() -> Files.createDirectories(COMMANDER_PATH)); - try { - if (BASE_PATH.getFileSystem().supportedFileAttributeViews().contains("dos")) - Files.setAttribute(BASE_PATH, "dos:hidden", Boolean.TRUE, LinkOption.NOFOLLOW_LINKS); - } catch (IOException ignored) { - LOGGER.warn("Failed to hide the .commander folder"); + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) + throws IOException { + Files.delete(dir); + return super.postVisitDirectory(dir, exc); } + }); } - - ServerReloadersEvent.EVENT.register(context -> { - this.resetCaches(); - context.register(new DynamicEventManager()); - }); - - ServerLifecycleEvents.SERVER_STARTING.register(server -> this.currentServer = server); - ServerLifecycleEvents.SERVER_STOPPING.register(server -> { - this.currentServer = null; - this.resetCaches(); - }); - - EvalUtils.init(); - this.loadMappings(); - - BuiltInEvents.init(); - BuiltInCommands.init(); - BuiltInSelectors.init(); - - LootContextParameterRegistry.register( - ORIGIN, TOOL, - THIS_ENTITY, LAST_DAMAGE_PLAYER, - KILLER_ENTITY, DIRECT_KILLER_ENTITY, - DAMAGE_SOURCE, EXPLOSION_RADIUS, - BLOCK_STATE, BLOCK_ENTITY); + } + } catch (IOException e) { + log.error("Failed to move old .commander folder!", e); } - private void resetCaches() { - EvalUtils.resetCache(); - RegistryAccessStruct.resetCache(); + if (!Files.exists(COMMANDER_PATH)) { + Exceptions.run(() -> Files.createDirectories(COMMANDER_PATH)); + try { + if (BASE_PATH.getFileSystem().supportedFileAttributeViews().contains("dos")) + Files.setAttribute(BASE_PATH, "dos:hidden", Boolean.TRUE, LinkOption.NOFOLLOW_LINKS); + } catch (IOException ignored) { + LOGGER.warn("Failed to hide the .commander folder"); + } } - private void loadMappings() { - if (MappingKeeper.NAMESPACE.equals("mojang")) { - mappingKeeper = (cls, name) -> name; // Nothing to remap. - return; - } - - try { - CompletableFuture offTarget = CompletableFuture.supplyAsync(MappingKeeper::loadOffTarget, Util.getMainWorkerExecutor()); - CompletableFuture offMojmap = CompletableFuture.runAsync(MinecraftDownloader::downloadMappings, Util.getMainWorkerExecutor()) - .thenApplyAsync(unused -> MappingKeeper.loadOffMojmap(), Util.getMainWorkerExecutor()); - mappingKeeper = new MappingKeeper(MappingKeeper.loadMojmapTarget(offMojmap.join(), offTarget.join())); - } catch (Throwable t) { - log.error("Failed to download and prepare mappings! Data access remapping will not work!!!", t); - mappingKeeper = (cls, name) -> name;//Returning null will force it to traverse the hierarchy. - } + ServerReloadersEvent.EVENT.register(context -> { + this.resetCaches(); + context.register(new DynamicEventManager()); + }); + + ServerLifecycleEvents.SERVER_STARTING.register(server -> this.currentServer = server); + ServerLifecycleEvents.SERVER_STOPPING.register(server -> { + this.currentServer = null; + this.resetCaches(); + }); + + EvalUtils.init(); + this.loadMappings(); + + BuiltInEvents.init(); + BuiltInCommands.init(); + BuiltInSelectors.init(); + + LootContextParameterRegistry.register( + ORIGIN, TOOL, + THIS_ENTITY, LAST_DAMAGE_PLAYER, + KILLER_ENTITY, DIRECT_KILLER_ENTITY, + DAMAGE_SOURCE, EXPLOSION_RADIUS, + BLOCK_STATE, BLOCK_ENTITY); + } + + private void resetCaches() { + EvalUtils.resetCache(); + RegistryAccessStruct.resetCache(); + } + + private void loadMappings() { + if (MappingKeeper.NAMESPACE.equals("mojang")) { + mappingKeeper = (cls, name) -> name; // Nothing to remap. + return; } - @SneakyThrows(IOException.class) - private static String getVersion() { - @Cleanup var stream = new InputStreamReader(MinecraftDownloader.class.getResourceAsStream("/version.json"), StandardCharsets.UTF_8); - JsonObject o = JsonParser.parseReader(stream).getAsJsonObject(); - return o.getAsJsonPrimitive("id").getAsString(); + try { + CompletableFuture offTarget = + CompletableFuture.supplyAsync(MappingKeeper::loadOffTarget, Util.getMainWorkerExecutor()); + CompletableFuture offMojmap = CompletableFuture.runAsync( + MinecraftDownloader::downloadMappings, Util.getMainWorkerExecutor()) + .thenApplyAsync(unused -> MappingKeeper.loadOffMojmap(), Util.getMainWorkerExecutor()); + mappingKeeper = + new MappingKeeper(MappingKeeper.loadMojmapTarget(offMojmap.join(), offTarget.join())); + } catch (Throwable t) { + log.error( + "Failed to download and prepare mappings! Data access remapping will not work!!!", t); + mappingKeeper = + (cls, name) -> name; // Returning null will force it to traverse the hierarchy. } + } + + @SneakyThrows(IOException.class) + private static String getVersion() { + @Cleanup + var stream = new InputStreamReader( + MinecraftDownloader.class.getResourceAsStream("/version.json"), StandardCharsets.UTF_8); + JsonObject o = JsonParser.parseReader(stream).getAsJsonObject(); + return o.getAsJsonPrimitive("id").getAsString(); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/BrigadierCommands.java b/src/main/java/me/melontini/commander/impl/builtin/BrigadierCommands.java index 4cdc6e5..c191599 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/BrigadierCommands.java +++ b/src/main/java/me/melontini/commander/impl/builtin/BrigadierCommands.java @@ -9,11 +9,11 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @UtilityClass public class BrigadierCommands { - public static void init() { - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { - ExplodeCommand.register(dispatcher); - ArithmeticaCommand.register(dispatcher); - DataCommand.register(dispatcher); - }); - } + public static void init() { + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + ExplodeCommand.register(dispatcher); + ArithmeticaCommand.register(dispatcher); + DataCommand.register(dispatcher); + }); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java b/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java index a646f93..7986ead 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java +++ b/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.builtin; +import static me.melontini.commander.impl.Commander.id; + import lombok.experimental.UtilityClass; import me.melontini.commander.api.command.CommandType; import me.melontini.commander.impl.builtin.commands.action.CancelCommand; @@ -11,22 +13,23 @@ import me.melontini.commander.impl.builtin.commands.logic.AnyOfCommand; import me.melontini.commander.impl.builtin.commands.logic.DefaultedCommand; import me.melontini.commander.impl.builtin.commands.logic.RandomCommand; -import static me.melontini.commander.impl.Commander.id; - @UtilityClass public class BuiltInCommands { - public static final CommandType RANDOM = CommandType.register(id("random"), RandomCommand.CODEC); - public static final CommandType ALL_OF = CommandType.register(id("all_of"), AllOfCommand.CODEC); - public static final CommandType ANY_OF = CommandType.register(id("any_of"), AnyOfCommand.CODEC); - public static final CommandType DEFAULTED = CommandType.register(id("defaulted"), DefaultedCommand.CODEC); + public static final CommandType RANDOM = CommandType.register(id("random"), RandomCommand.CODEC); + public static final CommandType ALL_OF = CommandType.register(id("all_of"), AllOfCommand.CODEC); + public static final CommandType ANY_OF = CommandType.register(id("any_of"), AnyOfCommand.CODEC); + public static final CommandType DEFAULTED = + CommandType.register(id("defaulted"), DefaultedCommand.CODEC); - public static final CommandType CANCEL = CommandType.register(id("cancel"), CancelCommand.CODEC); - public static final CommandType COMMANDS = CommandType.register(id("commands"), CommandCommand.CODEC); - public static final CommandType PRINT = CommandType.register(id("print"), PrintCommand.CODEC); - public static final CommandType PRINT_ARITHMETICA = CommandType.register(id("print_arithmetica"), PrintArithmeticaCommand.CODEC); + public static final CommandType CANCEL = CommandType.register(id("cancel"), CancelCommand.CODEC); + public static final CommandType COMMANDS = + CommandType.register(id("commands"), CommandCommand.CODEC); + public static final CommandType PRINT = CommandType.register(id("print"), PrintCommand.CODEC); + public static final CommandType PRINT_ARITHMETICA = + CommandType.register(id("print_arithmetica"), PrintArithmeticaCommand.CODEC); - public static void init() { - BrigadierCommands.init(); - } + public static void init() { + BrigadierCommands.init(); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/BuiltInEvents.java b/src/main/java/me/melontini/commander/impl/builtin/BuiltInEvents.java index 4a0a612..cdb8fab 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/BuiltInEvents.java +++ b/src/main/java/me/melontini/commander/impl/builtin/BuiltInEvents.java @@ -9,10 +9,10 @@ import me.melontini.commander.impl.builtin.events.ServerTick; @UtilityClass public class BuiltInEvents { - public static void init() { - ServerLifecycle.init(); - ServerTick.init(); - EntityEvents.init(); - PlayerEvents.init(); - } + public static void init() { + ServerLifecycle.init(); + ServerTick.init(); + EntityEvents.init(); + PlayerEvents.init(); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/BuiltInSelectors.java b/src/main/java/me/melontini/commander/impl/builtin/BuiltInSelectors.java index 14fba10..5ca5455 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/BuiltInSelectors.java +++ b/src/main/java/me/melontini/commander/impl/builtin/BuiltInSelectors.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.builtin; +import static me.melontini.commander.impl.Commander.id; + import lombok.experimental.UtilityClass; import me.melontini.commander.api.command.Selector; import me.melontini.dark_matter.api.base.util.Utilities; @@ -12,60 +14,86 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; -import static me.melontini.commander.impl.Commander.id; - @UtilityClass @SuppressWarnings("unused") public final class BuiltInSelectors { - public static final Selector SERVER = Selector.register(mc("server"), context -> context.getWorld().getServer().getCommandSource()); - public static final Selector ORIGIN = Selector.register(mc("origin"), context -> { - var world = context.getWorld(); - var o = context.requireParameter(LootContextParameters.ORIGIN); + public static final Selector SERVER = + Selector.register(mc("server"), context -> context.getWorld().getServer().getCommandSource()); + public static final Selector ORIGIN = Selector.register(mc("origin"), context -> { + var world = context.getWorld(); + var o = context.requireParameter(LootContextParameters.ORIGIN); - return new ServerCommandSource(world.getServer(), o, Vec2f.ZERO, - world, 4, world.getRegistryKey().getValue().toString(), TextUtil.literal(world.getRegistryKey().getValue().toString()), - world.getServer(), null); - }); - public static final Selector THIS_ENTITY = Selector.register(mc("this_entity"), context -> forEntity(context.requireParameter(LootContextParameters.THIS_ENTITY))); - public static final Selector KILLER_ENTITY = Selector.register(mc("killer_entity"), context -> forEntity(context.requireParameter(LootContextParameters.KILLER_ENTITY))); - public static final Selector DIRECT_KILLER_ENTITY = Selector.register(mc("direct_killer_entity"), context -> forEntity(context.requireParameter(LootContextParameters.DIRECT_KILLER_ENTITY))); - public static final Selector LAST_DAMAGE_PLAYER = Selector.register(mc("last_damage_player"), context -> forEntity(context.requireParameter(LootContextParameters.LAST_DAMAGE_PLAYER))); - public static final Selector BLOCK_ENTITY = Selector.register(mc("block_entity"), context -> { - var be = context.requireParameter(LootContextParameters.BLOCK_ENTITY); - return new ServerCommandSource(context.getWorld().getServer(), Vec3d.ofCenter(be.getPos()), Vec2f.ZERO, - (ServerWorld) be.getWorld(), 4, "BlockEntity", TextUtil.literal("BlockEntity"), - context.getWorld().getServer(), null); - }); + return new ServerCommandSource( + world.getServer(), + o, + Vec2f.ZERO, + world, + 4, + world.getRegistryKey().getValue().toString(), + TextUtil.literal(world.getRegistryKey().getValue().toString()), + world.getServer(), + null); + }); + public static final Selector THIS_ENTITY = Selector.register( + mc("this_entity"), + context -> forEntity(context.requireParameter(LootContextParameters.THIS_ENTITY))); + public static final Selector KILLER_ENTITY = Selector.register( + mc("killer_entity"), + context -> forEntity(context.requireParameter(LootContextParameters.KILLER_ENTITY))); + public static final Selector DIRECT_KILLER_ENTITY = Selector.register( + mc("direct_killer_entity"), + context -> forEntity(context.requireParameter(LootContextParameters.DIRECT_KILLER_ENTITY))); + public static final Selector LAST_DAMAGE_PLAYER = Selector.register( + mc("last_damage_player"), + context -> forEntity(context.requireParameter(LootContextParameters.LAST_DAMAGE_PLAYER))); + public static final Selector BLOCK_ENTITY = Selector.register(mc("block_entity"), context -> { + var be = context.requireParameter(LootContextParameters.BLOCK_ENTITY); + return new ServerCommandSource( + context.getWorld().getServer(), + Vec3d.ofCenter(be.getPos()), + Vec2f.ZERO, + (ServerWorld) be.getWorld(), + 4, + "BlockEntity", + TextUtil.literal("BlockEntity"), + context.getWorld().getServer(), + null); + }); - public static final Selector DAMAGE_SOURCE_SOURCE = Selector.register(id("damage_source/source"), context -> { + public static final Selector DAMAGE_SOURCE_SOURCE = + Selector.register(id("damage_source/source"), context -> { var s = context.requireParameter(LootContextParameters.DAMAGE_SOURCE).getSource(); return s != null ? forEntity(s) : null; - }); - public static final Selector DAMAGE_SOURCE_ATTACKER = Selector.register(id("damage_source/attacker"), context -> { + }); + public static final Selector DAMAGE_SOURCE_ATTACKER = + Selector.register(id("damage_source/attacker"), context -> { var s = context.requireParameter(LootContextParameters.DAMAGE_SOURCE).getAttacker(); return s != null ? forEntity(s) : null; - }); + }); - public static final Selector RANDOM_PLAYER = Selector.register(id("random_player"), context -> { - var l = context.getWorld().getServer().getPlayerManager().getPlayerList(); - if (l == null || l.isEmpty()) return null; - return forEntity(Utilities.pickAtRandom(l)); - }); + public static final Selector RANDOM_PLAYER = Selector.register(id("random_player"), context -> { + var l = context.getWorld().getServer().getPlayerManager().getPlayerList(); + if (l == null || l.isEmpty()) return null; + return forEntity(Utilities.pickAtRandom(l)); + }); - public static void init() { - } + public static void init() {} - public static Identifier mc(String string) { - return new Identifier("minecraft", string); - } + public static Identifier mc(String string) { + return new Identifier("minecraft", string); + } - public static ServerCommandSource forEntity(Entity entity) { - return new ServerCommandSource( - entity.getWorld().getServer(), entity.getPos(), - new Vec2f(entity.getPitch(), entity.getYaw()), - (ServerWorld) entity.getWorld(), 4, entity.getEntityName(), entity.getName(), - entity.getWorld().getServer(), entity - ); - } + public static ServerCommandSource forEntity(Entity entity) { + return new ServerCommandSource( + entity.getWorld().getServer(), + entity.getPos(), + new Vec2f(entity.getPitch(), entity.getYaw()), + (ServerWorld) entity.getWorld(), + 4, + entity.getEntityName(), + entity.getName(), + entity.getWorld().getServer(), + entity); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/brigadier/ArithmeticaCommand.java b/src/main/java/me/melontini/commander/impl/builtin/brigadier/ArithmeticaCommand.java index 76b25b7..a949413 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/brigadier/ArithmeticaCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/brigadier/ArithmeticaCommand.java @@ -16,33 +16,47 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; - public class ArithmeticaCommand { - public static void register(CommandDispatcher dispatcher) { - var cmd = CommandManager.argument("expression", StringArgumentType.string()).executes(context -> execute(context, StringArgumentType.getString(context, "expression"), null)); - - for (String cast : PatternParser.CONVERTERS.keySet()) { - cmd.then(CommandManager.literal(cast).executes(context -> execute(context, StringArgumentType.getString(context, "expression"), cast))); - } + public static void register(CommandDispatcher dispatcher) { + var cmd = CommandManager.argument("expression", StringArgumentType.string()) + .executes( + context -> execute(context, StringArgumentType.getString(context, "expression"), null)); - dispatcher.register(CommandManager.literal("cmd:arithmetica").requires(source -> source.hasPermissionLevel(2)).then(cmd)); + for (String cast : PatternParser.CONVERTERS.keySet()) { + cmd.then(CommandManager.literal(cast) + .executes(context -> + execute(context, StringArgumentType.getString(context, "expression"), cast))); } - private static int execute(CommandContext context, String expression, @Nullable String cast) throws CommandSyntaxException { - try { - var r = PatternParser.parseExpression(expression, cast); - if (r.error().isPresent()) throw Commander.EXPRESSION_EXCEPTION.create(r.error().get().message()); - - LootContext context1 = new LootContext.Builder(new LootContextParameterSet.Builder(context.getSource().getWorld()) - .add(LootContextParameters.ORIGIN, context.getSource().getPosition()) - .addOptional(LootContextParameters.THIS_ENTITY, context.getSource().getEntity()) - .build(LootContextTypes.COMMAND)).build(null); - - context.getSource().sendMessage(Text.literal(String.valueOf(r.result().orElseThrow().apply(context1, null)))); - return 1; - } catch (CmdEvalException e) { - throw Commander.EXPRESSION_EXCEPTION.create(e.getMessage()); - } + dispatcher.register(CommandManager.literal("cmd:arithmetica") + .requires(source -> source.hasPermissionLevel(2)) + .then(cmd)); + } + + private static int execute( + CommandContext context, String expression, @Nullable String cast) + throws CommandSyntaxException { + try { + var r = PatternParser.parseExpression(expression, cast); + if (r.error().isPresent()) + throw Commander.EXPRESSION_EXCEPTION.create(r.error().get().message()); + + LootContext context1 = new LootContext.Builder( + new LootContextParameterSet.Builder(context.getSource().getWorld()) + .add(LootContextParameters.ORIGIN, context.getSource().getPosition()) + .addOptional( + LootContextParameters.THIS_ENTITY, context.getSource().getEntity()) + .build(LootContextTypes.COMMAND)) + .build(null); + + context + .getSource() + .sendMessage( + Text.literal(String.valueOf(r.result().orElseThrow().apply(context1, null)))); + return 1; + } catch (CmdEvalException e) { + throw Commander.EXPRESSION_EXCEPTION.create(e.getMessage()); } + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/brigadier/DataCommand.java b/src/main/java/me/melontini/commander/impl/builtin/brigadier/DataCommand.java index ab09a0f..e00323c 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/brigadier/DataCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/brigadier/DataCommand.java @@ -8,6 +8,10 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import java.util.Locale; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Supplier; import me.melontini.commander.impl.Commander; import me.melontini.commander.impl.builtin.commands.StoreDataCommand.Target; import me.melontini.dark_matter.api.minecraft.util.TextUtil; @@ -21,94 +25,135 @@ import net.minecraft.nbt.NbtString; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import java.util.Locale; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Supplier; - public class DataCommand { - private static final DynamicCommandExceptionType NO_BE_EXCEPTION = new DynamicCommandExceptionType((a) -> TextUtil.literal("No block entity at position %s".formatted(a))); - private static final DynamicCommandExceptionType NO_KEY_EXCEPTION = new DynamicCommandExceptionType((a) -> TextUtil.literal("No such key '%s' in target".formatted(a))); - private static final SimpleCommandExceptionType WRONG_DATA_TYPE_EXCEPTION = new SimpleCommandExceptionType(TextUtil.literal("Nbt element must be a string or a number!")); - - private static final Map>> ARGS = Map.of( - Target.LEVEL, () -> null, - Target.CHUNK, () -> CommandManager.argument("position", BlockPosArgumentType.blockPos()), - Target.ENTITY, () -> CommandManager.argument("entity", EntityArgumentType.entity()), - Target.BLOCK_ENTITY, () -> CommandManager.argument("position", BlockPosArgumentType.blockPos()) - ); - - private static final Map, AttachmentTarget>> TO_TARGET = Map.of( - Target.LEVEL, ctx -> ctx.getSource().getWorld(), - Target.CHUNK, ctx -> ctx.getSource().getWorld().getChunk(BlockPosArgumentType.getBlockPos(ctx, "position")), - Target.ENTITY, ctx -> EntityArgumentType.getEntity(ctx, "entity"), - Target.BLOCK_ENTITY, ctx -> { + private static final DynamicCommandExceptionType NO_BE_EXCEPTION = + new DynamicCommandExceptionType( + (a) -> TextUtil.literal("No block entity at position %s".formatted(a))); + private static final DynamicCommandExceptionType NO_KEY_EXCEPTION = + new DynamicCommandExceptionType( + (a) -> TextUtil.literal("No such key '%s' in target".formatted(a))); + private static final SimpleCommandExceptionType WRONG_DATA_TYPE_EXCEPTION = + new SimpleCommandExceptionType(TextUtil.literal("Nbt element must be a string or a number!")); + + private static final Map>> ARGS = + Map.of( + Target.LEVEL, () -> null, + Target.CHUNK, () -> CommandManager.argument("position", BlockPosArgumentType.blockPos()), + Target.ENTITY, () -> CommandManager.argument("entity", EntityArgumentType.entity()), + Target.BLOCK_ENTITY, + () -> CommandManager.argument("position", BlockPosArgumentType.blockPos())); + + private static final Map< + Target, PseudoFunction, AttachmentTarget>> + TO_TARGET = Map.of( + Target.LEVEL, ctx -> ctx.getSource().getWorld(), + Target.CHUNK, + ctx -> ctx.getSource() + .getWorld() + .getChunk(BlockPosArgumentType.getBlockPos(ctx, "position")), + Target.ENTITY, ctx -> EntityArgumentType.getEntity(ctx, "entity"), + Target.BLOCK_ENTITY, + ctx -> { var pos = BlockPosArgumentType.getBlockPos(ctx, "position"); var be = ctx.getSource().getWorld().getBlockEntity(pos); if (be == null) - throw NO_BE_EXCEPTION.create("[%s, %s, %s]".formatted(pos.getX(), pos.getY(), pos.getZ())); + throw NO_BE_EXCEPTION.create( + "[%s, %s, %s]".formatted(pos.getX(), pos.getY(), pos.getZ())); return be; - } - ); - - public static void register(CommandDispatcher dispatcher) { - var cmd = CommandManager.literal("cmd:data").requires(source -> source.hasPermissionLevel(2)); - - attachCommand(cmd, "read", (target, builder) -> builder.executes(context -> readValue(context.getSource(), TO_TARGET.get(target).apply(context), StringArgumentType.getString(context, "key")))); - attachCommand(cmd, "write", (target, builder) -> builder.then(CommandManager.argument("data", NbtElementArgumentType.nbtElement()) - .executes(context -> writeValue(context.getSource(), TO_TARGET.get(target).apply(context), StringArgumentType.getString(context, "key"), NbtElementArgumentType.getNbtElement(context, "data"))))); - attachCommand(cmd, "remove", (target, builder) -> builder.executes(context -> removeValue(context.getSource(), TO_TARGET.get(target).apply(context), StringArgumentType.getString(context, "key")))); - - dispatcher.register(cmd); + }); + + public static void register(CommandDispatcher dispatcher) { + var cmd = CommandManager.literal("cmd:data").requires(source -> source.hasPermissionLevel(2)); + + attachCommand( + cmd, + "read", + (target, builder) -> builder.executes(context -> readValue( + context.getSource(), + TO_TARGET.get(target).apply(context), + StringArgumentType.getString(context, "key")))); + attachCommand( + cmd, + "write", + (target, builder) -> + builder.then(CommandManager.argument("data", NbtElementArgumentType.nbtElement()) + .executes(context -> writeValue( + context.getSource(), + TO_TARGET.get(target).apply(context), + StringArgumentType.getString(context, "key"), + NbtElementArgumentType.getNbtElement(context, "data"))))); + attachCommand( + cmd, + "remove", + (target, builder) -> builder.executes(context -> removeValue( + context.getSource(), + TO_TARGET.get(target).apply(context), + StringArgumentType.getString(context, "key")))); + + dispatcher.register(cmd); + } + + private static void attachCommand( + LiteralArgumentBuilder base, + String name, + BiFunction< + Target, + RequiredArgumentBuilder, + RequiredArgumentBuilder> + keyAttachment) { + var command = CommandManager.literal(name); + for (Target value : Target.values()) { + var start = CommandManager.literal(value.name().toLowerCase(Locale.ROOT)); + var keyArg = + keyAttachment.apply(value, CommandManager.argument("key", StringArgumentType.string())); + + var args = ARGS.get(value).get(); + if (args != null) args.then(keyArg); + else args = keyArg; + + command.then(start.then(args)); } - - private static void attachCommand(LiteralArgumentBuilder base, String name, BiFunction, RequiredArgumentBuilder> keyAttachment) { - var command = CommandManager.literal(name); - for (Target value : Target.values()) { - var start = CommandManager.literal(value.name().toLowerCase(Locale.ROOT)); - var keyArg = keyAttachment.apply(value, CommandManager.argument("key", StringArgumentType.string())); - - var args = ARGS.get(value).get(); - if (args != null) args.then(keyArg); - else args = keyArg; - - command.then(start.then(args)); - } - base.then(command); + base.then(command); + } + + private static int removeValue(ServerCommandSource source, AttachmentTarget target, String key) { + var nbt = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT); + if (nbt.contains(key)) { + nbt.remove(key); + source.sendFeedback( + () -> TextUtil.literal("Successfully removed key %s from target!".formatted(key)), false); + return 1; } - - private static int removeValue(ServerCommandSource source, AttachmentTarget target, String key) { - var nbt = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT); - if (nbt.contains(key)) { - nbt.remove(key); - source.sendFeedback(() -> TextUtil.literal("Successfully removed key %s from target!".formatted(key)), false); - return 1; - } - source.sendFeedback(() -> TextUtil.literal("Target has no %s key!".formatted(key)), false); - return 0; + source.sendFeedback(() -> TextUtil.literal("Target has no %s key!".formatted(key)), false); + return 0; + } + + public static int writeValue( + ServerCommandSource source, AttachmentTarget target, String key, NbtElement element) + throws CommandSyntaxException { + var r = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT); + if (element instanceof AbstractNbtNumber || element instanceof NbtString) { + r.put(key, element); + source.sendFeedback( + () -> TextUtil.literal("Successfully wrote value %s to target!".formatted(element)), + false); + return 1; } - - public static int writeValue(ServerCommandSource source, AttachmentTarget target, String key, NbtElement element) throws CommandSyntaxException { - var r = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT); - if (element instanceof AbstractNbtNumber || element instanceof NbtString) { - r.put(key, element); - source.sendFeedback(() -> TextUtil.literal("Successfully wrote value %s to target!".formatted(element)), false); - return 1; - } - throw WRONG_DATA_TYPE_EXCEPTION.create(); + throw WRONG_DATA_TYPE_EXCEPTION.create(); + } + + public static int readValue(ServerCommandSource source, AttachmentTarget target, String key) + throws CommandSyntaxException { + var r = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT).get(key); + if (r == null) { + throw NO_KEY_EXCEPTION.create(key); } + source.sendFeedback(() -> TextUtil.literal(r.asString()), false); + return 1; + } - public static int readValue(ServerCommandSource source, AttachmentTarget target, String key) throws CommandSyntaxException { - var r = target.getAttachedOrCreate(Commander.DATA_ATTACHMENT).get(key); - if (r == null) { - throw NO_KEY_EXCEPTION.create(key); - } - source.sendFeedback(() -> TextUtil.literal(r.asString()), false); - return 1; - } - - private interface PseudoFunction { - R apply(T t) throws CommandSyntaxException; - } + private interface PseudoFunction { + R apply(T t) throws CommandSyntaxException; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/brigadier/ExplodeCommand.java b/src/main/java/me/melontini/commander/impl/builtin/brigadier/ExplodeCommand.java index 5201c94..c08c14b 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/brigadier/ExplodeCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/brigadier/ExplodeCommand.java @@ -14,27 +14,74 @@ import org.jetbrains.annotations.Nullable; public class ExplodeCommand { - public static void register(CommandDispatcher dispatcher) { - dispatcher.register(CommandManager.literal("cmd:explode").requires(source -> source.hasPermissionLevel(2)) - .executes(context -> execute(context.getSource().getWorld(), null, context.getSource().getPosition(), 4, false)) - .then(CommandManager.argument("pos", Vec3ArgumentType.vec3()) - .executes(context -> execute(context.getSource().getWorld(), null, Vec3ArgumentType.getVec3(context, "pos"), 4, false)) - .then(CommandManager.argument("power", FloatArgumentType.floatArg(0)) - .executes(context -> execute(context.getSource().getWorld(), null, Vec3ArgumentType.getVec3(context, "pos"), FloatArgumentType.getFloat(context, "power"), false)) - .then(CommandManager.argument("fire", BoolArgumentType.bool()) - .executes(context -> execute(context.getSource().getWorld(), null, Vec3ArgumentType.getVec3(context, "pos"), FloatArgumentType.getFloat(context, "power"), BoolArgumentType.getBool(context, "fire")))))) - .then(CommandManager.argument("entity", EntityArgumentType.entity()) - .executes(context -> execute(context.getSource().getWorld(), EntityArgumentType.getEntity(context, "entity"), EntityArgumentType.getEntity(context, "entity").getPos(), 4, false)) - .then(CommandManager.argument("pos", Vec3ArgumentType.vec3()) - .executes(context -> execute(context.getSource().getWorld(), EntityArgumentType.getEntity(context, "entity"), Vec3ArgumentType.getVec3(context, "pos"), 4, false)) - .then(CommandManager.argument("power", FloatArgumentType.floatArg(0)) - .executes(context -> execute(context.getSource().getWorld(), EntityArgumentType.getEntity(context, "entity"), Vec3ArgumentType.getVec3(context, "pos"), FloatArgumentType.getFloat(context, "power"), false)) - .then(CommandManager.argument("fire", BoolArgumentType.bool()) - .executes(context -> execute(context.getSource().getWorld(), EntityArgumentType.getEntity(context, "entity"), Vec3ArgumentType.getVec3(context, "pos"), FloatArgumentType.getFloat(context, "power"), BoolArgumentType.getBool(context, "fire")))))))); - } + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(CommandManager.literal("cmd:explode") + .requires(source -> source.hasPermissionLevel(2)) + .executes(context -> execute( + context.getSource().getWorld(), null, context.getSource().getPosition(), 4, false)) + .then(CommandManager.argument("pos", Vec3ArgumentType.vec3()) + .executes(context -> execute( + context.getSource().getWorld(), + null, + Vec3ArgumentType.getVec3(context, "pos"), + 4, + false)) + .then(CommandManager.argument("power", FloatArgumentType.floatArg(0)) + .executes(context -> execute( + context.getSource().getWorld(), + null, + Vec3ArgumentType.getVec3(context, "pos"), + FloatArgumentType.getFloat(context, "power"), + false)) + .then(CommandManager.argument("fire", BoolArgumentType.bool()) + .executes(context -> execute( + context.getSource().getWorld(), + null, + Vec3ArgumentType.getVec3(context, "pos"), + FloatArgumentType.getFloat(context, "power"), + BoolArgumentType.getBool(context, "fire")))))) + .then(CommandManager.argument("entity", EntityArgumentType.entity()) + .executes(context -> execute( + context.getSource().getWorld(), + EntityArgumentType.getEntity(context, "entity"), + EntityArgumentType.getEntity(context, "entity").getPos(), + 4, + false)) + .then(CommandManager.argument("pos", Vec3ArgumentType.vec3()) + .executes(context -> execute( + context.getSource().getWorld(), + EntityArgumentType.getEntity(context, "entity"), + Vec3ArgumentType.getVec3(context, "pos"), + 4, + false)) + .then(CommandManager.argument("power", FloatArgumentType.floatArg(0)) + .executes(context -> execute( + context.getSource().getWorld(), + EntityArgumentType.getEntity(context, "entity"), + Vec3ArgumentType.getVec3(context, "pos"), + FloatArgumentType.getFloat(context, "power"), + false)) + .then(CommandManager.argument("fire", BoolArgumentType.bool()) + .executes(context -> execute( + context.getSource().getWorld(), + EntityArgumentType.getEntity(context, "entity"), + Vec3ArgumentType.getVec3(context, "pos"), + FloatArgumentType.getFloat(context, "power"), + BoolArgumentType.getBool(context, "fire")))))))); + } - private static int execute(World world, @Nullable Entity entity, Vec3d vec, float power, boolean fire) { - world.createExplosion(null, world.getDamageSources().explosion(null, entity), null, vec.getX(), vec.getY(), vec.getZ(), power, fire, World.ExplosionSourceType.TNT); - return 1; - } + private static int execute( + World world, @Nullable Entity entity, Vec3d vec, float power, boolean fire) { + world.createExplosion( + null, + world.getDamageSources().explosion(null, entity), + null, + vec.getX(), + vec.getY(), + vec.getZ(), + power, + fire, + World.ExplosionSourceType.TNT); + return 1; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/StoreDataCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/StoreDataCommand.java index 9691ea3..4667a58 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/StoreDataCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/StoreDataCommand.java @@ -1,5 +1,8 @@ package me.melontini.commander.impl.builtin.commands; +import java.util.Locale; +import java.util.Objects; +import java.util.function.Function; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.Selector; import me.melontini.commander.api.event.EventContext; @@ -9,42 +12,43 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.math.BlockPos; -import java.util.Locale; -import java.util.Objects; -import java.util.function.Function; - public interface StoreDataCommand extends Command { - @Override - default boolean execute(EventContext context) { - var opt = selector().select(context); - if (opt.isEmpty()) return false; + @Override + default boolean execute(EventContext context) { + var opt = selector().select(context); + if (opt.isEmpty()) return false; - var storage = target().select(opt.get()).getAttachedOrCreate(Commander.DATA_ATTACHMENT); - storage.put(key(), asElement(context)); - return true; - } + var storage = target().select(opt.get()).getAttachedOrCreate(Commander.DATA_ATTACHMENT); + storage.put(key(), asElement(context)); + return true; + } + + NbtElement asElement(EventContext context); - NbtElement asElement(EventContext context); + Target target(); - Target target(); - Selector.Conditioned selector(); - String key(); + Selector.Conditioned selector(); - enum Target { - LEVEL(ServerCommandSource::getWorld), - CHUNK(source -> source.getWorld().getChunk(BlockPos.ofFloored(source.getPosition()))), - ENTITY(ServerCommandSource::getEntity), - BLOCK_ENTITY(source -> source.getWorld().getBlockEntity(BlockPos.ofFloored(source.getPosition()))); + String key(); - private final Function function; + enum Target { + LEVEL(ServerCommandSource::getWorld), + CHUNK(source -> source.getWorld().getChunk(BlockPos.ofFloored(source.getPosition()))), + ENTITY(ServerCommandSource::getEntity), + BLOCK_ENTITY( + source -> source.getWorld().getBlockEntity(BlockPos.ofFloored(source.getPosition()))); - Target(Function function) { - this.function = function; - } + private final Function function; + + Target(Function function) { + this.function = function; + } - public AttachmentTarget select(ServerCommandSource source) { - return Objects.requireNonNull(this.function.apply(source), () -> "Source cannot be null! Type: %s".formatted(this.name().toLowerCase(Locale.ROOT))); - } + public AttachmentTarget select(ServerCommandSource source) { + return Objects.requireNonNull( + this.function.apply(source), + () -> "Source cannot be null! Type: %s".formatted(this.name().toLowerCase(Locale.ROOT))); } + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/action/CancelCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/action/CancelCommand.java index fede929..ab0ecff 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/action/CancelCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/action/CancelCommand.java @@ -19,31 +19,32 @@ import net.minecraft.util.dynamic.Codecs; @RequiredArgsConstructor public final class CancelCommand implements Command { - public static final MapCodec CODEC = Codecs.JSON_ELEMENT.fieldOf("value").xmap(CancelCommand::new, CancelCommand::element); - - private final JsonElement element; - private Object value;//This is not great - - @Override - public boolean execute(EventContext context) { - context.setReturnValue(value); - return true; - } - - @Override - public CommandType type() { - return BuiltInCommands.CANCEL; - } - - @Override - public DataResult validate(EventType type) { - if (type.get(EventType.CANCEL_TERM).isEmpty()) - return DataResult.error(() -> "Event '%s' does not support cancellation"); - - var val = type.get(EventType.CANCEL_TERM).orElseThrow().parse(JsonOps.INSTANCE, element); - if (val.error().isPresent()) return val.map(object -> null); - this.value = val.result().orElseThrow(); - - return Command.super.validate(type); - } + public static final MapCodec CODEC = + Codecs.JSON_ELEMENT.fieldOf("value").xmap(CancelCommand::new, CancelCommand::element); + + private final JsonElement element; + private Object value; // This is not great + + @Override + public boolean execute(EventContext context) { + context.setReturnValue(value); + return true; + } + + @Override + public CommandType type() { + return BuiltInCommands.CANCEL; + } + + @Override + public DataResult validate(EventType type) { + if (type.get(EventType.CANCEL_TERM).isEmpty()) + return DataResult.error(() -> "Event '%s' does not support cancellation"); + + var val = type.get(EventType.CANCEL_TERM).orElseThrow().parse(JsonOps.INSTANCE, element); + if (val.error().isPresent()) return val.map(object -> null); + this.value = val.result().orElseThrow(); + + return Command.super.validate(type); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/action/CommandCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/action/CommandCommand.java index 588f2ce..849b214 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/action/CommandCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/action/CommandCommand.java @@ -3,6 +3,7 @@ package me.melontini.commander.impl.builtin.commands.action; import com.mojang.datafixers.util.Either; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.List; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.CommandType; import me.melontini.commander.api.command.Selector; @@ -17,78 +18,87 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; -import java.util.List; +public record CommandCommand(Selector.Conditioned selector, InterFunction commands) + implements Command { -public record CommandCommand(Selector.Conditioned selector, InterFunction commands) implements Command { + public static final MapCodec CODEC = + RecordCodecBuilder.mapCodec(data -> data.group( + Selector.CODEC.fieldOf("selector").forGetter(CommandCommand::selector), + ExtraCodecs.either(BrigadierMacro.CODEC.listOf(), Identifier.CODEC) + .xmap( + e -> e.map(MacroedFunction::new, FunctionFunction::new), + InterFunction::origin) + .fieldOf("commands") + .forGetter(CommandCommand::commands)) + .apply(data, CommandCommand::new)); - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( - Selector.CODEC.fieldOf("selector").forGetter(CommandCommand::selector), - ExtraCodecs.either(BrigadierMacro.CODEC.listOf(), Identifier.CODEC) - .xmap(e -> e.map(MacroedFunction::new, FunctionFunction::new), InterFunction::origin) - .fieldOf("commands").forGetter(CommandCommand::commands) - ).apply(data, CommandCommand::new)); + @Override + public boolean execute(EventContext context) { + var opt = selector().select(context).map(ServerCommandSource::withSilent); + if (opt.isEmpty()) return false; + return commands().execute(context.lootContext(), opt.orElseThrow()); + } - @Override - public boolean execute(EventContext context) { - var opt = selector().select(context).map(ServerCommandSource::withSilent); - if (opt.isEmpty()) return false; - return commands().execute(context.lootContext(), opt.orElseThrow()); - } + @Override + public CommandType type() { + return BuiltInCommands.COMMANDS; + } - @Override - public CommandType type() { - return BuiltInCommands.COMMANDS; - } + private interface InterFunction { + boolean execute(LootContext context, ServerCommandSource source); - private interface InterFunction { - boolean execute(LootContext context, ServerCommandSource source); - Either, Identifier> origin(); - } + Either, Identifier> origin(); + } - private record MacroedFunction(List macros) implements InterFunction { + private record MacroedFunction(List macros) implements InterFunction { - @Override - public boolean execute(LootContext context, ServerCommandSource source) { - var server = context.getWorld().getServer(); + @Override + public boolean execute(LootContext context, ServerCommandSource source) { + var server = context.getWorld().getServer(); - for (BrigadierMacro command : macros()) { - try { - server.getCommandManager().executeWithPrefix(source, command.build(context)); - } catch (Throwable e) { - ServerHelper.broadcastToOps(server, Text.literal(command.original()).append(Text.literal(" failed execution! ")) - .append("%s: %s".formatted(e.getClass().getSimpleName(), e.getLocalizedMessage())).formatted(Formatting.RED)); - return false; - } - } - return true; + for (BrigadierMacro command : macros()) { + try { + server.getCommandManager().executeWithPrefix(source, command.build(context)); + } catch (Throwable e) { + ServerHelper.broadcastToOps( + server, + Text.literal(command.original()) + .append(Text.literal(" failed execution! ")) + .append("%s: %s".formatted(e.getClass().getSimpleName(), e.getLocalizedMessage())) + .formatted(Formatting.RED)); + return false; } + } + return true; + } - @Override - public Either, Identifier> origin() { - return Either.left(macros()); - } + @Override + public Either, Identifier> origin() { + return Either.left(macros()); } + } - private record FunctionFunction(Identifier identifier) implements InterFunction { + private record FunctionFunction(Identifier identifier) implements InterFunction { - @Override - public boolean execute(LootContext context, ServerCommandSource source) { - var server = context.getWorld().getServer(); + @Override + public boolean execute(LootContext context, ServerCommandSource source) { + var server = context.getWorld().getServer(); - var func = server.getCommandFunctionManager().getFunction(identifier()); - if (func.isPresent()) { - server.getCommandFunctionManager().execute(func.orElseThrow(), source); - return true; - } else { - ServerHelper.broadcastToOps(server, Text.literal("Unknown function %s!".formatted(identifier())) - .formatted(Formatting.RED)); - return false; - } - } + var func = server.getCommandFunctionManager().getFunction(identifier()); + if (func.isPresent()) { + server.getCommandFunctionManager().execute(func.orElseThrow(), source); + return true; + } else { + ServerHelper.broadcastToOps( + server, + Text.literal("Unknown function %s!".formatted(identifier())).formatted(Formatting.RED)); + return false; + } + } - @Override - public Either, Identifier> origin() { - return Either.right(identifier()); - } + @Override + public Either, Identifier> origin() { + return Either.right(identifier()); } + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintArithmeticaCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintArithmeticaCommand.java index 07acbf6..27ff1b1 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintArithmeticaCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintArithmeticaCommand.java @@ -9,16 +9,18 @@ import me.melontini.commander.impl.builtin.BuiltInCommands; public record PrintArithmeticaCommand(Arithmetica arithmetica) implements Command { - public static final MapCodec CODEC = Arithmetica.CODEC.xmap(PrintArithmeticaCommand::new, PrintArithmeticaCommand::arithmetica).fieldOf("value"); + public static final MapCodec CODEC = Arithmetica.CODEC + .xmap(PrintArithmeticaCommand::new, PrintArithmeticaCommand::arithmetica) + .fieldOf("value"); - @Override - public boolean execute(EventContext context) { - System.out.println(arithmetica().asDouble(context.lootContext())); - return true; - } + @Override + public boolean execute(EventContext context) { + System.out.println(arithmetica().asDouble(context.lootContext())); + return true; + } - @Override - public CommandType type() { - return BuiltInCommands.PRINT_ARITHMETICA; - } + @Override + public CommandType type() { + return BuiltInCommands.PRINT_ARITHMETICA; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintCommand.java index 7d4bf02..361bcc2 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/action/PrintCommand.java @@ -9,16 +9,17 @@ import me.melontini.commander.impl.builtin.BuiltInCommands; public record PrintCommand(String text) implements Command { - public static final MapCodec CODEC = Codec.STRING.fieldOf("text").xmap(PrintCommand::new, PrintCommand::text); + public static final MapCodec CODEC = + Codec.STRING.fieldOf("text").xmap(PrintCommand::new, PrintCommand::text); - @Override - public boolean execute(EventContext context) { - System.out.println(text()); - return true; - } + @Override + public boolean execute(EventContext context) { + System.out.println(text()); + return true; + } - @Override - public CommandType type() { - return BuiltInCommands.PRINT; - } + @Override + public CommandType type() { + return BuiltInCommands.PRINT; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AllOfCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AllOfCommand.java index 1aed115..0188aec 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AllOfCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AllOfCommand.java @@ -3,44 +3,48 @@ package me.melontini.commander.impl.builtin.commands.logic; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.List; +import java.util.Optional; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.CommandType; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.impl.builtin.BuiltInCommands; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; -import java.util.List; -import java.util.Optional; +public record AllOfCommand( + List commands, Optional then, boolean shortCircuit) + implements Command { -public record AllOfCommand(List commands, Optional then, boolean shortCircuit) implements Command { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( + ExtraCodecs.list(Command.CODEC.codec()) + .fieldOf("commands") + .forGetter(AllOfCommand::commands), + ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(AllOfCommand::then), + ExtraCodecs.optional("short_circuit", Codec.BOOL, false) + .forGetter(AllOfCommand::shortCircuit)) + .apply(data, AllOfCommand::new)); - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( - ExtraCodecs.list(Command.CODEC.codec()).fieldOf("commands").forGetter(AllOfCommand::commands), - ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(AllOfCommand::then), - ExtraCodecs.optional("short_circuit", Codec.BOOL, false).forGetter(AllOfCommand::shortCircuit) - ).apply(data, AllOfCommand::new)); - - @Override - public boolean execute(EventContext context) { - if (!shortCircuit) { - boolean b = true; - for (Conditioned command : commands()) { - b &= command.execute(context); - } - if (b) { - return then().map(cc -> cc.execute(context)).orElse(true); - } - return false; - } - - for (Conditioned command : commands()) { - if (!command.execute(context)) return false; - } + @Override + public boolean execute(EventContext context) { + if (!shortCircuit) { + boolean b = true; + for (Conditioned command : commands()) { + b &= command.execute(context); + } + if (b) { return then().map(cc -> cc.execute(context)).orElse(true); + } + return false; } - @Override - public CommandType type() { - return BuiltInCommands.ALL_OF; + for (Conditioned command : commands()) { + if (!command.execute(context)) return false; } + return then().map(cc -> cc.execute(context)).orElse(true); + } + + @Override + public CommandType type() { + return BuiltInCommands.ALL_OF; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AnyOfCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AnyOfCommand.java index 9090934..be1951b 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AnyOfCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/AnyOfCommand.java @@ -3,44 +3,48 @@ package me.melontini.commander.impl.builtin.commands.logic; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.List; +import java.util.Optional; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.CommandType; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.impl.builtin.BuiltInCommands; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; -import java.util.List; -import java.util.Optional; +public record AnyOfCommand( + List commands, Optional then, boolean shortCircuit) + implements Command { -public record AnyOfCommand(List commands, Optional then, boolean shortCircuit) implements Command { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( + ExtraCodecs.list(Command.CODEC.codec()) + .fieldOf("commands") + .forGetter(AnyOfCommand::commands), + ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(AnyOfCommand::then), + ExtraCodecs.optional("short_circuit", Codec.BOOL, false) + .forGetter(AnyOfCommand::shortCircuit)) + .apply(data, AnyOfCommand::new)); - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( - ExtraCodecs.list(Command.CODEC.codec()).fieldOf("commands").forGetter(AnyOfCommand::commands), - ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(AnyOfCommand::then), - ExtraCodecs.optional("short_circuit", Codec.BOOL, false).forGetter(AnyOfCommand::shortCircuit) - ).apply(data, AnyOfCommand::new)); - - @Override - public boolean execute(EventContext context) { - if (!shortCircuit) { - boolean b = false; - for (Command.Conditioned command : commands()) { - b |= command.execute(context); - } - if (b) { - return then().map(cc -> cc.execute(context)).orElse(true); - } - return false; - } - - for (Command.Conditioned command : commands()) { - if (command.execute(context)) return then().map(cc -> cc.execute(context)).orElse(true); - } - return false; + @Override + public boolean execute(EventContext context) { + if (!shortCircuit) { + boolean b = false; + for (Command.Conditioned command : commands()) { + b |= command.execute(context); + } + if (b) { + return then().map(cc -> cc.execute(context)).orElse(true); + } + return false; } - @Override - public CommandType type() { - return BuiltInCommands.ANY_OF; + for (Command.Conditioned command : commands()) { + if (command.execute(context)) return then().map(cc -> cc.execute(context)).orElse(true); } + return false; + } + + @Override + public CommandType type() { + return BuiltInCommands.ANY_OF; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/DefaultedCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/DefaultedCommand.java index 95b6156..7e8c074 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/DefaultedCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/DefaultedCommand.java @@ -3,44 +3,50 @@ package me.melontini.commander.impl.builtin.commands.logic; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.List; +import java.util.Optional; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.CommandType; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.impl.builtin.BuiltInCommands; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; -import java.util.List; -import java.util.Optional; +public record DefaultedCommand( + List commands, Optional then, boolean shortCircuit) + implements Command { -public record DefaultedCommand(List commands, Optional then, boolean shortCircuit) implements Command { + public static final MapCodec CODEC = + RecordCodecBuilder.mapCodec(data -> data.group( + ExtraCodecs.list(Command.CODEC.codec()) + .fieldOf("commands") + .forGetter(DefaultedCommand::commands), + ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(DefaultedCommand::then), + ExtraCodecs.optional("short_circuit", Codec.BOOL, false) + .forGetter(DefaultedCommand::shortCircuit)) + .apply(data, DefaultedCommand::new)); - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( - ExtraCodecs.list(Command.CODEC.codec()).fieldOf("commands").forGetter(DefaultedCommand::commands), - ExtraCodecs.optional("then", Command.CODEC.codec()).forGetter(DefaultedCommand::then), - ExtraCodecs.optional("short_circuit", Codec.BOOL, false).forGetter(DefaultedCommand::shortCircuit) - ).apply(data, DefaultedCommand::new)); - - @Override - public boolean execute(EventContext context) { - if (!shortCircuit) { - boolean b = false; - for (Command.Conditioned command : commands()) { - b |= command.execute(context); - } - if (!b) { - return then().map(cc -> cc.execute(context)).orElse(false); - } - return true; - } - - for (Command.Conditioned command : commands()) { - if (!command.execute(context)) return then().map(cc -> cc.execute(context)).orElse(false); - } - return true; + @Override + public boolean execute(EventContext context) { + if (!shortCircuit) { + boolean b = false; + for (Command.Conditioned command : commands()) { + b |= command.execute(context); + } + if (!b) { + return then().map(cc -> cc.execute(context)).orElse(false); + } + return true; } - @Override - public CommandType type() { - return BuiltInCommands.DEFAULTED; + for (Command.Conditioned command : commands()) { + if (!command.execute(context)) + return then().map(cc -> cc.execute(context)).orElse(false); } + return true; + } + + @Override + public CommandType type() { + return BuiltInCommands.DEFAULTED; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/RandomCommand.java b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/RandomCommand.java index 796fd36..a24138f 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/commands/logic/RandomCommand.java +++ b/src/main/java/me/melontini/commander/impl/builtin/commands/logic/RandomCommand.java @@ -10,26 +10,31 @@ import me.melontini.commander.impl.builtin.BuiltInCommands; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.util.collection.WeightedList; -public record RandomCommand(WeightedList commands, Arithmetica rolls) implements Command { +public record RandomCommand(WeightedList commands, Arithmetica rolls) + implements Command { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(data -> data.group( - ExtraCodecs.weightedList(Command.CODEC.codec()).fieldOf("commands").forGetter(RandomCommand::commands), - ExtraCodecs.optional("rolls", Arithmetica.CODEC, Arithmetica.constant(1)).forGetter(RandomCommand::rolls) - ).apply(data, RandomCommand::new)); + public static final MapCodec CODEC = + RecordCodecBuilder.mapCodec(data -> data.group( + ExtraCodecs.weightedList(Command.CODEC.codec()) + .fieldOf("commands") + .forGetter(RandomCommand::commands), + ExtraCodecs.optional("rolls", Arithmetica.CODEC, Arithmetica.constant(1)) + .forGetter(RandomCommand::rolls)) + .apply(data, RandomCommand::new)); - @Override - public boolean execute(EventContext context) { - boolean b = false; - int rolls = rolls().asInt(context.lootContext()); - for (int i = 0; i < rolls; i++) { - var itr = this.commands().shuffle().iterator(); - if (itr.hasNext()) b |= itr.next().execute(context); - } - return b; + @Override + public boolean execute(EventContext context) { + boolean b = false; + int rolls = rolls().asInt(context.lootContext()); + for (int i = 0; i < rolls; i++) { + var itr = this.commands().shuffle().iterator(); + if (itr.hasNext()) b |= itr.next().execute(context); } + return b; + } - @Override - public CommandType type() { - return BuiltInCommands.RANDOM; - } + @Override + public CommandType type() { + return BuiltInCommands.RANDOM; + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/events/EntityEvents.java b/src/main/java/me/melontini/commander/impl/builtin/events/EntityEvents.java index 514b0df..8703e50 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/events/EntityEvents.java +++ b/src/main/java/me/melontini/commander/impl/builtin/events/EntityEvents.java @@ -1,6 +1,11 @@ package me.melontini.commander.impl.builtin.events; +import static me.melontini.commander.api.util.EventExecutors.*; +import static me.melontini.commander.impl.Commander.id; +import static net.minecraft.loot.context.LootContextParameters.*; + import com.mojang.serialization.Codec; +import java.util.Objects; import lombok.experimental.UtilityClass; import me.melontini.commander.api.event.EventType; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; @@ -19,60 +24,102 @@ import net.minecraft.util.ActionResult; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.Nullable; -import java.util.Objects; - -import static me.melontini.commander.api.util.EventExecutors.*; -import static me.melontini.commander.impl.Commander.id; -import static net.minecraft.loot.context.LootContextParameters.*; - @UtilityClass public class EntityEvents { - public static final EventType ALLOW_DAMAGE = EventType.builder().cancelTerm(Codec.BOOL).build(id("allow_damage")); - public static final EventType ALLOW_DEATH = EventType.builder().cancelTerm(Codec.BOOL).build(id("allow_death")); - public static final EventType AFTER_DEATH = EventType.builder().build(id("after_death")); + public static final EventType ALLOW_DAMAGE = + EventType.builder().cancelTerm(Codec.BOOL).build(id("allow_damage")); + public static final EventType ALLOW_DEATH = + EventType.builder().cancelTerm(Codec.BOOL).build(id("allow_death")); + public static final EventType AFTER_DEATH = EventType.builder().build(id("after_death")); - public static final EventType START_SLEEPING = EventType.builder().build(id("sleeping/start")); - public static final EventType STOP_SLEEPING = EventType.builder().build(id("sleeping/stop")); - public static final EventType ALLOW_SLEEPING = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(PlayerEntity.SleepFailureReason.class)).build(id("sleeping/allow")); - public static final EventType ALLOW_SLEEP_TIME = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("sleeping/allow_time")); - public static final EventType ALLOW_NEARBY_MONSTERS = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("sleeping/allow_nearby_monsters")); + public static final EventType START_SLEEPING = EventType.builder().build(id("sleeping/start")); + public static final EventType STOP_SLEEPING = EventType.builder().build(id("sleeping/stop")); + public static final EventType ALLOW_SLEEPING = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(PlayerEntity.SleepFailureReason.class)) + .build(id("sleeping/allow")); + public static final EventType ALLOW_SLEEP_TIME = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("sleeping/allow_time")); + public static final EventType ALLOW_NEARBY_MONSTERS = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("sleeping/allow_nearby_monsters")); - public static final EventType ALLOW_ELYTRA = EventType.builder().cancelTerm(Codec.BOOL).build(id("elytra_flight/allow")); - //public static final EventType CUSTOM_ELYTRA = EventType.builder().cancelTerm(Codec.BOOL).build(id("elytra_flight/custom")); + public static final EventType ALLOW_ELYTRA = + EventType.builder().cancelTerm(Codec.BOOL).build(id("elytra_flight/allow")); + // public static final EventType CUSTOM_ELYTRA = + // EventType.builder().cancelTerm(Codec.BOOL).build(id("elytra_flight/custom")); - public static final EventType AFTER_KILLED_BY_OTHER = EventType.builder().build(id("after_killed_by_other")); + public static final EventType AFTER_KILLED_BY_OTHER = + EventType.builder().build(id("after_killed_by_other")); - public static void init() { - ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> runBoolean(ALLOW_DAMAGE, entity.getWorld(), () -> makeContext(entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); - ServerLivingEntityEvents.ALLOW_DEATH.register((entity, source, damageAmount) -> runBoolean(ALLOW_DEATH, entity.getWorld(), () -> makeContext(entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); + public static void init() { + ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> runBoolean( + ALLOW_DAMAGE, + entity.getWorld(), + () -> makeContext( + entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); + ServerLivingEntityEvents.ALLOW_DEATH.register((entity, source, damageAmount) -> runBoolean( + ALLOW_DEATH, + entity.getWorld(), + () -> makeContext( + entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); - ServerLivingEntityEvents.AFTER_DEATH.register((entity, source) -> runVoid(AFTER_DEATH, entity.getWorld(), () -> makeContext(entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); + ServerLivingEntityEvents.AFTER_DEATH.register((entity, source) -> runVoid( + AFTER_DEATH, + entity.getWorld(), + () -> makeContext( + entity, Objects.requireNonNullElse(source.getPosition(), entity.getPos()), source))); - EntitySleepEvents.START_SLEEPING.register((entity, sleepingPos) -> runVoid(START_SLEEPING, entity.getWorld(), () -> makeContext(entity, Vec3d.ofCenter(sleepingPos), null))); - EntitySleepEvents.STOP_SLEEPING.register((entity, sleepingPos) -> runVoid(STOP_SLEEPING, entity.getWorld(), () -> makeContext(entity, Vec3d.ofCenter(sleepingPos), null))); - EntitySleepEvents.ALLOW_SLEEPING.register((player, sleepingPos) -> runEnum(ALLOW_SLEEPING, null, player.getWorld(), () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); - EntitySleepEvents.ALLOW_SLEEP_TIME.register((player, sleepingPos, vanillaResult) -> runActionResult(ALLOW_SLEEP_TIME, player.getWorld(), () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); - EntitySleepEvents.ALLOW_NEARBY_MONSTERS.register((player, sleepingPos, vanillaResult) -> runActionResult(ALLOW_NEARBY_MONSTERS, player.getWorld(), () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); + EntitySleepEvents.START_SLEEPING.register((entity, sleepingPos) -> runVoid( + START_SLEEPING, + entity.getWorld(), + () -> makeContext(entity, Vec3d.ofCenter(sleepingPos), null))); + EntitySleepEvents.STOP_SLEEPING.register((entity, sleepingPos) -> runVoid( + STOP_SLEEPING, + entity.getWorld(), + () -> makeContext(entity, Vec3d.ofCenter(sleepingPos), null))); + EntitySleepEvents.ALLOW_SLEEPING.register((player, sleepingPos) -> runEnum( + ALLOW_SLEEPING, + null, + player.getWorld(), + () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); + EntitySleepEvents.ALLOW_SLEEP_TIME.register( + (player, sleepingPos, vanillaResult) -> runActionResult( + ALLOW_SLEEP_TIME, + player.getWorld(), + () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); + EntitySleepEvents.ALLOW_NEARBY_MONSTERS.register( + (player, sleepingPos, vanillaResult) -> runActionResult( + ALLOW_NEARBY_MONSTERS, + player.getWorld(), + () -> makeContext(player, Vec3d.ofCenter(sleepingPos), null))); - EntityElytraEvents.ALLOW.register(entity -> runBoolean(ALLOW_ELYTRA, entity.getWorld(), () -> makeContext(entity, entity.getPos(), null))); + EntityElytraEvents.ALLOW.register(entity -> runBoolean( + ALLOW_ELYTRA, entity.getWorld(), () -> makeContext(entity, entity.getPos(), null))); - ServerEntityCombatEvents.AFTER_KILLED_OTHER_ENTITY.register((world, entity, killedEntity) -> runVoid(AFTER_KILLED_BY_OTHER, world, () -> { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) entity.getWorld()); - builder.add(THIS_ENTITY, killedEntity).add(ORIGIN, killedEntity.getPos()); - builder.add(DAMAGE_SOURCE, world.getDamageSources().generic()).add(KILLER_ENTITY, entity); - return new LootContext.Builder(builder.build(LootContextTypes.ENTITY)).build(null); + ServerEntityCombatEvents.AFTER_KILLED_OTHER_ENTITY.register( + (world, entity, killedEntity) -> runVoid(AFTER_KILLED_BY_OTHER, world, () -> { + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder((ServerWorld) entity.getWorld()); + builder.add(THIS_ENTITY, killedEntity).add(ORIGIN, killedEntity.getPos()); + builder.add(DAMAGE_SOURCE, world.getDamageSources().generic()).add(KILLER_ENTITY, entity); + return new LootContext.Builder(builder.build(LootContextTypes.ENTITY)).build(null); })); - } + } - private static LootContext makeContext(Entity entity, Vec3d origin, @Nullable DamageSource source) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) entity.getWorld()); - builder.add(THIS_ENTITY, entity).add(ORIGIN, origin); - if (source != null) { - builder.add(DAMAGE_SOURCE, source); - builder.addOptional(DIRECT_KILLER_ENTITY, source.getAttacker()); - builder.addOptional(KILLER_ENTITY, source.getSource()); - } - return new LootContext.Builder(builder.build(source == null ? LootContextTypes.COMMAND : LootContextTypes.ENTITY)).build(null); + private static LootContext makeContext( + Entity entity, Vec3d origin, @Nullable DamageSource source) { + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder((ServerWorld) entity.getWorld()); + builder.add(THIS_ENTITY, entity).add(ORIGIN, origin); + if (source != null) { + builder.add(DAMAGE_SOURCE, source); + builder.addOptional(DIRECT_KILLER_ENTITY, source.getAttacker()); + builder.addOptional(KILLER_ENTITY, source.getSource()); } + return new LootContext.Builder( + builder.build(source == null ? LootContextTypes.COMMAND : LootContextTypes.ENTITY)) + .build(null); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/events/PlayerEvents.java b/src/main/java/me/melontini/commander/impl/builtin/events/PlayerEvents.java index 3c30449..aa92ed1 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/events/PlayerEvents.java +++ b/src/main/java/me/melontini/commander/impl/builtin/events/PlayerEvents.java @@ -1,5 +1,8 @@ package me.melontini.commander.impl.builtin.events; +import static me.melontini.commander.impl.Commander.id; +import static net.minecraft.loot.context.LootContextParameters.*; + import com.mojang.serialization.Codec; import lombok.experimental.UtilityClass; import me.melontini.commander.api.event.EventType; @@ -24,77 +27,126 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; -import static me.melontini.commander.impl.Commander.id; -import static net.minecraft.loot.context.LootContextParameters.*; - @UtilityClass public class PlayerEvents { - public static final EventType ATTACK_BLOCK = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("player_attack/block")); - public static final EventType USE_BLOCK = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("player_use/block")); - - public static final EventType ATTACK_ENTITY = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("player_attack/entity")); - public static final EventType USE_ENTITY = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("player_use/entity")); - - public static final EventType USE_ITEM = EventType.builder().cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)).build(id("player_use/item")); - - public static final EventType BEFORE_BREAK = EventType.builder().cancelTerm(Codec.BOOL).build(id("player_break_block/before")); - public static final EventType AFTER_BREAK = EventType.builder().build(id("player_break_block/after")); - public static final EventType CANCELLED_BREAK = EventType.builder().build(id("player_break_block/cancelled")); - - public static void init() { - AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> blockCallback(ATTACK_BLOCK, world, player, player.getStackInHand(hand), Vec3d.ofCenter(pos), pos)); - UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> blockCallback(USE_BLOCK, world, player, player.getStackInHand(hand), hitResult.getPos(), hitResult.getBlockPos())); - - AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> entityCallback(ATTACK_ENTITY, world, player, hand, entity)); - UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> entityCallback(USE_ENTITY, world, player, hand, entity)); - - UseItemCallback.EVENT.register((player, world, hand) -> new TypedActionResult<>(EventExecutors.runActionResult(USE_ITEM, world, () -> { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) world) - .add(THIS_ENTITY, player) - .add(ORIGIN, player.getPos()) - .add(TOOL, player.getStackInHand(hand)); - return new LootContext.Builder(builder.build(LootContextTypes.FISHING)).build(null); - }), player.getStackInHand(hand))); - - PlayerBlockBreakEvents.BEFORE.register((world, player, pos, state, blockEntity) -> EventExecutors.runBoolean(BEFORE_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); - PlayerBlockBreakEvents.AFTER.register((world, player, pos, state, blockEntity) -> EventExecutors.runVoid(AFTER_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); - PlayerBlockBreakEvents.CANCELED.register((world, player, pos, state, blockEntity) -> EventExecutors.runVoid(CANCELLED_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); - } - - private static LootContext breakContext(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) world) - .add(THIS_ENTITY, player).add(ORIGIN, Vec3d.ofCenter(pos)) - .add(BLOCK_STATE, state).add(TOOL, ItemStack.EMPTY) - .addOptional(BLOCK_ENTITY, blockEntity); - return new LootContext.Builder(builder.build(LootContextTypes.BLOCK)).build(null); - } - - private static ActionResult entityCallback(EventType type, World world, PlayerEntity player, Hand hand, Entity entity) { - if (world.isClient()) return ActionResult.PASS; - return EventExecutors.runActionResult(type, world, () -> { - ItemStack tool = player.getStackInHand(hand); - DamageSource source = world.getDamageSources().generic(); - - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) world) - .add(THIS_ENTITY, entity).add(ORIGIN, entity.getPos()) - .add(TOOL, tool).add(LAST_DAMAGE_PLAYER, player) - .add(DAMAGE_SOURCE, source); - return new LootContext.Builder(builder.build(LootContextTypes.ENTITY)).build(null); - }); - } - - private static ActionResult blockCallback(EventType type, World world, PlayerEntity player, ItemStack tool, Vec3d origin, BlockPos pos) { - if (world.isClient()) return ActionResult.PASS; - return EventExecutors.runActionResult(type, world, () -> { - BlockState state = world.getBlockState(pos); - BlockEntity blockEntity = world.getBlockEntity(pos); - - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder((ServerWorld) world) - .add(THIS_ENTITY, player).add(ORIGIN,origin) - .add(BLOCK_STATE, state).add(TOOL, tool) - .addOptional(BLOCK_ENTITY, blockEntity); - return new LootContext.Builder(builder.build(LootContextTypes.BLOCK)).build(null); - }); - } + public static final EventType ATTACK_BLOCK = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("player_attack/block")); + public static final EventType USE_BLOCK = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("player_use/block")); + + public static final EventType ATTACK_ENTITY = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("player_attack/entity")); + public static final EventType USE_ENTITY = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("player_use/entity")); + + public static final EventType USE_ITEM = EventType.builder() + .cancelTerm(ExtraCodecs.enumCodec(ActionResult.class)) + .build(id("player_use/item")); + + public static final EventType BEFORE_BREAK = + EventType.builder().cancelTerm(Codec.BOOL).build(id("player_break_block/before")); + public static final EventType AFTER_BREAK = + EventType.builder().build(id("player_break_block/after")); + public static final EventType CANCELLED_BREAK = + EventType.builder().build(id("player_break_block/cancelled")); + + public static void init() { + AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> blockCallback( + ATTACK_BLOCK, world, player, player.getStackInHand(hand), Vec3d.ofCenter(pos), pos)); + UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> blockCallback( + USE_BLOCK, + world, + player, + player.getStackInHand(hand), + hitResult.getPos(), + hitResult.getBlockPos())); + + AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> + entityCallback(ATTACK_ENTITY, world, player, hand, entity)); + UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> + entityCallback(USE_ENTITY, world, player, hand, entity)); + + UseItemCallback.EVENT.register((player, world, hand) -> new TypedActionResult<>( + EventExecutors.runActionResult(USE_ITEM, world, () -> { + LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder( + (ServerWorld) world) + .add(THIS_ENTITY, player) + .add(ORIGIN, player.getPos()) + .add(TOOL, player.getStackInHand(hand)); + return new LootContext.Builder(builder.build(LootContextTypes.FISHING)).build(null); + }), + player.getStackInHand(hand))); + + PlayerBlockBreakEvents.BEFORE.register( + (world, player, pos, state, blockEntity) -> EventExecutors.runBoolean( + BEFORE_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); + PlayerBlockBreakEvents.AFTER.register( + (world, player, pos, state, blockEntity) -> EventExecutors.runVoid( + AFTER_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); + PlayerBlockBreakEvents.CANCELED.register( + (world, player, pos, state, blockEntity) -> EventExecutors.runVoid( + CANCELLED_BREAK, world, () -> breakContext(world, player, pos, state, blockEntity))); + } + + private static LootContext breakContext( + World world, + PlayerEntity player, + BlockPos pos, + BlockState state, + @Nullable BlockEntity blockEntity) { + LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder( + (ServerWorld) world) + .add(THIS_ENTITY, player) + .add(ORIGIN, Vec3d.ofCenter(pos)) + .add(BLOCK_STATE, state) + .add(TOOL, ItemStack.EMPTY) + .addOptional(BLOCK_ENTITY, blockEntity); + return new LootContext.Builder(builder.build(LootContextTypes.BLOCK)).build(null); + } + + private static ActionResult entityCallback( + EventType type, World world, PlayerEntity player, Hand hand, Entity entity) { + if (world.isClient()) return ActionResult.PASS; + return EventExecutors.runActionResult(type, world, () -> { + ItemStack tool = player.getStackInHand(hand); + DamageSource source = world.getDamageSources().generic(); + + LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder( + (ServerWorld) world) + .add(THIS_ENTITY, entity) + .add(ORIGIN, entity.getPos()) + .add(TOOL, tool) + .add(LAST_DAMAGE_PLAYER, player) + .add(DAMAGE_SOURCE, source); + return new LootContext.Builder(builder.build(LootContextTypes.ENTITY)).build(null); + }); + } + + private static ActionResult blockCallback( + EventType type, + World world, + PlayerEntity player, + ItemStack tool, + Vec3d origin, + BlockPos pos) { + if (world.isClient()) return ActionResult.PASS; + return EventExecutors.runActionResult(type, world, () -> { + BlockState state = world.getBlockState(pos); + BlockEntity blockEntity = world.getBlockEntity(pos); + + LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder( + (ServerWorld) world) + .add(THIS_ENTITY, player) + .add(ORIGIN, origin) + .add(BLOCK_STATE, state) + .add(TOOL, tool) + .addOptional(BLOCK_ENTITY, blockEntity); + return new LootContext.Builder(builder.build(LootContextTypes.BLOCK)).build(null); + }); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/events/ServerLifecycle.java b/src/main/java/me/melontini/commander/impl/builtin/events/ServerLifecycle.java index dafdcc2..a15597b 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/events/ServerLifecycle.java +++ b/src/main/java/me/melontini/commander/impl/builtin/events/ServerLifecycle.java @@ -1,5 +1,8 @@ package me.melontini.commander.impl.builtin.events; +import static me.melontini.commander.api.util.EventExecutors.runVoid; +import static me.melontini.commander.impl.Commander.id; + import me.melontini.commander.api.event.EventType; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; @@ -13,54 +16,62 @@ import net.minecraft.loot.context.LootContextTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Vec3d; -import static me.melontini.commander.api.util.EventExecutors.runVoid; -import static me.melontini.commander.impl.Commander.id; - public class ServerLifecycle { - public static final EventType SERVER_STARTED = EventType.builder().build(id("server/started")); - public static final EventType SERVER_STOPPING = EventType.builder().build(id("server/stopping")); + public static final EventType SERVER_STARTED = EventType.builder().build(id("server/started")); + public static final EventType SERVER_STOPPING = EventType.builder().build(id("server/stopping")); - public static final EventType WORLD_LOAD = EventType.builder().build(id("world/load")); - public static final EventType WORLD_UNLOAD = EventType.builder().build(id("world/unload")); + public static final EventType WORLD_LOAD = EventType.builder().build(id("world/load")); + public static final EventType WORLD_UNLOAD = EventType.builder().build(id("world/unload")); - public static final EventType CHUNK_LOAD = EventType.builder().build(id("chunk/load")); - public static final EventType CHUNK_UNLOAD = EventType.builder().build(id("chunk/unload")); + public static final EventType CHUNK_LOAD = EventType.builder().build(id("chunk/load")); + public static final EventType CHUNK_UNLOAD = EventType.builder().build(id("chunk/unload")); - public static final EventType ENTITY_LOAD = EventType.builder().build(id("entity/load")); - public static final EventType ENTITY_UNLOAD = EventType.builder().build(id("entity/unload")); + public static final EventType ENTITY_LOAD = EventType.builder().build(id("entity/load")); + public static final EventType ENTITY_UNLOAD = EventType.builder().build(id("entity/unload")); - public static void init() { - ServerLifecycleEvents.SERVER_STARTED.register(server -> runVoid(SERVER_STARTED, server.getOverworld(), () -> forWorld(server.getOverworld()))); - ServerLifecycleEvents.SERVER_STOPPING.register(server -> { - if (server.getOverworld() != null) //If the server crashes at a specific moment, this event may be triggered, but the worlds are not yet loaded. - runVoid(SERVER_STOPPING, server.getOverworld(), () -> forWorld(server.getOverworld())); - }); + public static void init() { + ServerLifecycleEvents.SERVER_STARTED.register(server -> + runVoid(SERVER_STARTED, server.getOverworld(), () -> forWorld(server.getOverworld()))); + ServerLifecycleEvents.SERVER_STOPPING.register(server -> { + if (server.getOverworld() + != null) // If the server crashes at a specific moment, this event may be triggered, but + // the worlds are not yet loaded. + runVoid(SERVER_STOPPING, server.getOverworld(), () -> forWorld(server.getOverworld())); + }); - ServerWorldEvents.LOAD.register((server, world) -> runVoid(WORLD_LOAD, world, () -> forWorld(world))); - ServerWorldEvents.UNLOAD.register((server, world) -> runVoid(WORLD_UNLOAD, world, () -> forWorld(world))); + ServerWorldEvents.LOAD.register( + (server, world) -> runVoid(WORLD_LOAD, world, () -> forWorld(world))); + ServerWorldEvents.UNLOAD.register( + (server, world) -> runVoid(WORLD_UNLOAD, world, () -> forWorld(world))); - ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> runVoid(CHUNK_LOAD, world, () -> forWorld(world, Vec3d.of(chunk.getPos().getStartPos())))); - ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> runVoid(CHUNK_UNLOAD, world, () -> forWorld(world, Vec3d.of(chunk.getPos().getStartPos())))); + ServerChunkEvents.CHUNK_LOAD.register((world, chunk) -> + runVoid(CHUNK_LOAD, world, () -> forWorld(world, Vec3d.of(chunk.getPos().getStartPos())))); + ServerChunkEvents.CHUNK_UNLOAD.register((world, chunk) -> runVoid( + CHUNK_UNLOAD, world, () -> forWorld(world, Vec3d.of(chunk.getPos().getStartPos())))); - ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> runVoid(ENTITY_LOAD, world, () -> forEntity(world, entity))); - ServerEntityEvents.ENTITY_UNLOAD.register((entity, world) -> runVoid(ENTITY_UNLOAD, world, () -> forEntity(world, entity))); - } + ServerEntityEvents.ENTITY_LOAD.register( + (entity, world) -> runVoid(ENTITY_LOAD, world, () -> forEntity(world, entity))); + ServerEntityEvents.ENTITY_UNLOAD.register( + (entity, world) -> runVoid(ENTITY_UNLOAD, world, () -> forEntity(world, entity))); + } - private static LootContext forEntity(ServerWorld world, Entity entity) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(world) - .add(LootContextParameters.ORIGIN, entity.getPos()) - .add(LootContextParameters.THIS_ENTITY, entity); - return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); - } + private static LootContext forEntity(ServerWorld world, Entity entity) { + LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(world) + .add(LootContextParameters.ORIGIN, entity.getPos()) + .add(LootContextParameters.THIS_ENTITY, entity); + return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); + } - private static LootContext forWorld(ServerWorld world, Vec3d origin) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, origin); - return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); - } + private static LootContext forWorld(ServerWorld world, Vec3d origin) { + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, origin); + return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); + } - private static LootContext forWorld(ServerWorld world) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, Vec3d.ZERO); - return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); - } + private static LootContext forWorld(ServerWorld world) { + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, Vec3d.ZERO); + return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); + } } diff --git a/src/main/java/me/melontini/commander/impl/builtin/events/ServerTick.java b/src/main/java/me/melontini/commander/impl/builtin/events/ServerTick.java index 089ac64..95acafd 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/events/ServerTick.java +++ b/src/main/java/me/melontini/commander/impl/builtin/events/ServerTick.java @@ -1,5 +1,8 @@ package me.melontini.commander.impl.builtin.events; +import static me.melontini.commander.api.util.EventExecutors.runVoid; +import static me.melontini.commander.impl.Commander.id; + import lombok.experimental.UtilityClass; import me.melontini.commander.api.event.EventType; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; @@ -10,27 +13,30 @@ import net.minecraft.loot.context.LootContextTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Vec3d; -import static me.melontini.commander.api.util.EventExecutors.runVoid; -import static me.melontini.commander.impl.Commander.id; - @UtilityClass public class ServerTick { - public static final EventType START_TICK = EventType.builder().build(id("server_tick/start")); - public static final EventType END_TICK = EventType.builder().build(id("server_tick/end")); - public static final EventType START_WORLD_TICK = EventType.builder().build(id("world_tick/start")); - public static final EventType END_WORLD_TICK = EventType.builder().build(id("world_tick/end")); + public static final EventType START_TICK = EventType.builder().build(id("server_tick/start")); + public static final EventType END_TICK = EventType.builder().build(id("server_tick/end")); + public static final EventType START_WORLD_TICK = + EventType.builder().build(id("world_tick/start")); + public static final EventType END_WORLD_TICK = EventType.builder().build(id("world_tick/end")); - public static void init() { - ServerTickEvents.START_SERVER_TICK.register(server -> runVoid(START_TICK, server.getOverworld(), () -> forWorld(server.getOverworld()))); - ServerTickEvents.END_SERVER_TICK.register(server -> runVoid(END_TICK, server.getOverworld(), () -> forWorld(server.getOverworld()))); + public static void init() { + ServerTickEvents.START_SERVER_TICK.register(server -> + runVoid(START_TICK, server.getOverworld(), () -> forWorld(server.getOverworld()))); + ServerTickEvents.END_SERVER_TICK.register( + server -> runVoid(END_TICK, server.getOverworld(), () -> forWorld(server.getOverworld()))); - ServerTickEvents.START_WORLD_TICK.register((world) -> runVoid(START_WORLD_TICK, world, () -> forWorld(world))); - ServerTickEvents.END_WORLD_TICK.register((world) -> runVoid(END_WORLD_TICK, world, () -> forWorld(world))); - } + ServerTickEvents.START_WORLD_TICK.register( + (world) -> runVoid(START_WORLD_TICK, world, () -> forWorld(world))); + ServerTickEvents.END_WORLD_TICK.register( + (world) -> runVoid(END_WORLD_TICK, world, () -> forWorld(world))); + } - private static LootContext forWorld(ServerWorld world) { - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, Vec3d.ZERO); - return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); - } + private static LootContext forWorld(ServerWorld world) { + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder(world).add(LootContextParameters.ORIGIN, Vec3d.ZERO); + return new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); + } } diff --git a/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java b/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java index 679f938..253c562 100644 --- a/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java +++ b/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java @@ -1,6 +1,9 @@ package me.melontini.commander.impl.command; import com.mojang.serialization.*; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.api.event.EventType; @@ -8,42 +11,52 @@ import me.melontini.commander.impl.event.data.types.CommandTypes; import me.melontini.commander.impl.util.MagicCodecs; import net.minecraft.loot.condition.LootCondition; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; - -public record ConditionedCommand(Optional condition, Command other) implements Command.Conditioned { +public record ConditionedCommand(Optional condition, Command other) + implements Command.Conditioned { - public static final MapCodec CODEC = new MapCodec() { + public static final MapCodec CODEC = + new MapCodec() { @Override - public RecordBuilder encode(ConditionedCommand input, DynamicOps ops, RecordBuilder prefix) { - var r = ((MapCodecCodec) CommandTypes.CODEC).codec().encode(input.other(), ops, prefix); - input.condition().map(condition1 -> MagicCodecs.LOOT_CONDITION.encodeStart(ops, condition1)).ifPresent(tDataResult -> r.add("condition", tDataResult)); - return r; + public RecordBuilder encode( + ConditionedCommand input, DynamicOps ops, RecordBuilder prefix) { + var r = ((MapCodecCodec) CommandTypes.CODEC) + .codec() + .encode(input.other(), ops, prefix); + input + .condition() + .map(condition1 -> MagicCodecs.LOOT_CONDITION.encodeStart(ops, condition1)) + .ifPresent(tDataResult -> r.add("condition", tDataResult)); + return r; } @Override public DataResult decode(DynamicOps ops, MapLike input) { - var r = ((MapCodecCodec) CommandTypes.CODEC).codec().decode(ops, input); - T condition = input.get("condition"); - if (condition == null) return r.map(command -> new ConditionedCommand(Optional.empty(), command)); - return r.map(command -> MagicCodecs.LOOT_CONDITION.parse(ops, condition).map(condition1 -> new ConditionedCommand(Optional.of(condition1), command))).flatMap(Function.identity()); + var r = ((MapCodecCodec) CommandTypes.CODEC).codec().decode(ops, input); + T condition = input.get("condition"); + if (condition == null) + return r.map(command -> new ConditionedCommand(Optional.empty(), command)); + return r.map(command -> MagicCodecs.LOOT_CONDITION + .parse(ops, condition) + .map(condition1 -> new ConditionedCommand(Optional.of(condition1), command))) + .flatMap(Function.identity()); } @Override public Stream keys(DynamicOps ops) { - return Stream.of("condition").map(ops::createString); + return Stream.of("condition").map(ops::createString); } - }; - - @Override - public boolean execute(EventContext context) { - if (!this.condition.map(condition1 -> condition1.test(context.lootContext())).orElse(true)) return false; - return other().execute(context); - } - - @Override - public DataResult validate(EventType type) { - return this.other().validate(type); - } + }; + + @Override + public boolean execute(EventContext context) { + if (!this.condition + .map(condition1 -> condition1.test(context.lootContext())) + .orElse(true)) return false; + return other().execute(context); + } + + @Override + public DataResult validate(EventType type) { + return this.other().validate(type); + } } diff --git a/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java b/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java index ac07185..93ae06b 100644 --- a/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java +++ b/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java @@ -3,6 +3,8 @@ package me.melontini.commander.impl.command; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.util.Optional; +import java.util.function.Function; import me.melontini.commander.api.command.Selector; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.impl.event.data.types.SelectorTypes; @@ -15,27 +17,34 @@ import net.minecraft.loot.context.LootContextParameters; import net.minecraft.loot.context.LootContextTypes; import net.minecraft.server.command.ServerCommandSource; -import java.util.Optional; -import java.util.function.Function; - -public record ConditionedSelector(Optional condition, Selector other) implements Selector.Conditioned { +public record ConditionedSelector(Optional condition, Selector other) + implements Selector.Conditioned { - public static final Codec CODEC = ExtraCodecs.either(RecordCodecBuilder.create(data -> data.group( - ExtraCodecs.optional("condition", MagicCodecs.LOOT_CONDITION).forGetter(ConditionedSelector::condition), - SelectorTypes.CODEC.fieldOf("value").forGetter(ConditionedSelector::other) - ).apply(data, ConditionedSelector::new)), SelectorTypes.CODEC).xmap(e -> e.map(Function.identity(), selector -> new ConditionedSelector(Optional.empty(), selector)), Either::left); + public static final Codec CODEC = ExtraCodecs.either( + RecordCodecBuilder.create(data -> data.group( + ExtraCodecs.optional("condition", MagicCodecs.LOOT_CONDITION) + .forGetter(ConditionedSelector::condition), + SelectorTypes.CODEC.fieldOf("value").forGetter(ConditionedSelector::other)) + .apply(data, ConditionedSelector::new)), + SelectorTypes.CODEC) + .xmap( + e -> e.map( + Function.identity(), selector -> new ConditionedSelector(Optional.empty(), selector)), + Either::left); - @Override - public Optional select(EventContext context) { - var source = other.select(context.lootContext()); - if (source == null) return Optional.empty(); - if (condition.isEmpty()) return Optional.of(source); + @Override + public Optional select(EventContext context) { + var source = other.select(context.lootContext()); + if (source == null) return Optional.empty(); + if (condition.isEmpty()) return Optional.of(source); - LootContextParameterSet.Builder builder = new LootContextParameterSet.Builder(context.lootContext().getWorld()); - builder.add(LootContextParameters.ORIGIN, source.getPosition()); - builder.addOptional(LootContextParameters.THIS_ENTITY, source.getEntity()); - LootContext sourceContext = new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); + LootContextParameterSet.Builder builder = + new LootContextParameterSet.Builder(context.lootContext().getWorld()); + builder.add(LootContextParameters.ORIGIN, source.getPosition()); + builder.addOptional(LootContextParameters.THIS_ENTITY, source.getEntity()); + LootContext sourceContext = + new LootContext.Builder(builder.build(LootContextTypes.COMMAND)).build(null); - return condition.get().test(sourceContext) ? Optional.of(source) : Optional.empty(); - } + return condition.get().test(sourceContext) ? Optional.of(source) : Optional.empty(); + } } diff --git a/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java b/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java index d5a6e78..c60b63e 100644 --- a/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java +++ b/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.event; +import java.util.IdentityHashMap; +import java.util.concurrent.atomic.AtomicReference; import lombok.Getter; import lombok.experimental.Accessors; import me.melontini.commander.api.event.EventContext; @@ -8,77 +10,76 @@ import me.melontini.commander.api.event.EventType; import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.NotNull; -import java.util.IdentityHashMap; -import java.util.concurrent.atomic.AtomicReference; - @Accessors(fluent = true) public final class EventContextImpl implements EventContext { - @Getter + @Getter + private final EventType type; + + private final IdentityHashMap, Object> parameters; + + private EventContextImpl(EventType type, IdentityHashMap, Object> parameters) { + this.parameters = parameters; + this.type = type; + } + + @Override + public EventContextImpl with(IdentityHashMap, Object> parameters) { + IdentityHashMap, Object> map = new IdentityHashMap<>(this.parameters); + map.putAll(parameters); + return new EventContextImpl(type, map); + } + + @Override + public @NotNull T getParameter(EventKey key) { + var r = parameters.get(key); + if (r == null) + throw new IllegalStateException("Missing required parameter key %s".formatted(key.id())); + return (T) r; + } + + @Override + public @NotNull LootContext lootContext() { + return getParameter(EventKey.LOOT_CONTEXT); + } + + @Override + public void setReturnValue(Object value) { + getParameter(EventKey.RETURN_VALUE).set(value); + } + + @Override + public T getReturnValue(T def) { + var r = getParameter(EventKey.RETURN_VALUE).get(); + if (r == null) return def; + return (T) r; + } + + public static Builder builder(EventTypeImpl type) { + return new Builder(type); + } + + public static final class Builder implements EventContext.Builder { + private final IdentityHashMap, Object> map = new IdentityHashMap<>(); private final EventType type; - private final IdentityHashMap, Object> parameters; - private EventContextImpl(EventType type, IdentityHashMap, Object> parameters) { - this.parameters = parameters; - this.type = type; - } + public Builder(EventType type) { + this.type = type; - @Override - public EventContextImpl with(IdentityHashMap, Object> parameters) { - IdentityHashMap, Object> map = new IdentityHashMap<>(this.parameters); - map.putAll(parameters); - return new EventContextImpl(type, map); + if (this.type.get(EventType.CANCEL_TERM).isPresent()) { + map.put(EventKey.RETURN_VALUE, new AtomicReference<>()); + } } @Override - public @NotNull T getParameter(EventKey key) { - var r = parameters.get(key); - if (r == null) throw new IllegalStateException("Missing required parameter key %s".formatted(key.id())); - return (T) r; + public Builder addParameter(EventKey key, T value) { + this.map.put(key, value); + return this; } @Override - public @NotNull LootContext lootContext() { - return getParameter(EventKey.LOOT_CONTEXT); - } - - @Override - public void setReturnValue(Object value) { - getParameter(EventKey.RETURN_VALUE).set(value); - } - - @Override - public T getReturnValue(T def) { - var r = getParameter(EventKey.RETURN_VALUE).get(); - if (r == null) return def; - return (T) r; - } - - public static Builder builder(EventTypeImpl type) { - return new Builder(type); - } - - public static final class Builder implements EventContext.Builder { - private final IdentityHashMap, Object> map = new IdentityHashMap<>(); - private final EventType type; - - public Builder(EventType type) { - this.type = type; - - if (this.type.get(EventType.CANCEL_TERM).isPresent()) { - map.put(EventKey.RETURN_VALUE, new AtomicReference<>()); - } - } - - @Override - public Builder addParameter(EventKey key, T value) { - this.map.put(key, value); - return this; - } - - @Override - public EventContextImpl build() { - return new EventContextImpl(type, map); - } + public EventContextImpl build() { + return new EventContextImpl(type, map); } + } } diff --git a/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java b/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java index cf95f9b..7725d66 100644 --- a/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java +++ b/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java @@ -1,6 +1,10 @@ package me.melontini.commander.impl.event; import com.mojang.serialization.Codec; +import java.util.List; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Function; import me.melontini.commander.api.event.EventType; import me.melontini.commander.api.event.Subscription; import me.melontini.commander.impl.event.data.types.EventTypes; @@ -9,49 +13,45 @@ import me.melontini.dark_matter.api.base.util.Utilities; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.Optional; -import java.util.function.BiConsumer; -import java.util.function.Function; - public record EventTypeImpl(Context context) implements EventType { - @Override - public Optional get(Key key) { - return context.get(key); - } + @Override + public Optional get(Key key) { + return context.get(key); + } + + @Override + public void forEach(BiConsumer, Object> consumer) { + context.forEach(consumer); + } + + @Override + public boolean equals(Object obj) { + return obj == this; + } + + public static class Builder implements EventType.Builder { + private final Context.Builder builder = Context.builder(); @Override - public void forEach(BiConsumer, Object> consumer) { - context.forEach(consumer); + public Builder extension( + @Nullable Codec extension, Function>, C> finalizer) { + if (extension != null) builder.put(EXTENSION, extension); + builder.put(FINALIZER, Utilities.cast(finalizer)); + return this; } @Override - public boolean equals(Object obj) { - return obj == this; + public Builder cancelTerm(Codec returnCodec) { + builder.put(CANCEL_TERM, returnCodec); + return this; } - public static class Builder implements EventType.Builder { - private final Context.Builder builder = Context.builder(); - - @Override - public Builder extension(@Nullable Codec extension, Function>, C> finalizer) { - if (extension != null) builder.put(EXTENSION, extension); - builder.put(FINALIZER, Utilities.cast(finalizer)); - return this; - } - - @Override - public Builder cancelTerm(Codec returnCodec) { - builder.put(CANCEL_TERM, returnCodec); - return this; - } - - @Override - public EventTypeImpl build(Identifier identifier) { - var type = new EventTypeImpl(this.builder.build()); - EventTypes.register(identifier, type); - return type; - } + @Override + public EventTypeImpl build(Identifier identifier) { + var type = new EventTypeImpl(this.builder.build()); + EventTypes.register(identifier, type); + return type; } + } } diff --git a/src/main/java/me/melontini/commander/impl/event/data/DynamicEventManager.java b/src/main/java/me/melontini/commander/impl/event/data/DynamicEventManager.java index c021874..a15b9f5 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/DynamicEventManager.java +++ b/src/main/java/me/melontini/commander/impl/event/data/DynamicEventManager.java @@ -1,6 +1,8 @@ package me.melontini.commander.impl.event.data; import com.google.common.collect.Sets; +import java.util.*; +import java.util.stream.Collectors; import lombok.experimental.Accessors; import me.melontini.commander.api.event.EventType; import me.melontini.commander.api.event.Subscription; @@ -13,46 +15,51 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.*; -import java.util.stream.Collectors; - @Accessors(fluent = true) -public class DynamicEventManager extends JsonCodecDataLoader>> implements IdentifiableResourceReloadListener { +public class DynamicEventManager extends JsonCodecDataLoader>> + implements IdentifiableResourceReloadListener { - public static final ReloaderType RELOADER = ReloaderType.create(new Identifier("commander:events")); + public static final ReloaderType RELOADER = + ReloaderType.create(new Identifier("commander:events")); - final IdentityHashMap customData = new IdentityHashMap<>(); + final IdentityHashMap customData = new IdentityHashMap<>(); - public DynamicEventManager() { - super(RELOADER.identifier(), SubscriptionImpl.CODEC); - } + public DynamicEventManager() { + super(RELOADER.identifier(), SubscriptionImpl.CODEC); + } - public static @Nullable T getData(MinecraftServer server, EventType type) { - return server.dm$getReloader(DynamicEventManager.RELOADER).getData(type); - } + public static @Nullable T getData(MinecraftServer server, EventType type) { + return server.dm$getReloader(DynamicEventManager.RELOADER).getData(type); + } - public @Nullable T getData(EventType type) { - return (T) this.customData.get(type); - } + public @Nullable T getData(EventType type) { + return (T) this.customData.get(type); + } - @Override - protected void apply(Map>> parsed, ResourceManager manager) { - parsed.values().stream().flatMap(Collection::stream).collect(Collectors.groupingBy(Subscription::type)).forEach((eventType, subscriptions) -> { - var finalizer = eventType.get(EventType.FINALIZER); - if (finalizer.isPresent()) { - this.customData.put(eventType, finalizer.get().apply(Collections.unmodifiableList(subscriptions))); - return; - } - this.customData.put(eventType, subscriptions.stream().flatMap(s -> s.list().stream()).toList()); + @Override + protected void apply( + Map>> parsed, ResourceManager manager) { + parsed.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.groupingBy(Subscription::type)) + .forEach((eventType, subscriptions) -> { + var finalizer = eventType.get(EventType.FINALIZER); + if (finalizer.isPresent()) { + this.customData.put( + eventType, finalizer.get().apply(Collections.unmodifiableList(subscriptions))); + return; + } + this.customData.put( + eventType, subscriptions.stream().flatMap(s -> s.list().stream()).toList()); }); - Sets.difference(EventTypes.types(), customData.keySet()).forEach(type -> { - var finalizer = type.get(EventType.FINALIZER); - if (finalizer.isPresent()) { - this.customData.put(type, finalizer.get().apply(Collections.emptyList())); - return; - } - this.customData.put(type, Collections.emptyList()); - }); - } + Sets.difference(EventTypes.types(), customData.keySet()).forEach(type -> { + var finalizer = type.get(EventType.FINALIZER); + if (finalizer.isPresent()) { + this.customData.put(type, finalizer.get().apply(Collections.emptyList())); + return; + } + this.customData.put(type, Collections.emptyList()); + }); + } } diff --git a/src/main/java/me/melontini/commander/impl/event/data/SubscriptionImpl.java b/src/main/java/me/melontini/commander/impl/event/data/SubscriptionImpl.java index 93d345a..ead68f8 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/SubscriptionImpl.java +++ b/src/main/java/me/melontini/commander/impl/event/data/SubscriptionImpl.java @@ -2,6 +2,11 @@ package me.melontini.commander.impl.event.data; import com.mojang.datafixers.util.Either; import com.mojang.serialization.*; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.event.EventType; import me.melontini.commander.api.event.Subscription; @@ -10,65 +15,82 @@ import me.melontini.dark_matter.api.base.util.Utilities; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; - -public record SubscriptionImpl(EventType type, @Nullable E parameters, List list) implements Subscription { +public record SubscriptionImpl( + EventType type, @Nullable E parameters, List list) + implements Subscription { - private static final Codec> LIST_CODEC = ExtraCodecs.list(Command.CODEC.codec()); - public static final MapCodec> BASE_CODEC = new MapCodec>() { + private static final Codec> LIST_CODEC = + ExtraCodecs.list(Command.CODEC.codec()); + public static final MapCodec> BASE_CODEC = + new MapCodec>() { @Override - public RecordBuilder encode(SubscriptionImpl input, DynamicOps ops, RecordBuilder prefix) { - var map = ops.mapBuilder(); - var r = EventTypes.CODEC.encodeStart(ops, input.type()); - map.add("event", r); - if (!input.list().isEmpty()) map.add("commands", LIST_CODEC.encodeStart(ops, input.list())); - if (input.parameters() != null) { - var opt = input.type().get(EventType.EXTENSION); - opt.ifPresent(codec -> map.add("parameters", codec.encodeStart(ops, Utilities.cast(input.parameters())))); - } - return map; + public RecordBuilder encode( + SubscriptionImpl input, DynamicOps ops, RecordBuilder prefix) { + var map = ops.mapBuilder(); + var r = EventTypes.CODEC.encodeStart(ops, input.type()); + map.add("event", r); + if (!input.list().isEmpty()) + map.add("commands", LIST_CODEC.encodeStart(ops, input.list())); + if (input.parameters() != null) { + var opt = input.type().get(EventType.EXTENSION); + opt.ifPresent(codec -> + map.add("parameters", codec.encodeStart(ops, Utilities.cast(input.parameters())))); + } + return map; } @Override public DataResult> decode(DynamicOps ops, MapLike input) { - T type = input.get("event"); - if (type == null) return DataResult.error(() -> "Missing 'event' field in %s".formatted(input)); - DataResult event = EventTypes.CODEC.parse(ops, type); + T type = input.get("event"); + if (type == null) + return DataResult.error(() -> "Missing 'event' field in %s".formatted(input)); + DataResult event = EventTypes.CODEC.parse(ops, type); - T parameters = input.get("parameters"); - return event.flatMap(eventType -> { + T parameters = input.get("parameters"); + return event + .flatMap(eventType -> { var opt = eventType.get(EventType.EXTENSION); if (opt.isPresent()) { - if (parameters == null) - return DataResult.error(() -> "Missing required 'parameters' field in %s".formatted(input)); - return opt.get().parse(ops, parameters).map(Optional::ofNullable); + if (parameters == null) + return DataResult.error( + () -> "Missing required 'parameters' field in %s".formatted(input)); + return opt.get().parse(ops, parameters).map(Optional::ofNullable); } return DataResult.success(Optional.empty()); - }).map(o -> event.map(eventType -> { + }) + .map(o -> event.map(eventType -> { T commands = input.get("commands"); if (commands != null) - return LIST_CODEC.parse(ops, commands).flatMap(list1 -> { + return LIST_CODEC + .parse(ops, commands) + .flatMap(list1 -> { for (Command.Conditioned conditionedCommand : list1) { - var r = conditionedCommand.validate(eventType); - if (r.error().isPresent()) - return r.map(unused -> Collections.emptyList()); + var r = conditionedCommand.validate(eventType); + if (r.error().isPresent()) + return r.map(unused -> Collections.emptyList()); } return DataResult.success(list1); - }).map(list1 -> new SubscriptionImpl<>(eventType, o.orElse(null), (List) list1)); - return DataResult.success(new SubscriptionImpl<>(eventType, o.orElse(null), Collections.emptyList())); - })).flatMap(Function.identity()).map(Function.identity()).flatMap(r -> r).map(Function.identity()); + }) + .map(list1 -> new SubscriptionImpl<>( + eventType, o.orElse(null), (List) list1)); + return DataResult.success( + new SubscriptionImpl<>(eventType, o.orElse(null), Collections.emptyList())); + })) + .flatMap(Function.identity()) + .map(Function.identity()) + .flatMap(r -> r) + .map(Function.identity()); } @Override public Stream keys(DynamicOps ops) { - return Stream.of("event", "parameters", "commands").map(ops::createString); + return Stream.of("event", "parameters", "commands").map(ops::createString); } - }; + }; - public static final Codec>> CODEC = ExtraCodecs.either(ExtraCodecs.list(BASE_CODEC.codec()).fieldOf("events").codec(), BASE_CODEC.codec()) - .xmap(e -> e.map(Function.identity(), Collections::singletonList), subscriptions -> Utilities.cast(Either.left(subscriptions))); + public static final Codec>> CODEC = ExtraCodecs.either( + ExtraCodecs.list(BASE_CODEC.codec()).fieldOf("events").codec(), BASE_CODEC.codec()) + .xmap( + e -> e.map(Function.identity(), Collections::singletonList), + subscriptions -> Utilities.cast(Either.left(subscriptions))); } diff --git a/src/main/java/me/melontini/commander/impl/event/data/types/CommandTypes.java b/src/main/java/me/melontini/commander/impl/event/data/types/CommandTypes.java index 26a7a5c..0ce4227 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/types/CommandTypes.java +++ b/src/main/java/me/melontini/commander/impl/event/data/types/CommandTypes.java @@ -3,34 +3,39 @@ package me.melontini.commander.impl.event.data.types; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.mojang.serialization.Codec; +import java.util.IdentityHashMap; +import java.util.Objects; import lombok.experimental.UtilityClass; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.command.CommandType; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.util.Identifier; -import java.util.IdentityHashMap; -import java.util.Objects; - @UtilityClass public final class CommandTypes { - private static final BiMap COMMANDS = HashBiMap.create(); - private static final Codec TYPE_CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, COMMANDS); - private static final IdentityHashMap> CACHE = new IdentityHashMap<>(); - public static final Codec CODEC = TYPE_CODEC.dispatch("type", Command::type, type -> CACHE.computeIfAbsent(type, t -> t.codec().codec())); + private static final BiMap COMMANDS = HashBiMap.create(); + private static final Codec TYPE_CODEC = + ExtraCodecs.mapLookup(Identifier.CODEC, COMMANDS); + private static final IdentityHashMap> CACHE = + new IdentityHashMap<>(); + public static final Codec CODEC = TYPE_CODEC.dispatch( + "type", Command::type, type -> CACHE.computeIfAbsent(type, t -> t.codec().codec())); - public static Identifier getId(CommandType type) { - return Objects.requireNonNull(COMMANDS.inverse().get(type), () -> "Unregistered CommandType %s!".formatted(type)); - } + public static Identifier getId(CommandType type) { + return Objects.requireNonNull( + COMMANDS.inverse().get(type), () -> "Unregistered CommandType %s!".formatted(type)); + } - public static CommandType getType(Identifier identifier) { - return Objects.requireNonNull(COMMANDS.get(identifier), () -> "Unknown CommandType %s!".formatted(identifier)); - } + public static CommandType getType(Identifier identifier) { + return Objects.requireNonNull( + COMMANDS.get(identifier), () -> "Unknown CommandType %s!".formatted(identifier)); + } - public static CommandType register(Identifier identifier, CommandType type) { - var old = COMMANDS.put(identifier, type); - if (old != null) throw new IllegalStateException("Already registered command %s".formatted(identifier)); - return type; - } + public static CommandType register(Identifier identifier, CommandType type) { + var old = COMMANDS.put(identifier, type); + if (old != null) + throw new IllegalStateException("Already registered command %s".formatted(identifier)); + return type; + } } diff --git a/src/main/java/me/melontini/commander/impl/event/data/types/EventTypes.java b/src/main/java/me/melontini/commander/impl/event/data/types/EventTypes.java index e554c13..b24837a 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/types/EventTypes.java +++ b/src/main/java/me/melontini/commander/impl/event/data/types/EventTypes.java @@ -3,37 +3,39 @@ package me.melontini.commander.impl.event.data.types; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.mojang.serialization.Codec; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; import lombok.experimental.UtilityClass; import me.melontini.commander.api.event.EventType; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.util.Identifier; import org.jetbrains.annotations.UnmodifiableView; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; - @UtilityClass public final class EventTypes { - private static final BiMap EVENTS = HashBiMap.create(); - public static final Codec CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, EVENTS); - - public static Identifier getId(EventType type) { - return Objects.requireNonNull(EVENTS.inverse().get(type), () -> "Unregistered EventType %s!".formatted(type)); - } - - public static EventType getType(Identifier identifier) { - return Objects.requireNonNull(EVENTS.get(identifier), "Unknown EventType %s!".formatted(identifier)); - } - - public static @UnmodifiableView Set types() { - return Collections.unmodifiableSet(EVENTS.values()); - } - - public static EventType register(Identifier identifier, EventType type) { - var old = EVENTS.put(identifier, type); - if (old != null) throw new IllegalStateException("Already registered event %s".formatted(identifier)); - return type; - } + private static final BiMap EVENTS = HashBiMap.create(); + public static final Codec CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, EVENTS); + + public static Identifier getId(EventType type) { + return Objects.requireNonNull( + EVENTS.inverse().get(type), () -> "Unregistered EventType %s!".formatted(type)); + } + + public static EventType getType(Identifier identifier) { + return Objects.requireNonNull( + EVENTS.get(identifier), "Unknown EventType %s!".formatted(identifier)); + } + + public static @UnmodifiableView Set types() { + return Collections.unmodifiableSet(EVENTS.values()); + } + + public static EventType register(Identifier identifier, EventType type) { + var old = EVENTS.put(identifier, type); + if (old != null) + throw new IllegalStateException("Already registered event %s".formatted(identifier)); + return type; + } } diff --git a/src/main/java/me/melontini/commander/impl/event/data/types/ExtractionTypes.java b/src/main/java/me/melontini/commander/impl/event/data/types/ExtractionTypes.java index 726c259..75e8fc3 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/types/ExtractionTypes.java +++ b/src/main/java/me/melontini/commander/impl/event/data/types/ExtractionTypes.java @@ -10,15 +10,18 @@ import org.jetbrains.annotations.Nullable; public class ExtractionTypes { - private static final BiMap> KNOWN_PARAMETERS = HashBiMap.create(); - public static final Codec> CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, KNOWN_PARAMETERS); + private static final BiMap> KNOWN_PARAMETERS = + HashBiMap.create(); + public static final Codec> CODEC = + ExtraCodecs.mapLookup(Identifier.CODEC, KNOWN_PARAMETERS); - public static @Nullable LootContextParameter getParameter(Identifier identifier) { - return KNOWN_PARAMETERS.get(identifier); - } + public static @Nullable LootContextParameter getParameter(Identifier identifier) { + return KNOWN_PARAMETERS.get(identifier); + } - public static void register(LootContextParameter parameter) { - var old = KNOWN_PARAMETERS.put(parameter.getId(), parameter); - if (old != null) throw new IllegalStateException("Already registered context %s".formatted(parameter.getId())); - } + public static void register(LootContextParameter parameter) { + var old = KNOWN_PARAMETERS.put(parameter.getId(), parameter); + if (old != null) + throw new IllegalStateException("Already registered context %s".formatted(parameter.getId())); + } } diff --git a/src/main/java/me/melontini/commander/impl/event/data/types/SelectorTypes.java b/src/main/java/me/melontini/commander/impl/event/data/types/SelectorTypes.java index d0dcd44..9481812 100644 --- a/src/main/java/me/melontini/commander/impl/event/data/types/SelectorTypes.java +++ b/src/main/java/me/melontini/commander/impl/event/data/types/SelectorTypes.java @@ -11,13 +11,14 @@ import net.minecraft.util.Identifier; @UtilityClass public final class SelectorTypes { - private static final BiMap SELECTORS = HashBiMap.create(); + private static final BiMap SELECTORS = HashBiMap.create(); - public static final Codec CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, SELECTORS); + public static final Codec CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, SELECTORS); - public static Selector register(Identifier identifier, Selector selector) { - var old = SELECTORS.put(identifier, selector); - if (old != null) throw new IllegalStateException("Already registered selector %s".formatted(identifier)); - return selector; - } + public static Selector register(Identifier identifier, Selector selector) { + var old = SELECTORS.put(identifier, selector); + if (old != null) + throw new IllegalStateException("Already registered selector %s".formatted(identifier)); + return selector; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/CmdEvalException.java b/src/main/java/me/melontini/commander/impl/expression/CmdEvalException.java index a961e0d..ece0171 100644 --- a/src/main/java/me/melontini/commander/impl/expression/CmdEvalException.java +++ b/src/main/java/me/melontini/commander/impl/expression/CmdEvalException.java @@ -3,5 +3,4 @@ package me.melontini.commander.impl.expression; import lombok.experimental.StandardException; @StandardException -public class CmdEvalException extends RuntimeException { -} +public class CmdEvalException extends RuntimeException {} diff --git a/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java b/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java index 0c66a8e..d7d2304 100644 --- a/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java +++ b/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java @@ -22,6 +22,13 @@ import com.mojang.serialization.DataResult; import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; import it.unimi.dsi.fastutil.objects.Object2ReferenceMaps; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.StringJoiner; +import java.util.function.Function; import lombok.extern.log4j.Log4j2; import me.melontini.commander.api.expression.extensions.ProxyMap; import me.melontini.commander.impl.event.data.types.ExtractionTypes; @@ -43,196 +50,244 @@ import net.minecraft.registry.RegistryKeys; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.StringJoiner; -import java.util.function.Function; - @Log4j2 public class EvalUtils { - public static final ExpressionConfiguration CONFIGURATION; - public static final ExpressionParser PARSER; - public static final Object2ReferenceMap CONSTANTS = Object2ReferenceMaps.unmodifiable(new Object2ReferenceOpenHashMap<>(ImmutableMap.of( - "true", BooleanValue.TRUE, - "false", BooleanValue.FALSE, - "PI", NumberValue.of(new BigDecimal("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679")), - "E", NumberValue.of(new BigDecimal("2.71828182845904523536028747135266249775724709369995957496696762772407663")), - "null", NullValue.of(), - "DT_FORMAT_ISO_DATE_TIME", StringValue.of("yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX]['['VV']']"), - "DT_FORMAT_LOCAL_DATE_TIME", StringValue.of("yyyy-MM-dd'T'HH:mm:ss[.SSS]"), - "DT_FORMAT_LOCAL_DATE", StringValue.of("yyyy-MM-dd") - ))); - - static { - var builder = ExpressionConfiguration.builder() - .dataAccessorSupplier(LootContextDataAccessor::new) - .parameterMapSupplier(Object2ReferenceOpenHashMap::new) - .evaluationValueConverter(new ReflectiveValueConverter()) - .allowOverwriteConstants(false) - .additionalAllowedIdentifierChars(new char[] {':'}) - .singleQuoteStringLiteralsAllowed(true) - .mathContext(MathContext.DECIMAL64) - .constants(CONSTANTS); - - Set toCache = ImmutableSet.of( - "fact", "sqrt", - "acos", "acosh", "acosr", "acot", "acoth", "acotr", "asin", "asinh", "asinr", - "atan", "atan2", "atan2r", "atanh", "atanr", "cosh", "cosr", "cot", "coth", "cotr", - "csc", "csch", "cscr", "sinh", "sinr", "sec", "sech", "secr", "tanh", "tanr", - "strContains", "strEndsWith", "strLower", "strStartsWith", "strTrim", "strUpper" - ); - - var fd = ExpressionConfiguration.defaultConfiguration().getFunctionDictionary(); - var dictionary = fd.toBuilder(Object2ReferenceOpenHashMap::new); - fd.forEach((string, functionIfc) -> { - var newName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, string); - dictionary.add(newName, toCache.contains(newName) ? LruCachingFunction.of(functionIfc) : functionIfc); - }); - - dictionary.add("random", new RangedRandomFunction()); - dictionary.add("lerp", new LerpFunction()); - dictionary.add("clamp", new ClampFunction()); - dictionary.add("ifMatches", new MatchesFunction()); - dictionary.add("chain", new ChainFunction()); - dictionary.add("length", new LengthFunction()); - - dictionary.add("arrayOf", new ArrayOf()); - dictionary.add("arrayMap", new ArrayMap()); - dictionary.add("arrayFind", new ArrayFind()); - dictionary.add("arrayFindAny", new ArrayFindAny()); - dictionary.add("arrayFindFirst", new ArrayFindFirst()); - dictionary.add("arrayAnyMatch", new ArrayAnyMatch()); - dictionary.add("arrayNoneMatch", new ArrayNoneMatch()); - dictionary.add("arrayAllMatch", new ArrayAllMatch()); - - dictionary.add("structContainsKey", new StructContainsKeyFunction()); - dictionary.add("hasContext", new HasContextFunction()); - - dictionary.add("Registry", new RegistryFunction(Registries.REGISTRIES)); - dictionary.add("Item", LruCachingFunction.of(new RegistryFunction(Registries.ITEM))); - dictionary.add("Block", LruCachingFunction.of(new RegistryFunction(Registries.BLOCK))); - - dictionary.add("DynamicRegistry", new DynamicRegistryRegistryFunction()); - dictionary.add("Biome", new DynamicRegistryFunction(RegistryKeys.BIOME)); - dictionary.add("DimensionType", new DynamicRegistryFunction(RegistryKeys.DIMENSION_TYPE)); - builder.functionDictionary(dictionary.build()); - - CONFIGURATION = builder.build(); - PARSER = new ExpressionParser(CONFIGURATION); - } + public static final ExpressionConfiguration CONFIGURATION; + public static final ExpressionParser PARSER; + public static final Object2ReferenceMap CONSTANTS = + Object2ReferenceMaps.unmodifiable(new Object2ReferenceOpenHashMap<>(ImmutableMap.of( + "true", BooleanValue.TRUE, + "false", BooleanValue.FALSE, + "PI", + NumberValue.of( + new BigDecimal( + "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679")), + "E", + NumberValue.of(new BigDecimal( + "2.71828182845904523536028747135266249775724709369995957496696762772407663")), + "null", NullValue.of(), + "DT_FORMAT_ISO_DATE_TIME", StringValue.of("yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX]['['VV']']"), + "DT_FORMAT_LOCAL_DATE_TIME", StringValue.of("yyyy-MM-dd'T'HH:mm:ss[.SSS]"), + "DT_FORMAT_LOCAL_DATE", StringValue.of("yyyy-MM-dd")))); - public static String prettyToString(EvaluationValue value) { - if (value.isNumberValue()) return '\'' + value.getStringValue() + '\''; - if (value.isBooleanValue()) return value.getBooleanValue() ? "true" : "false"; - if (value.isStringValue()) return value.getStringValue(); - - if (value.isArrayValue()) { - StringJoiner joiner = new StringJoiner(", ", "[", "]"); - value.getArrayValue().forEach(value1 -> joiner.add(prettyToString(value1))); - return joiner.toString(); - } - - if (value.isStructureValue()) { - var map = value.getStructureValue(); - //TODO consider a DataAccessor type to avoid posing as structures. - if ((Object) map instanceof ProxyMap) return String.valueOf(map); //Those do not implement any itr methods. - StringJoiner joiner = new StringJoiner(", ", "{", "}"); - map.forEach((string, value1) -> joiner.add(string + "=" + prettyToString(value1))); - return joiner.toString(); - } - - if (value.isNullValue()) return "null"; - return Objects.toString(value.getValue()); - } + static { + var builder = ExpressionConfiguration.builder() + .dataAccessorSupplier(LootContextDataAccessor::new) + .parameterMapSupplier(Object2ReferenceOpenHashMap::new) + .evaluationValueConverter(new ReflectiveValueConverter()) + .allowOverwriteConstants(false) + .additionalAllowedIdentifierChars(new char[] {':'}) + .singleQuoteStringLiteralsAllowed(true) + .mathContext(MathContext.DECIMAL64) + .constants(CONSTANTS); - public static ThrowingOptional valueOrEmpty(ASTNode node) { - if (node instanceof InlinedASTNode inlined) return ThrowingOptional.of(inlined.value()); - return ThrowingOptional.empty(); - } + Set toCache = ImmutableSet.of( + "fact", + "sqrt", + "acos", + "acosh", + "acosr", + "acot", + "acoth", + "acotr", + "asin", + "asinh", + "asinr", + "atan", + "atan2", + "atan2r", + "atanh", + "atanr", + "cosh", + "cosr", + "cot", + "coth", + "cotr", + "csc", + "csch", + "cscr", + "sinh", + "sinr", + "sec", + "sech", + "secr", + "tanh", + "tanr", + "strContains", + "strEndsWith", + "strLower", + "strStartsWith", + "strTrim", + "strUpper"); - public static EvaluationValue runLambda(EvaluationContext context, EvaluationValue value, ASTNode predicate) throws EvaluationException { - return context.expression().evaluateSubtree(predicate, context.withParameter("it", value)); + var fd = ExpressionConfiguration.defaultConfiguration().getFunctionDictionary(); + var dictionary = fd.toBuilder(Object2ReferenceOpenHashMap::new); + fd.forEach((string, functionIfc) -> { + var newName = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, string); + dictionary.add( + newName, toCache.contains(newName) ? LruCachingFunction.of(functionIfc) : functionIfc); + }); + + dictionary.add("random", new RangedRandomFunction()); + dictionary.add("lerp", new LerpFunction()); + dictionary.add("clamp", new ClampFunction()); + dictionary.add("ifMatches", new MatchesFunction()); + dictionary.add("chain", new ChainFunction()); + dictionary.add("length", new LengthFunction()); + + dictionary.add("arrayOf", new ArrayOf()); + dictionary.add("arrayMap", new ArrayMap()); + dictionary.add("arrayFind", new ArrayFind()); + dictionary.add("arrayFindAny", new ArrayFindAny()); + dictionary.add("arrayFindFirst", new ArrayFindFirst()); + dictionary.add("arrayAnyMatch", new ArrayAnyMatch()); + dictionary.add("arrayNoneMatch", new ArrayNoneMatch()); + dictionary.add("arrayAllMatch", new ArrayAllMatch()); + + dictionary.add("structContainsKey", new StructContainsKeyFunction()); + dictionary.add("hasContext", new HasContextFunction()); + + dictionary.add("Registry", new RegistryFunction(Registries.REGISTRIES)); + dictionary.add("Item", LruCachingFunction.of(new RegistryFunction(Registries.ITEM))); + dictionary.add("Block", LruCachingFunction.of(new RegistryFunction(Registries.BLOCK))); + + dictionary.add("DynamicRegistry", new DynamicRegistryRegistryFunction()); + dictionary.add("Biome", new DynamicRegistryFunction(RegistryKeys.BIOME)); + dictionary.add("DimensionType", new DynamicRegistryFunction(RegistryKeys.DIMENSION_TYPE)); + builder.functionDictionary(dictionary.build()); + + CONFIGURATION = builder.build(); + PARSER = new ExpressionParser(CONFIGURATION); + } + + public static String prettyToString(EvaluationValue value) { + if (value.isNumberValue()) return '\'' + value.getStringValue() + '\''; + if (value.isBooleanValue()) return value.getBooleanValue() ? "true" : "false"; + if (value.isStringValue()) return value.getStringValue(); + + if (value.isArrayValue()) { + StringJoiner joiner = new StringJoiner(", ", "[", "]"); + value.getArrayValue().forEach(value1 -> joiner.add(prettyToString(value1))); + return joiner.toString(); } - public static EvaluationValue evaluate(LootContext context, Expression exp, @Nullable Map params) { - try { - var builder = EvaluationContext.builder(exp).context(context); - if (params != null && !params.isEmpty()) builder.parameters(params); - return exp.evaluate(builder.build()); - } catch (BaseException e) { - throw new CmdEvalException(Objects.requireNonNullElseGet(e.getMessage(), () -> "Failed to evaluate expression %s".formatted(exp.getExpressionString())), e); - } + if (value.isStructureValue()) { + var map = value.getStructureValue(); + // TODO consider a DataAccessor type to avoid posing as structures. + if ((Object) map instanceof ProxyMap) + return String.valueOf(map); // Those do not implement any itr methods. + StringJoiner joiner = new StringJoiner(", ", "{", "}"); + map.forEach((string, value1) -> joiner.add(string + "=" + prettyToString(value1))); + return joiner.toString(); } - private static final Object CACHE_LOCK = new Object(); - private static Function EXPRESSION_CACHE; + if (value.isNullValue()) return "null"; + return Objects.toString(value.getValue()); + } - static { - resetCache(); - } + public static ThrowingOptional valueOrEmpty(ASTNode node) { + if (node instanceof InlinedASTNode inlined) return ThrowingOptional.of(inlined.value()); + return ThrowingOptional.empty(); + } - public static void resetCache() { - synchronized (CACHE_LOCK) { - EXPRESSION_CACHE = Memoize.lruFunction(Exceptions.function(PARSER::parseAndInline), 60); - } + public static EvaluationValue runLambda( + EvaluationContext context, EvaluationValue value, ASTNode predicate) + throws EvaluationException { + return context.expression().evaluateSubtree(predicate, context.withParameter("it", value)); + } + + public static EvaluationValue evaluate( + LootContext context, Expression exp, @Nullable Map params) { + try { + var builder = EvaluationContext.builder(exp).context(context); + if (params != null && !params.isEmpty()) builder.parameters(params); + return exp.evaluate(builder.build()); + } catch (BaseException e) { + throw new CmdEvalException( + Objects.requireNonNullElseGet(e.getMessage(), () -> "Failed to evaluate expression %s" + .formatted(exp.getExpressionString())), + e); } + } + + private static final Object CACHE_LOCK = new Object(); + private static Function EXPRESSION_CACHE; + + static { + resetCache(); + } - public static DataResult parseExpression(String expression) { - try { - Expression result; - synchronized (CACHE_LOCK) { - result = EXPRESSION_CACHE.apply(expression); - } - return DataResult.success(result.copy()); - } catch (Throwable throwable) { - var unwrapped = Exceptions.unwrap(throwable); - return DataResult.error(unwrapped::getMessage); - } + public static void resetCache() { + synchronized (CACHE_LOCK) { + EXPRESSION_CACHE = Memoize.lruFunction(Exceptions.function(PARSER::parseAndInline), 60); } + } - public static class LootContextDataAccessor implements DataAccessorIfc { - - private static final Map> overrides = new Object2ReferenceOpenHashMap<>(Map.of( - new Identifier("level"), LootContext::getWorld, - new Identifier("luck"), LootContext::getLuck - )); - //In most cases the expression is reused, so caching this helps us avoid some big overhead. - private final Map> varCache = new Object2ReferenceOpenHashMap<>(); - - @Override - public EvaluationValue getData(String variable, Token token, EvaluationContext context) throws EvaluationException { - var supplier = varCache.get(variable); - if (supplier != null) return supplier.apply((LootContext) context.context()[0]); //Parameters are cached by setData, so this is fine. - - var r = Identifier.validate(variable); - if (r.error().isPresent()) { - throw new EvaluationException(token, "%s - no such variable or %s".formatted(variable, r.error().orElseThrow().message())); - } - - var id = r.result().orElseThrow(); - var func = overrides.get(id); - if (func != null) { - varCache.put(variable, supplier = (lootContext) -> ReflectiveValueConverter.convert(func.apply(lootContext))); - return supplier.apply((LootContext) context.context()[0]); - } - - var param = ExtractionTypes.getParameter(id); - if (param == null) { - throw new EvaluationException(token, "%s is not a registered loot context parameter, variable or override!".formatted(id)); - } - varCache.put(variable, supplier = (lootContext) -> { - var object = lootContext.get(param); - if (object == null) return null; - return ReflectiveValueConverter.convert(object); - }); - return supplier.apply((LootContext) context.context()[0]); - } + public static DataResult parseExpression(String expression) { + try { + Expression result; + synchronized (CACHE_LOCK) { + result = EXPRESSION_CACHE.apply(expression); + } + return DataResult.success(result.copy()); + } catch (Throwable throwable) { + var unwrapped = Exceptions.unwrap(throwable); + return DataResult.error(unwrapped::getMessage); } + } + + public static class LootContextDataAccessor implements DataAccessorIfc { + + private static final Map> overrides = + new Object2ReferenceOpenHashMap<>(Map.of( + new Identifier("level"), LootContext::getWorld, + new Identifier("luck"), LootContext::getLuck)); + // In most cases the expression is reused, so caching this helps us avoid some big overhead. + private final Map> varCache = + new Object2ReferenceOpenHashMap<>(); - public static void init() { + @Override + public EvaluationValue getData(String variable, Token token, EvaluationContext context) + throws EvaluationException { + var supplier = varCache.get(variable); + if (supplier != null) + return supplier.apply((LootContext) + context.context()[0]); // Parameters are cached by setData, so this is fine. + + var r = Identifier.validate(variable); + if (r.error().isPresent()) { + throw new EvaluationException( + token, + "%s - no such variable or %s" + .formatted(variable, r.error().orElseThrow().message())); + } + + var id = r.result().orElseThrow(); + var func = overrides.get(id); + if (func != null) { + varCache.put( + variable, + supplier = (lootContext) -> ReflectiveValueConverter.convert(func.apply(lootContext))); + return supplier.apply((LootContext) context.context()[0]); + } + + var param = ExtractionTypes.getParameter(id); + if (param == null) { + throw new EvaluationException( + token, + "%s is not a registered loot context parameter, variable or override!".formatted(id)); + } + varCache.put( + variable, + supplier = (lootContext) -> { + var object = lootContext.get(param); + if (object == null) return null; + return ReflectiveValueConverter.convert(object); + }); + return supplier.apply((LootContext) context.context()[0]); } + } + + public static void init() {} } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/DefaultCustomFields.java b/src/main/java/me/melontini/commander/impl/expression/extensions/DefaultCustomFields.java index 2042ae4..465cb47 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/DefaultCustomFields.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/DefaultCustomFields.java @@ -17,20 +17,25 @@ import net.minecraft.state.State; class DefaultCustomFields { - private static final NbtCompound EMPTY = new NbtCompound(); + private static final NbtCompound EMPTY = new NbtCompound(); - static void init() { - CustomFields.addVirtualField(ItemStack.class, "nbt", object -> { - if (object.getNbt() == null) return EMPTY; - return object.getNbt(); - }); - CustomFields.addVirtualField(Entity.class, "nbt", NbtPredicate::entityToNbt); - CustomFields.addVirtualField(BlockEntity.class, "nbt", BlockEntity::createNbtWithIdentifyingData); + static void init() { + CustomFields.addVirtualField(ItemStack.class, "nbt", object -> { + if (object.getNbt() == null) return EMPTY; + return object.getNbt(); + }); + CustomFields.addVirtualField(Entity.class, "nbt", NbtPredicate::entityToNbt); + CustomFields.addVirtualField( + BlockEntity.class, "nbt", BlockEntity::createNbtWithIdentifyingData); - CustomFields.addVirtualField(State.class, "properties", StateStruct::new); - CustomFields.addVirtualField(LivingEntity.class, "attributes", e -> new EntityAttributesStruct(e.getAttributes())); + CustomFields.addVirtualField(State.class, "properties", StateStruct::new); + CustomFields.addVirtualField( + LivingEntity.class, "attributes", e -> new EntityAttributesStruct(e.getAttributes())); - CustomFields.addVirtualField(AttachmentTarget.class, "storage", target -> target.getAttachedOrCreate(Commander.DATA_ATTACHMENT)); - CustomFields.addVirtualField(Registry.class, "access", RegistryAccessStruct::forRegistry); - } + CustomFields.addVirtualField( + AttachmentTarget.class, + "storage", + target -> target.getAttachedOrCreate(Commander.DATA_ATTACHMENT)); + CustomFields.addVirtualField(Registry.class, "access", RegistryAccessStruct::forRegistry); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveMapStructure.java b/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveMapStructure.java index 225360d..ae66a7c 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveMapStructure.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveMapStructure.java @@ -4,16 +4,6 @@ import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -import lombok.EqualsAndHashCode; -import lombok.NonNull; -import lombok.Synchronized; -import lombok.extern.log4j.Log4j2; -import me.melontini.commander.api.expression.extensions.ProxyMap; -import me.melontini.commander.impl.Commander; -import me.melontini.commander.impl.expression.CmdEvalException; -import me.melontini.dark_matter.api.base.util.tuple.Tuple; -import org.jetbrains.annotations.Nullable; - import java.lang.invoke.CallSite; import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandles; @@ -23,187 +13,206 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.function.Function; +import lombok.EqualsAndHashCode; +import lombok.NonNull; +import lombok.Synchronized; +import lombok.extern.log4j.Log4j2; +import me.melontini.commander.api.expression.extensions.ProxyMap; +import me.melontini.commander.impl.Commander; +import me.melontini.commander.impl.expression.CmdEvalException; +import me.melontini.dark_matter.api.base.util.tuple.Tuple; +import org.jetbrains.annotations.Nullable; -@Log4j2 @EqualsAndHashCode(callSuper = false) +@Log4j2 +@EqualsAndHashCode(callSuper = false) public class ReflectiveMapStructure extends ProxyMap { - private static final Map, Struct> MAPPINGS = new Reference2ReferenceOpenHashMap<>(); - private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + private static final Map, Struct> MAPPINGS = new Reference2ReferenceOpenHashMap<>(); + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - static { - DefaultCustomFields.init(); - } + static { + DefaultCustomFields.init(); + } - @EqualsAndHashCode.Exclude - private final Struct mappings; - private final Object object; + @EqualsAndHashCode.Exclude + private final Struct mappings; - public ReflectiveMapStructure(Object object) { - this.object = object; - this.mappings = getAccessors(object.getClass()); - } - - public static void addField(Class cls, String name, Function accessor) { - ReflectiveMapStructure.getAccessors(cls).addAccessor(name, (Function) accessor); - } + private final Object object; - private static Struct getAccessors(Class cls) { - Struct map = MAPPINGS.get(cls); - if (map != null) return map; - - synchronized (MAPPINGS) { - Struct struct = new Struct(); - - for (Class anInterface : cls.getInterfaces()) { - getAccessors(anInterface).addListener(struct); - } - Class target = cls; - while ((target = target.getSuperclass()) != null) { - getAccessors(target).addListener(struct); - for (Class anInterface : cls.getInterfaces()) { - getAccessors(anInterface).addListener(struct); - } - } - - MAPPINGS.put(cls, struct); - return struct; - } - } + public ReflectiveMapStructure(Object object) { + this.object = object; + this.mappings = getAccessors(object.getClass()); + } - private static Function methodAccessor(Method method) { - try { - var handle = LOOKUP.unreflect(method); - CallSite getterSite = LambdaMetafactory.metafactory(LOOKUP, - "apply", - MethodType.methodType(Function.class), - MethodType.methodType(Object.class, Object.class), - handle, handle.type().wrap()); - return (Function) getterSite.getTarget().invoke(); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } + public static void addField(Class cls, String name, Function accessor) { + ReflectiveMapStructure.getAccessors(cls).addAccessor(name, (Function) accessor); + } - @Override - public boolean containsKey(String key) { - if (this.mappings.isInvalid(key)) return false; + private static Struct getAccessors(Class cls) { + Struct map = MAPPINGS.get(cls); + if (map != null) return map; - var cache = this.mappings.getAccessor(key); - if (cache != null) return true; + synchronized (MAPPINGS) { + Struct struct = new Struct(); - var accessor = findFieldOrMethod(this.object.getClass(), key); - if (accessor == null) { - this.mappings.invalidate(key); - return false; + for (Class anInterface : cls.getInterfaces()) { + getAccessors(anInterface).addListener(struct); + } + Class target = cls; + while ((target = target.getSuperclass()) != null) { + getAccessors(target).addListener(struct); + for (Class anInterface : cls.getInterfaces()) { + getAccessors(anInterface).addListener(struct); } + } - synchronized (MAPPINGS) { - getAccessors(accessor.left()).addAccessor(key, accessor.right()); - } - return true; + MAPPINGS.put(cls, struct); + return struct; } - - private static @Nullable Tuple, Function> findFieldOrMethod(Class cls, String name) { - var keeper = Commander.get().mappingKeeper(); - String mapped; - Class target = cls; - do { - if ((mapped = keeper.getFieldOrMethod(target, name)) != null) return findAccessor(target, mapped); - var targetItfs = target.getInterfaces(); - if (targetItfs.length == 0) continue; - - Queue> interfaces = new ArrayDeque<>(List.of(targetItfs)); - while (!interfaces.isEmpty()) { - var itf = interfaces.poll(); - - if ((mapped = keeper.getFieldOrMethod(itf, name)) != null) return findAccessor(itf, mapped); - if ((targetItfs = itf.getInterfaces()).length > 0) interfaces.addAll(List.of(targetItfs)); - } - } while ((target = target.getSuperclass()) != null); - return findAccessor(cls, name); + } + + private static Function methodAccessor(Method method) { + try { + var handle = LOOKUP.unreflect(method); + CallSite getterSite = LambdaMetafactory.metafactory( + LOOKUP, + "apply", + MethodType.methodType(Function.class), + MethodType.methodType(Object.class, Object.class), + handle, + handle.type().wrap()); + return (Function) getterSite.getTarget().invoke(); + } catch (Throwable e) { + throw new RuntimeException(e); } + } - @Nullable private static Tuple, Function> findAccessor(@NonNull Class cls, String mapped) { - for (Method method : cls.getMethods()) { - if (!method.getName().equals(mapped)) continue; - if (Modifier.isStatic(method.getModifiers())) continue; - if (method.getParameterCount() > 0) continue; - if (method.getReturnType() == void.class) continue; + @Override + public boolean containsKey(String key) { + if (this.mappings.isInvalid(key)) return false; - return Tuple.of(method.getDeclaringClass(), methodAccessor(method)); - } + var cache = this.mappings.getAccessor(key); + if (cache != null) return true; - for (Field field : cls.getFields()) { - if (!field.getName().equals(mapped)) continue; - if (Modifier.isStatic(field.getModifiers())) continue; - return Tuple.of(field.getDeclaringClass(), o -> { - try { - return field.get(o); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } + var accessor = findFieldOrMethod(this.object.getClass(), key); + if (accessor == null) { + this.mappings.invalidate(key); + return false; + } - return null; + synchronized (MAPPINGS) { + getAccessors(accessor.left()).addAccessor(key, accessor.right()); + } + return true; + } + + private static @Nullable Tuple, Function> findFieldOrMethod( + Class cls, String name) { + var keeper = Commander.get().mappingKeeper(); + String mapped; + Class target = cls; + do { + if ((mapped = keeper.getFieldOrMethod(target, name)) != null) + return findAccessor(target, mapped); + var targetItfs = target.getInterfaces(); + if (targetItfs.length == 0) continue; + + Queue> interfaces = new ArrayDeque<>(List.of(targetItfs)); + while (!interfaces.isEmpty()) { + var itf = interfaces.poll(); + + if ((mapped = keeper.getFieldOrMethod(itf, name)) != null) return findAccessor(itf, mapped); + if ((targetItfs = itf.getInterfaces()).length > 0) interfaces.addAll(List.of(targetItfs)); + } + } while ((target = target.getSuperclass()) != null); + return findAccessor(cls, name); + } + + @Nullable private static Tuple, Function> findAccessor( + @NonNull Class cls, String mapped) { + for (Method method : cls.getMethods()) { + if (!method.getName().equals(mapped)) continue; + if (Modifier.isStatic(method.getModifiers())) continue; + if (method.getParameterCount() > 0) continue; + if (method.getReturnType() == void.class) continue; + + return Tuple.of(method.getDeclaringClass(), methodAccessor(method)); } - @Override - public Object getValue(String key) { + for (Field field : cls.getFields()) { + if (!field.getName().equals(mapped)) continue; + if (Modifier.isStatic(field.getModifiers())) continue; + return Tuple.of(field.getDeclaringClass(), o -> { try { - Function field = this.mappings.getAccessor(key); - if (field == null) throw new RuntimeException("%s has no public field or method '%s'".formatted(this.object.getClass().getSimpleName(), key)); - return field.apply(this.object); - } catch (Exception e) { - throw new CmdEvalException(Objects.requireNonNullElse(e.getMessage(), "Failed to reflectively access member!")); + return field.get(o); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); } + }); } - @Override - public String toString() { - return String.valueOf(this.object); + return null; + } + + @Override + public Object getValue(String key) { + try { + Function field = this.mappings.getAccessor(key); + if (field == null) + throw new RuntimeException("%s has no public field or method '%s'" + .formatted(this.object.getClass().getSimpleName(), key)); + return field.apply(this.object); + } catch (Exception e) { + throw new CmdEvalException( + Objects.requireNonNullElse(e.getMessage(), "Failed to reflectively access member!")); } + } - static final class Struct { - private Map> accessors; - private Set invalid; - private Set consumers; + @Override + public String toString() { + return String.valueOf(this.object); + } - public boolean isInvalid(String key) { - return this.invalid != null && this.invalid.contains(key); - } + static final class Struct { + private Map> accessors; + private Set invalid; + private Set consumers; - @Synchronized - public void invalidate(String key) { - if (this.invalid == null) this.invalid = new ObjectOpenHashSet<>(); - this.invalid.add(key); - } + public boolean isInvalid(String key) { + return this.invalid != null && this.invalid.contains(key); + } - public @Nullable Function getAccessor(String key) { - return this.accessors == null ? null : this.accessors.get(key); - } + @Synchronized + public void invalidate(String key) { + if (this.invalid == null) this.invalid = new ObjectOpenHashSet<>(); + this.invalid.add(key); + } - @Synchronized - public void addAccessor(String key, Function accessor) { - if (this.accessors == null) this.accessors = new Object2ReferenceOpenHashMap<>(); - this.accessors.put(key, accessor); + public @Nullable Function getAccessor(String key) { + return this.accessors == null ? null : this.accessors.get(key); + } - if (this.consumers == null) return; - for (Struct consumer : consumers) { - consumer.addAccessor(key, accessor); - } - } + @Synchronized + public void addAccessor(String key, Function accessor) { + if (this.accessors == null) this.accessors = new Object2ReferenceOpenHashMap<>(); + this.accessors.put(key, accessor); - @Synchronized - public void addListener(Struct other) { - if (this.consumers == null) this.consumers = new ReferenceOpenHashSet<>(); - this.consumers.add(other); - if (this.accessors != null) this.accessors.forEach(other::addAccessor); - } + if (this.consumers == null) return; + for (Struct consumer : consumers) { + consumer.addAccessor(key, accessor); + } + } - @Override - public String toString() { - return String.valueOf(this.accessors); - } + @Synchronized + public void addListener(Struct other) { + if (this.consumers == null) this.consumers = new ReferenceOpenHashSet<>(); + this.consumers.add(other); + if (this.accessors != null) this.accessors.forEach(other::addAccessor); + } + + @Override + public String toString() { + return String.valueOf(this.accessors); } + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveValueConverter.java b/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveValueConverter.java index 7d02903..52cf646 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveValueConverter.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/ReflectiveValueConverter.java @@ -6,57 +6,61 @@ import com.ezylang.evalex.data.conversion.*; import com.ezylang.evalex.data.types.NullValue; import com.ezylang.evalex.data.types.StructureValue; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Map; import me.melontini.commander.api.expression.extensions.ObjectConverter; import me.melontini.commander.api.expression.extensions.ProxyMap; import me.melontini.commander.impl.expression.EvalUtils; import me.melontini.commander.impl.expression.extensions.convert.nbt.NbtConverter; import me.melontini.dark_matter.api.base.util.MathUtil; -import java.util.List; -import java.util.Map; - public class ReflectiveValueConverter implements EvaluationValueConverterIfc { - private static final List converters = Lists.newArrayList( - new NumberConverter(), - new StringConverter(), - new BooleanConverter(), - new ExpressionNodeConverter(), - new NbtConverter(), - new ArrayConverter(), - new DateTimeConverter(), - new DurationConverter()); - - public static void registerConverter(int priority, ObjectConverter converter) { - priority = MathUtil.clamp(priority, 0, converters.size()); - - converters.add(priority, new ConverterIfc() { - @Override - public EvaluationValue convert(Object object, ExpressionConfiguration configuration) { - return (EvaluationValue) (Object) converter.convert(object); - } - - @Override - public boolean canConvert(Object object) { - return converter.canConvert(object); - } - }); - } + private static final List converters = Lists.newArrayList( + new NumberConverter(), + new StringConverter(), + new BooleanConverter(), + new ExpressionNodeConverter(), + new NbtConverter(), + new ArrayConverter(), + new DateTimeConverter(), + new DurationConverter()); - public static EvaluationValue convert(Object o) { - return EvalUtils.CONFIGURATION.getEvaluationValueConverter().convertObject(o, EvalUtils.CONFIGURATION); - } + public static void registerConverter(int priority, ObjectConverter converter) { + priority = MathUtil.clamp(priority, 0, converters.size()); + + converters.add(priority, new ConverterIfc() { + @Override + public EvaluationValue convert(Object object, ExpressionConfiguration configuration) { + return (EvaluationValue) (Object) converter.convert(object); + } - @Override - public EvaluationValue convertObject(Object object, ExpressionConfiguration configuration) { - if (object == null) return NullValue.of(); - if (object instanceof EvaluationValue value) return value; - if (object instanceof ProxyMap map) return StructureValue.of((Map) (Object) map); //Proxy maps convert all of their outputs. + @Override + public boolean canConvert(Object object) { + return converter.canConvert(object); + } + }); + } - for (ConverterIfc converter : converters) { - if (converter.canConvert(object)) return converter.convert(object, configuration); - } + public static EvaluationValue convert(Object o) { + return EvalUtils.CONFIGURATION + .getEvaluationValueConverter() + .convertObject(o, EvalUtils.CONFIGURATION); + } - return StructureValue.of((Map) (Object) new ReflectiveMapStructure(object)); + @Override + public EvaluationValue convertObject(Object object, ExpressionConfiguration configuration) { + if (object == null) return NullValue.of(); + if (object instanceof EvaluationValue value) return value; + if (object instanceof ProxyMap map) + return StructureValue.of( + (Map) (Object) map); // Proxy maps convert all of their outputs. + + for (ConverterIfc converter : converters) { + if (converter.canConvert(object)) return converter.convert(object, configuration); } + + return StructureValue.of( + (Map) (Object) new ReflectiveMapStructure(object)); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/RegistryAccessStruct.java b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/RegistryAccessStruct.java index ad6b446..0b8926f 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/RegistryAccessStruct.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/RegistryAccessStruct.java @@ -1,5 +1,6 @@ package me.melontini.commander.impl.expression.extensions.convert; +import java.util.function.Function; import lombok.EqualsAndHashCode; import me.melontini.commander.api.expression.extensions.ProxyMap; import me.melontini.commander.impl.util.Identity; @@ -7,55 +8,53 @@ import me.melontini.dark_matter.api.base.util.functions.Memoize; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; -import java.util.function.Function; - @EqualsAndHashCode(callSuper = false) public class RegistryAccessStruct extends ProxyMap { - private static final Object CACHE_LOCK = new Object(); - private static Function>, RegistryAccessStruct> CACHE; + private static final Object CACHE_LOCK = new Object(); + private static Function>, RegistryAccessStruct> CACHE; - static { - resetCache(); - } + static { + resetCache(); + } - public static void resetCache() { - synchronized (CACHE_LOCK) { - CACHE = Memoize.lruFunction(identity -> new RegistryAccessStruct(identity.value()), 10); - } + public static void resetCache() { + synchronized (CACHE_LOCK) { + CACHE = Memoize.lruFunction(identity -> new RegistryAccessStruct(identity.value()), 10); } + } - public synchronized static RegistryAccessStruct forRegistry(Registry registry) { - synchronized (CACHE_LOCK) { - return CACHE.apply(new Identity<>(registry)); - } + public static synchronized RegistryAccessStruct forRegistry(Registry registry) { + synchronized (CACHE_LOCK) { + return CACHE.apply(new Identity<>(registry)); } + } - private final Registry registry; - private final Function cache; + private final Registry registry; + private final Function cache; - private RegistryAccessStruct(Registry registry) { - this.registry = registry; - this.cache = Memoize.lruFunction(key -> registry.get(new Identifier(key)), 20); - } + private RegistryAccessStruct(Registry registry) { + this.registry = registry; + this.cache = Memoize.lruFunction(key -> registry.get(new Identifier(key)), 20); + } - @Override - public boolean containsKey(String key) { - return this.cache.apply(key) != null; - } + @Override + public boolean containsKey(String key) { + return this.cache.apply(key) != null; + } - @Override - public Object getValue(String key) { - return this.cache.apply(key); - } + @Override + public Object getValue(String key) { + return this.cache.apply(key); + } - @Override - public int size() { - return registry.size(); - } + @Override + public int size() { + return registry.size(); + } - @Override - public String toString() { - return String.valueOf(registry); - } + @Override + public String toString() { + return String.valueOf(registry); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/attributes/EntityAttributesStruct.java b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/attributes/EntityAttributesStruct.java index 4e39387..4945629 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/attributes/EntityAttributesStruct.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/attributes/EntityAttributesStruct.java @@ -6,30 +6,29 @@ import net.minecraft.entity.attribute.AttributeContainer; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; - @EqualsAndHashCode(callSuper = false) public class EntityAttributesStruct extends ProxyMap { - private final AttributeContainer container; + private final AttributeContainer container; - public EntityAttributesStruct(AttributeContainer container) { - this.container = container; - } + public EntityAttributesStruct(AttributeContainer container) { + this.container = container; + } - @Override - public boolean containsKey(String key) { - var attr = Registries.ATTRIBUTE.get(new Identifier(key)); - if (attr == null) return false; - return container.hasAttribute(attr); - } + @Override + public boolean containsKey(String key) { + var attr = Registries.ATTRIBUTE.get(new Identifier(key)); + if (attr == null) return false; + return container.hasAttribute(attr); + } - @Override - public Object getValue(String key) { - return container.getValue(Registries.ATTRIBUTE.get(new Identifier(key))); - } + @Override + public Object getValue(String key) { + return container.getValue(Registries.ATTRIBUTE.get(new Identifier(key))); + } - @Override - public String toString() { - return String.valueOf(container.toNbt()); - } + @Override + public String toString() { + return String.valueOf(container.toNbt()); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtCompoundStruct.java b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtCompoundStruct.java index bbf5609..8936727 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtCompoundStruct.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtCompoundStruct.java @@ -7,29 +7,29 @@ import net.minecraft.nbt.NbtCompound; @EqualsAndHashCode(callSuper = false) public class NbtCompoundStruct extends ProxyMap { - private final NbtCompound compound; - - public NbtCompoundStruct(NbtCompound compound) { - this.compound = compound; - } - - @Override - public boolean containsKey(String key) { - return compound.contains(key); - } - - @Override - public Object getValue(String key) { - return compound.get(key); - } - - @Override - public int size() { - return compound.getSize(); - } - - @Override - public String toString() { - return String.valueOf(compound); - } + private final NbtCompound compound; + + public NbtCompoundStruct(NbtCompound compound) { + this.compound = compound; + } + + @Override + public boolean containsKey(String key) { + return compound.contains(key); + } + + @Override + public Object getValue(String key) { + return compound.get(key); + } + + @Override + public int size() { + return compound.getSize(); + } + + @Override + public String toString() { + return String.valueOf(compound); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtConverter.java b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtConverter.java index e4a0d12..ddee13c 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtConverter.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/nbt/NbtConverter.java @@ -8,32 +8,31 @@ import com.ezylang.evalex.data.types.ArrayValue; import com.ezylang.evalex.data.types.StringValue; import com.ezylang.evalex.data.types.StructureValue; import com.ezylang.evalex.data.util.LazyListWrapper; -import net.minecraft.nbt.*; - import java.util.Map; +import net.minecraft.nbt.*; public class NbtConverter implements ConverterIfc { - private final NumberConverter converter = new NumberConverter(); + private final NumberConverter converter = new NumberConverter(); - @Override - public EvaluationValue convert(Object object, ExpressionConfiguration configuration) { + @Override + public EvaluationValue convert(Object object, ExpressionConfiguration configuration) { - if (object instanceof AbstractNbtNumber n) { - return converter.convert(n.numberValue(), configuration); - } else if (object instanceof NbtString n) { - return StringValue.of(n.asString()); - } else if (object instanceof AbstractNbtList n) { - return ArrayValue.of(new LazyListWrapper(n, configuration)); - } else if (object instanceof NbtCompound n) { - return StructureValue.of((Map) (Object) new NbtCompoundStruct(n)); - } - - throw illegalArgument(object); + if (object instanceof AbstractNbtNumber n) { + return converter.convert(n.numberValue(), configuration); + } else if (object instanceof NbtString n) { + return StringValue.of(n.asString()); + } else if (object instanceof AbstractNbtList n) { + return ArrayValue.of(new LazyListWrapper(n, configuration)); + } else if (object instanceof NbtCompound n) { + return StructureValue.of((Map) (Object) new NbtCompoundStruct(n)); } - @Override - public boolean canConvert(Object object) { - return object instanceof NbtElement; - } + throw illegalArgument(object); + } + + @Override + public boolean canConvert(Object object) { + return object instanceof NbtElement; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/states/StateStruct.java b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/states/StateStruct.java index 3fa42b9..237f4d5 100644 --- a/src/main/java/me/melontini/commander/impl/expression/extensions/convert/states/StateStruct.java +++ b/src/main/java/me/melontini/commander/impl/expression/extensions/convert/states/StateStruct.java @@ -8,35 +8,35 @@ import net.minecraft.state.property.Property; @EqualsAndHashCode(callSuper = false) public class StateStruct extends ProxyMap { - private final State state; + private final State state; - public StateStruct(State state) { - this.state = state; - } - - @Override - public boolean containsKey(String key) { - for (Entry, Comparable> e : state.getEntries().entrySet()) { - if (e.getKey().getName().equals(key)) return true; - } - return false; - } - - @Override - public Object getValue(String key) { - for (Entry, Comparable> e : state.getEntries().entrySet()) { - if (e.getKey().getName().equals(key)) return e.getValue(); - } - return null; - } + public StateStruct(State state) { + this.state = state; + } - @Override - public int size() { - return state.getEntries().size(); + @Override + public boolean containsKey(String key) { + for (Entry, Comparable> e : state.getEntries().entrySet()) { + if (e.getKey().getName().equals(key)) return true; } + return false; + } - @Override - public String toString() { - return String.valueOf(state.getEntries()); + @Override + public Object getValue(String key) { + for (Entry, Comparable> e : state.getEntries().entrySet()) { + if (e.getKey().getName().equals(key)) return e.getValue(); } + return null; + } + + @Override + public int size() { + return state.getEntries().size(); + } + + @Override + public String toString() { + return String.valueOf(state.getEntries()); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/ChainFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/ChainFunction.java index 5e7c759..60514cd 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/ChainFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/ChainFunction.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -8,32 +10,31 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import org.jetbrains.annotations.Nullable; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "value") @FunctionParameter(name = "actions", isLazy = true, isVarArg = true) public class ChainFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token token, EvaluationValue... par) throws EvaluationException { - var value = par[0]; - for (int i = 1; i < par.length; i++) { - value = runLambda(context, value, par[i].getExpressionNode()); - } - return value; + @Override + public EvaluationValue evaluate(EvaluationContext context, Token token, EvaluationValue... par) + throws EvaluationException { + var value = par[0]; + for (int i = 1; i < par.length; i++) { + value = runLambda(context, value, par[i].getExpressionNode()); } + return value; + } - @Override - public boolean forceInline() { - return true; - } + @Override + public boolean forceInline() { + return true; + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/HasContextFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/HasContextFunction.java index 4f72775..f51aedb 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/HasContextFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/HasContextFunction.java @@ -9,29 +9,32 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import org.jetbrains.annotations.Nullable; - import java.util.List; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "key", isVarArg = true) public class HasContextFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token token, EvaluationValue... par) throws EvaluationException { - return switch (par.length) { - case 0 -> BooleanValue.TRUE; - case 1 -> BooleanValue.of(context.expression().getDataAccessor().getData(par[0].getStringValue(), token, context) != null); - default -> { - var da = context.expression().getDataAccessor(); - for (EvaluationValue value : par) { - if (da.getData(value.getStringValue(), token, context) == null) yield BooleanValue.FALSE; - } - yield BooleanValue.TRUE; - } - }; - } + @Override + public EvaluationValue evaluate(EvaluationContext context, Token token, EvaluationValue... par) + throws EvaluationException { + return switch (par.length) { + case 0 -> BooleanValue.TRUE; + case 1 -> BooleanValue.of( + context.expression().getDataAccessor().getData(par[0].getStringValue(), token, context) + != null); + default -> { + var da = context.expression().getDataAccessor(); + for (EvaluationValue value : par) { + if (da.getData(value.getStringValue(), token, context) == null) yield BooleanValue.FALSE; + } + yield BooleanValue.TRUE; + } + }; + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/LengthFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/LengthFunction.java index 256e2d1..e4e365b 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/LengthFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/LengthFunction.java @@ -9,33 +9,44 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.commander.impl.expression.EvalUtils; -import org.jetbrains.annotations.Nullable; - import java.math.BigDecimal; import java.util.List; +import me.melontini.commander.impl.expression.EvalUtils; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "value") public class LengthFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - EvaluationValue value = par[0]; + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + EvaluationValue value = par[0]; - if (value.isStringValue()) return context.expression().convertValue(value.getStringValue().length()); - if (value.isArrayValue()) return context.expression().convertValue(value.getArrayValue().size()); - if (value.isStructureValue()) return context.expression().convertValue(value.getStructureValue().size()); - if (value.isDurationValue()) return context.expression().convertValue(value.getDurationValue().toMillis()); + if (value.isStringValue()) + return context.expression().convertValue(value.getStringValue().length()); + if (value.isArrayValue()) + return context.expression().convertValue(value.getArrayValue().size()); + if (value.isStructureValue()) + return context.expression().convertValue(value.getStructureValue().size()); + if (value.isDurationValue()) + return context.expression().convertValue(value.getDurationValue().toMillis()); - return NumberValue.of(BigDecimal.ZERO); - } + return NumberValue.of(BigDecimal.ZERO); + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return EvalUtils.valueOrEmpty(parameters.get(0)).map(value -> { - if (value.isStringValue()) return expression.convertValue(value.getStringValue().length()); - if (value.isArrayValue()) return expression.convertValue(value.getArrayValue().size()); - if (value.isDurationValue()) return expression.convertValue(value.getDurationValue().toMillis()); - return null; - }).orElse(null); - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return EvalUtils.valueOrEmpty(parameters.get(0)) + .map(value -> { + if (value.isStringValue()) + return expression.convertValue(value.getStringValue().length()); + if (value.isArrayValue()) + return expression.convertValue(value.getArrayValue().size()); + if (value.isDurationValue()) + return expression.convertValue(value.getDurationValue().toMillis()); + return null; + }) + .orElse(null); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/LruCachingFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/LruCachingFunction.java index e18d703..df6c6d7 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/LruCachingFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/LruCachingFunction.java @@ -6,83 +6,86 @@ import com.ezylang.evalex.data.EvaluationValue; import com.ezylang.evalex.functions.FunctionIfc; import com.ezylang.evalex.functions.FunctionParameterDefinition; import com.ezylang.evalex.parser.Token; - import java.util.*; import java.util.function.Function; public class LruCachingFunction implements FunctionIfc { - public static FunctionIfc of(FunctionIfc delegate) { - return new LruCachingFunction(delegate); - } + public static FunctionIfc of(FunctionIfc delegate) { + return new LruCachingFunction(delegate); + } - private final FunctionIfc delegate; - private final Function keyGetter; - private final Map cache = Collections.synchronizedMap(new LinkedHashMap<>(128 + 1, 0.75f, true) { + private final FunctionIfc delegate; + private final Function keyGetter; + private final Map cache = + Collections.synchronizedMap(new LinkedHashMap<>(128 + 1, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > 128; + return size() > 128; } - }); + }); - public LruCachingFunction(FunctionIfc delegate) { - this.delegate = delegate; + public LruCachingFunction(FunctionIfc delegate) { + this.delegate = delegate; - if (this.delegate.getFunctionParameterDefinitions().size() == 1) { - this.keyGetter = vals -> vals[0].getValue(); - } else { - this.keyGetter = ArrayEqualityWrapper::new; - } + if (this.delegate.getFunctionParameterDefinitions().size() == 1) { + this.keyGetter = vals -> vals[0].getValue(); + } else { + this.keyGetter = ArrayEqualityWrapper::new; } - - @Override - public List getFunctionParameterDefinitions() { - return delegate.getFunctionParameterDefinitions(); + } + + @Override + public List getFunctionParameterDefinitions() { + return delegate.getFunctionParameterDefinitions(); + } + + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... parameterValues) + throws EvaluationException { + var key = this.keyGetter.apply(parameterValues); + var r = this.cache.get(key); + if (r == null) { + r = delegate.evaluate(context, functionToken, parameterValues); + this.cache.put(key, r); + return r; } + return r; + } - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... parameterValues) throws EvaluationException { - var key = this.keyGetter.apply(parameterValues); - var r = this.cache.get(key); - if (r == null) { - r = delegate.evaluate(context, functionToken, parameterValues); - this.cache.put(key, r); - return r; - } - return r; - } + @Override + public void validatePreEvaluation(Token token, EvaluationValue... parameterValues) + throws EvaluationException { + delegate.validatePreEvaluation(token, parameterValues); + } - @Override - public void validatePreEvaluation(Token token, EvaluationValue... parameterValues) throws EvaluationException { - delegate.validatePreEvaluation(token, parameterValues); - } + @Override + public boolean hasVarArgs() { + return delegate.hasVarArgs(); + } - @Override - public boolean hasVarArgs() { - return delegate.hasVarArgs(); - } + @Override + public boolean isParameterLazy(int parameterIndex) { + return delegate.isParameterLazy(parameterIndex); + } - @Override - public boolean isParameterLazy(int parameterIndex) { - return delegate.isParameterLazy(parameterIndex); - } + @Override + public int getCountOfNonVarArgParameters() { + return delegate.getCountOfNonVarArgParameters(); + } + + private record ArrayEqualityWrapper(EvaluationValue[] arr) { @Override - public int getCountOfNonVarArgParameters() { - return delegate.getCountOfNonVarArgParameters(); + public boolean equals(Object obj) { + if (!(obj instanceof ArrayEqualityWrapper o)) return false; + return Arrays.equals(arr, o.arr); } - private record ArrayEqualityWrapper(EvaluationValue[] arr) { - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof ArrayEqualityWrapper o)) return false; - return Arrays.equals(arr, o.arr); - } - - @Override - public int hashCode() { - return Arrays.hashCode(arr); - } + @Override + public int hashCode() { + return Arrays.hashCode(arr); } + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/MatchesFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/MatchesFunction.java index 3ab8dac..e89fced 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/MatchesFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/MatchesFunction.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -8,11 +10,8 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import org.jetbrains.annotations.Nullable; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "value") @FunctionParameter(name = "predicate", isLazy = true) @@ -20,16 +19,19 @@ import static me.melontini.commander.impl.expression.EvalUtils.runLambda; @FunctionParameter(name = "ifFalse", isLazy = true) public class MatchesFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - EvaluationValue value = par[0]; - boolean predicate = runLambda(context, value, par[1].getExpressionNode()).getBooleanValue(); + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + EvaluationValue value = par[0]; + boolean predicate = runLambda(context, value, par[1].getExpressionNode()).getBooleanValue(); - return runLambda(context, value, par[predicate ? 2 : 3].getExpressionNode()); - } + return runLambda(context, value, par[predicate ? 2 : 3].getExpressionNode()); + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/StructContainsKeyFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/StructContainsKeyFunction.java index 95822dc..722fc1e 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/StructContainsKeyFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/StructContainsKeyFunction.java @@ -9,32 +9,34 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import org.jetbrains.annotations.Nullable; - import java.util.List; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "struct") @FunctionParameter(name = "key", isVarArg = true) public class StructContainsKeyFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - return switch (par.length) { - case 1 -> BooleanValue.TRUE; - case 2 -> BooleanValue.of(par[0].getStructureValue().containsKey(par[1].getStringValue())); - default -> { - var struct = par[0].getStructureValue(); - for (int i = 1; i < par.length; i++) { - var key = par[i].getStringValue(); - if (!struct.containsKey(key)) yield BooleanValue.FALSE; - } - yield BooleanValue.TRUE; - } - }; - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + return switch (par.length) { + case 1 -> BooleanValue.TRUE; + case 2 -> BooleanValue.of(par[0].getStructureValue().containsKey(par[1].getStringValue())); + default -> { + var struct = par[0].getStructureValue(); + for (int i = 1; i < par.length; i++) { + var key = par[i].getStringValue(); + if (!struct.containsKey(key)) yield BooleanValue.FALSE; + } + yield BooleanValue.TRUE; + } + }; + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAllMatch.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAllMatch.java index dbc3bed..ef4b7a3 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAllMatch.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAllMatch.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions.arrays; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -9,25 +11,27 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.dark_matter.api.base.util.Exceptions; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import me.melontini.dark_matter.api.base.util.Exceptions; @FunctionParameter(name = "array") @FunctionParameter(name = "predicate", isLazy = true) public class ArrayAllMatch extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - List array = par[0].getArrayValue(); - ASTNode predicate = par[1].getExpressionNode(); - return BooleanValue.of(array.stream().allMatch(value -> Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + List array = par[0].getArrayValue(); + ASTNode predicate = par[1].getExpressionNode(); + return BooleanValue.of(array.stream() + .allMatch(value -> + Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); + } - @Override - public EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAnyMatch.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAnyMatch.java index 1e2f5c2..9a09f41 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAnyMatch.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayAnyMatch.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions.arrays; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -9,26 +11,28 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.dark_matter.api.base.util.Exceptions; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import me.melontini.dark_matter.api.base.util.Exceptions; @FunctionParameter(name = "array") @FunctionParameter(name = "predicate", isLazy = true) public class ArrayAnyMatch extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - List array = par[0].getArrayValue(); - ASTNode predicate = par[1].getExpressionNode(); + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + List array = par[0].getArrayValue(); + ASTNode predicate = par[1].getExpressionNode(); - return BooleanValue.of(array.stream().anyMatch(value -> Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); - } + return BooleanValue.of(array.stream() + .anyMatch(value -> + Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); + } - @Override - public EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFind.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFind.java index a4c6a66..00c08ea 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFind.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFind.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions.arrays; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -9,26 +11,29 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.dark_matter.api.base.util.Exceptions; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import me.melontini.dark_matter.api.base.util.Exceptions; @FunctionParameter(name = "array") @FunctionParameter(name = "predicate", isLazy = true) public class ArrayFind extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - List array = par[0].getArrayValue(); - ASTNode predicate = par[1].getExpressionNode(); + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + List array = par[0].getArrayValue(); + ASTNode predicate = par[1].getExpressionNode(); - return ArrayValue.of(array.stream().filter(value -> Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue()).toList()); - } + return ArrayValue.of(array.stream() + .filter(value -> + Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue()) + .toList()); + } - @Override - public EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindAny.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindAny.java index 74c226e..40d922d 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindAny.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindAny.java @@ -11,8 +11,10 @@ import com.ezylang.evalex.parser.Token; @FunctionParameter(name = "array") public class ArrayFindAny extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - return par[0].getArrayValue().stream().findAny().orElse(NullValue.of()); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + return par[0].getArrayValue().stream().findAny().orElse(NullValue.of()); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindFirst.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindFirst.java index 26e723f..26cbb4d 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindFirst.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayFindFirst.java @@ -11,8 +11,10 @@ import com.ezylang.evalex.parser.Token; @FunctionParameter(name = "array") public class ArrayFindFirst extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - return par[0].getArrayValue().stream().findFirst().orElse(NullValue.of()); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + return par[0].getArrayValue().stream().findFirst().orElse(NullValue.of()); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayMap.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayMap.java index 8a5be42..f3d11be 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayMap.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayMap.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions.arrays; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -10,26 +12,27 @@ import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; import com.google.common.collect.Lists; -import me.melontini.dark_matter.api.base.util.Exceptions; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import me.melontini.dark_matter.api.base.util.Exceptions; @FunctionParameter(name = "array") @FunctionParameter(name = "function", isLazy = true) public class ArrayMap extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext expression, Token functionToken, EvaluationValue... par) throws EvaluationException { - List array = par[0].getArrayValue(); - ASTNode function = par[1].getExpressionNode(); + @Override + public EvaluationValue evaluate( + EvaluationContext expression, Token functionToken, EvaluationValue... par) + throws EvaluationException { + List array = par[0].getArrayValue(); + ASTNode function = par[1].getExpressionNode(); - return ArrayValue.of(Lists.transform(array, input -> Exceptions.supply(() -> runLambda(expression, input, function)))); - } + return ArrayValue.of(Lists.transform( + array, input -> Exceptions.supply(() -> runLambda(expression, input, function)))); + } - @Override - public EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayNoneMatch.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayNoneMatch.java index 379afe5..b969461 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayNoneMatch.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayNoneMatch.java @@ -1,5 +1,7 @@ package me.melontini.commander.impl.expression.functions.arrays; +import static me.melontini.commander.impl.expression.EvalUtils.runLambda; + import com.ezylang.evalex.EvaluationContext; import com.ezylang.evalex.EvaluationException; import com.ezylang.evalex.Expression; @@ -9,26 +11,28 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.dark_matter.api.base.util.Exceptions; - import java.util.List; - -import static me.melontini.commander.impl.expression.EvalUtils.runLambda; +import me.melontini.dark_matter.api.base.util.Exceptions; @FunctionParameter(name = "array") @FunctionParameter(name = "predicate", isLazy = true) public class ArrayNoneMatch extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - List array = par[0].getArrayValue(); - ASTNode predicate = par[1].getExpressionNode(); + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + List array = par[0].getArrayValue(); + ASTNode predicate = par[1].getExpressionNode(); - return BooleanValue.of(array.stream().noneMatch(value -> Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); - } + return BooleanValue.of(array.stream() + .noneMatch(value -> + Exceptions.supply(() -> runLambda(context, value, predicate)).getBooleanValue())); + } - @Override - public EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayOf.java b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayOf.java index 417e8e4..c868b2d 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayOf.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/arrays/ArrayOf.java @@ -7,13 +7,14 @@ import com.ezylang.evalex.data.types.ArrayValue; import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.Token; - import java.util.Arrays; @FunctionParameter(name = "args", isVarArg = true) public class ArrayOf extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - return ArrayValue.of(Arrays.asList(par)); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + return ArrayValue.of(Arrays.asList(par)); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/math/ClampFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/math/ClampFunction.java index c12e709..edbacc2 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/math/ClampFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/math/ClampFunction.java @@ -7,18 +7,19 @@ import com.ezylang.evalex.data.types.NumberValue; import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.Token; - import java.math.BigDecimal; @FunctionParameter(name = "value") @FunctionParameter(name = "min") @FunctionParameter(name = "max") public class ClampFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - BigDecimal value = par[0].getNumberValue(); - BigDecimal min = par[1].getNumberValue(); - BigDecimal max = par[2].getNumberValue(); - return NumberValue.of(value.compareTo(min) < 0 ? min : value.min(max)); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + BigDecimal value = par[0].getNumberValue(); + BigDecimal min = par[1].getNumberValue(); + BigDecimal max = par[2].getNumberValue(); + return NumberValue.of(value.compareTo(min) < 0 ? min : value.min(max)); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/math/LerpFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/math/LerpFunction.java index ebc45d9..6733545 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/math/LerpFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/math/LerpFunction.java @@ -7,18 +7,19 @@ import com.ezylang.evalex.data.types.NumberValue; import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.Token; - import java.math.BigDecimal; @FunctionParameter(name = "delta") @FunctionParameter(name = "start") @FunctionParameter(name = "end") public class LerpFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - BigDecimal start = par[0].getNumberValue(); - BigDecimal delta = par[1].getNumberValue(); - BigDecimal end = par[2].getNumberValue(); - return NumberValue.of(start.add(delta.multiply(end.subtract(start)))); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + BigDecimal start = par[0].getNumberValue(); + BigDecimal delta = par[1].getNumberValue(); + BigDecimal end = par[2].getNumberValue(); + return NumberValue.of(start.add(delta.multiply(end.subtract(start)))); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/math/RangedRandomFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/math/RangedRandomFunction.java index 5dff5fc..697ac13 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/math/RangedRandomFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/math/RangedRandomFunction.java @@ -8,24 +8,33 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; -import me.melontini.dark_matter.api.base.util.MathUtil; -import org.jetbrains.annotations.Nullable; - import java.math.BigDecimal; import java.util.List; +import me.melontini.dark_matter.api.base.util.MathUtil; +import org.jetbrains.annotations.Nullable; @FunctionParameter(name = "min") @FunctionParameter(name = "max") public class RangedRandomFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - BigDecimal min = par[0].getNumberValue(); - BigDecimal max = par[1].getNumberValue(); - return context.expression().convertValue(min.compareTo(max) >= 0 ? min : BigDecimal.valueOf(MathUtil.threadRandom().nextDouble()).multiply(max.subtract(min)).add(min)); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + BigDecimal min = par[0].getNumberValue(); + BigDecimal max = par[1].getNumberValue(); + return context + .expression() + .convertValue( + min.compareTo(max) >= 0 + ? min + : BigDecimal.valueOf(MathUtil.threadRandom().nextDouble()) + .multiply(max.subtract(min)) + .add(min)); + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryFunction.java index 7eb9098..11967e7 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryFunction.java @@ -8,6 +8,8 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; +import java.util.List; +import java.util.NoSuchElementException; import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; import net.minecraft.loot.context.LootContext; import net.minecraft.registry.Registry; @@ -15,31 +17,36 @@ import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.NoSuchElementException; - @FunctionParameter(name = "identifier") public class DynamicRegistryFunction extends AbstractFunction { - protected final RegistryKey> registry; + protected final RegistryKey> registry; - public DynamicRegistryFunction(RegistryKey> registry) { - this.registry = registry; - } + public DynamicRegistryFunction(RegistryKey> registry) { + this.registry = registry; + } - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - try { - var id = new Identifier(par[0].getStringValue()); - var server = ((LootContext)context.context()[0]).getWorld().getServer(); - return ReflectiveValueConverter.convert(server.getRegistryManager().get(registry).getOrEmpty(id).orElseThrow(() -> new NoSuchElementException("No such %s: %s".formatted(registry.getValue(), id)))); - } catch (Exception e) { - throw new EvaluationException(functionToken, e.getMessage()); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + try { + var id = new Identifier(par[0].getStringValue()); + var server = ((LootContext) context.context()[0]).getWorld().getServer(); + return ReflectiveValueConverter.convert(server + .getRegistryManager() + .get(registry) + .getOrEmpty(id) + .orElseThrow(() -> + new NoSuchElementException("No such %s: %s".formatted(registry.getValue(), id)))); + } catch (Exception e) { + throw new EvaluationException(functionToken, e.getMessage()); } + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryRegistryFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryRegistryFunction.java index 3c1dac7..158c24a 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryRegistryFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/registry/DynamicRegistryRegistryFunction.java @@ -8,31 +8,37 @@ import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.ASTNode; import com.ezylang.evalex.parser.Token; +import java.util.List; +import java.util.NoSuchElementException; import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; import net.minecraft.loot.context.LootContext; import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.NoSuchElementException; - @FunctionParameter(name = "identifier") public class DynamicRegistryRegistryFunction extends AbstractFunction { - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - try { - var id = new Identifier(par[0].getStringValue()); - var server = ((LootContext)context.context()[0]).getWorld().getServer(); - return ReflectiveValueConverter.convert(server.getRegistryManager().getOptional(RegistryKey.ofRegistry(id)).orElseThrow(() -> new NoSuchElementException("No such %s: %s".formatted("minecraft:root", id)))); - } catch (Exception e) { - throw new EvaluationException(functionToken, e.getMessage()); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + try { + var id = new Identifier(par[0].getStringValue()); + var server = ((LootContext) context.context()[0]).getWorld().getServer(); + return ReflectiveValueConverter.convert(server + .getRegistryManager() + .getOptional(RegistryKey.ofRegistry(id)) + .orElseThrow( + () -> new NoSuchElementException("No such %s: %s".formatted("minecraft:root", id)))); + } catch (Exception e) { + throw new EvaluationException(functionToken, e.getMessage()); } + } - @Override - public @Nullable EvaluationValue inlineFunction(Expression expression, Token token, List parameters) throws EvaluationException { - return null; - } + @Override + public @Nullable EvaluationValue inlineFunction( + Expression expression, Token token, List parameters) throws EvaluationException { + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/functions/registry/RegistryFunction.java b/src/main/java/me/melontini/commander/impl/expression/functions/registry/RegistryFunction.java index 1865dbb..23a4bb1 100644 --- a/src/main/java/me/melontini/commander/impl/expression/functions/registry/RegistryFunction.java +++ b/src/main/java/me/melontini/commander/impl/expression/functions/registry/RegistryFunction.java @@ -6,29 +6,33 @@ import com.ezylang.evalex.data.EvaluationValue; import com.ezylang.evalex.functions.AbstractFunction; import com.ezylang.evalex.functions.FunctionParameter; import com.ezylang.evalex.parser.Token; +import java.util.NoSuchElementException; import me.melontini.commander.impl.expression.extensions.ReflectiveValueConverter; import me.melontini.dark_matter.api.base.util.Exceptions; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; -import java.util.NoSuchElementException; - @FunctionParameter(name = "identifier") public class RegistryFunction extends AbstractFunction { - private final Registry registry; + private final Registry registry; - public RegistryFunction(Registry registry) { - this.registry = registry; - } + public RegistryFunction(Registry registry) { + this.registry = registry; + } - @Override - public EvaluationValue evaluate(EvaluationContext context, Token functionToken, EvaluationValue... par) throws EvaluationException { - try { - var id = new Identifier(par[0].getStringValue()); - return ReflectiveValueConverter.convert(this.registry.getOrEmpty(id).orElseThrow(() -> new NoSuchElementException("No such %s: %s".formatted(registry.getKey().getValue(), id)))); - } catch (Exception e) { - throw new EvaluationException(functionToken, Exceptions.unwrap(e).getMessage()); - } + @Override + public EvaluationValue evaluate( + EvaluationContext context, Token functionToken, EvaluationValue... par) + throws EvaluationException { + try { + var id = new Identifier(par[0].getStringValue()); + return ReflectiveValueConverter.convert(this.registry + .getOrEmpty(id) + .orElseThrow(() -> new NoSuchElementException( + "No such %s: %s".formatted(registry.getKey().getValue(), id)))); + } catch (Exception e) { + throw new EvaluationException(functionToken, Exceptions.unwrap(e).getMessage()); } + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/macro/ConstantMacro.java b/src/main/java/me/melontini/commander/impl/expression/macro/ConstantMacro.java index 6a6612f..e0e2f9d 100644 --- a/src/main/java/me/melontini/commander/impl/expression/macro/ConstantMacro.java +++ b/src/main/java/me/melontini/commander/impl/expression/macro/ConstantMacro.java @@ -1,13 +1,12 @@ package me.melontini.commander.impl.expression.macro; +import java.util.Map; import me.melontini.commander.api.expression.BrigadierMacro; import net.minecraft.loot.context.LootContext; -import java.util.Map; - public record ConstantMacro(String original) implements BrigadierMacro { - @Override - public String build(LootContext context, Map params) { - return original(); - } + @Override + public String build(LootContext context, Map params) { + return original(); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/macro/DynamicMacro.java b/src/main/java/me/melontini/commander/impl/expression/macro/DynamicMacro.java index 0aa4445..98c2d4d 100644 --- a/src/main/java/me/melontini/commander/impl/expression/macro/DynamicMacro.java +++ b/src/main/java/me/melontini/commander/impl/expression/macro/DynamicMacro.java @@ -1,15 +1,16 @@ package me.melontini.commander.impl.expression.macro; -import me.melontini.commander.api.expression.BrigadierMacro; -import net.minecraft.loot.context.LootContext; - import java.util.Map; import java.util.function.BiFunction; +import me.melontini.commander.api.expression.BrigadierMacro; +import net.minecraft.loot.context.LootContext; -public record DynamicMacro(String original, BiFunction, StringBuilder> start) implements BrigadierMacro { +public record DynamicMacro( + String original, BiFunction, StringBuilder> start) + implements BrigadierMacro { - @Override - public String build(LootContext context, Map params) { - return start.apply(context, params).toString(); - } + @Override + public String build(LootContext context, Map params) { + return start.apply(context, params).toString(); + } } diff --git a/src/main/java/me/melontini/commander/impl/expression/macro/PatternParser.java b/src/main/java/me/melontini/commander/impl/expression/macro/PatternParser.java index 635eb08..462e0db 100644 --- a/src/main/java/me/melontini/commander/impl/expression/macro/PatternParser.java +++ b/src/main/java/me/melontini/commander/impl/expression/macro/PatternParser.java @@ -1,13 +1,10 @@ package me.melontini.commander.impl.expression.macro; +import static me.melontini.commander.impl.expression.EvalUtils.evaluate; + import com.ezylang.evalex.data.EvaluationValue; import com.google.common.collect.ImmutableMap; import com.mojang.serialization.DataResult; -import me.melontini.commander.api.expression.BrigadierMacro; -import me.melontini.commander.impl.expression.EvalUtils; -import net.minecraft.loot.context.LootContext; -import org.jetbrains.annotations.Nullable; - import java.math.RoundingMode; import java.util.Map; import java.util.function.BiFunction; @@ -15,60 +12,67 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; - -import static me.melontini.commander.impl.expression.EvalUtils.evaluate; +import me.melontini.commander.api.expression.BrigadierMacro; +import me.melontini.commander.impl.expression.EvalUtils; +import net.minecraft.loot.context.LootContext; +import org.jetbrains.annotations.Nullable; public class PatternParser { - public static final Pattern PATTERN = Pattern.compile("\\$(?:\\(([a-z]+)\\))?\\{\\{([^{}]*)\\}\\}"); - public static final Map> CONVERTERS = ImmutableMap.of( - "bool", v -> v.getBooleanValue().toString(), - "long", v -> v.getNumberValue().setScale(0, RoundingMode.DOWN).toString(), - "int", v -> v.getNumberValue().setScale(0, RoundingMode.DOWN).toString(), - "double", v -> v.getNumberValue().toString() - ); + public static final Pattern PATTERN = + Pattern.compile("\\$(?:\\(([a-z]+)\\))?\\{\\{([^{}]*)\\}\\}"); + public static final Map> CONVERTERS = ImmutableMap.of( + "bool", v -> v.getBooleanValue().toString(), + "long", v -> v.getNumberValue().setScale(0, RoundingMode.DOWN).toString(), + "int", v -> v.getNumberValue().setScale(0, RoundingMode.DOWN).toString(), + "double", v -> v.getNumberValue().toString()); - public static final int CAST = 1; - public static final int EXPRESSION = 2; + public static final int CAST = 1; + public static final int EXPRESSION = 2; - public static DataResult parse(String input) { - Matcher matcher = PATTERN.matcher(input); - if (matcher.results().findAny().isEmpty()) return DataResult.success(new ConstantMacro(input)); - matcher.reset(); + public static DataResult parse(String input) { + Matcher matcher = PATTERN.matcher(input); + if (matcher.results().findAny().isEmpty()) return DataResult.success(new ConstantMacro(input)); + matcher.reset(); - BiFunction, StringBuilder> start = (context, params) -> new StringBuilder(); - while (matcher.find()) { - var result = parseExpression(matcher.group(EXPRESSION), matcher.group(CAST)); - if (result.error().isPresent()) return result.map(e -> null); + BiFunction, StringBuilder> start = + (context, params) -> new StringBuilder(); + while (matcher.find()) { + var result = parseExpression(matcher.group(EXPRESSION), matcher.group(CAST)); + if (result.error().isPresent()) return result.map(e -> null); - var func = result.result().orElseThrow(); - var cmd = sb(b -> matcher.appendReplacement(b, "")); - var fin = start; - start = (context, params) -> fin.apply(context, params).append(cmd).append(func.apply(context, params)); - } + var func = result.result().orElseThrow(); + var cmd = sb(b -> matcher.appendReplacement(b, "")); + var fin = start; + start = (context, params) -> + fin.apply(context, params).append(cmd).append(func.apply(context, params)); + } - var cmd = sb(matcher::appendTail); - var fin = start; - start = (context, params) -> fin.apply(context, params).append(cmd); + var cmd = sb(matcher::appendTail); + var fin = start; + start = (context, params) -> fin.apply(context, params).append(cmd); - return DataResult.success(new DynamicMacro(input, start)); - } + return DataResult.success(new DynamicMacro(input, start)); + } - private static String sb(Consumer consumer) { - var b = new StringBuilder(); - consumer.accept(b); - return b.toString(); - } + private static String sb(Consumer consumer) { + var b = new StringBuilder(); + consumer.accept(b); + return b.toString(); + } - public static DataResult, String>> parseExpression(String expression, @Nullable String cast) { - if (cast == null) - return EvalUtils.parseExpression(expression).map(exp -> (context, params) -> EvalUtils.prettyToString(evaluate(context, exp, params))); + public static DataResult, String>> parseExpression( + String expression, @Nullable String cast) { + if (cast == null) + return EvalUtils.parseExpression(expression) + .map( + exp -> (context, params) -> EvalUtils.prettyToString(evaluate(context, exp, params))); - var c = CONVERTERS.get(cast); - if (c == null) return DataResult.error(() -> "Unknown cast type %s".formatted(cast)); - return EvalUtils.parseExpression(expression).map(exp -> (context, params) -> { - var evalResult = evaluate(context, exp, params); - return evalResult.getValue() == null ? null : c.apply(evalResult); - }); - } + var c = CONVERTERS.get(cast); + if (c == null) return DataResult.error(() -> "Unknown cast type %s".formatted(cast)); + return EvalUtils.parseExpression(expression).map(exp -> (context, params) -> { + var evalResult = evaluate(context, exp, params); + return evalResult.getValue() == null ? null : c.apply(evalResult); + }); + } } diff --git a/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java b/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java index 98f9f4f..866406a 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java @@ -7,6 +7,7 @@ import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; +import java.util.List; import me.melontini.commander.api.command.Command; import me.melontini.commander.api.event.EventContext; import me.melontini.commander.api.event.EventKey; @@ -24,51 +25,57 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.List; - @Mixin(AdvancementRewards.class) public class AdvancementRewardsMixin { - @Unique private static final Codec> COMMANDER_CODEC = ExtraCodecs.list(Command.CODEC.codec()); + @Unique private static final Codec> COMMANDER_CODEC = + ExtraCodecs.list(Command.CODEC.codec()); - @Unique private List commands; + @Unique private List commands; - @ModifyReturnValue(at = @At("TAIL"), method = "toJson") - private JsonElement commander$encodeCommands(JsonElement original) { - if (!original.isJsonNull() && this.commands != null) { - var result = COMMANDER_CODEC.encodeStart(JsonOps.INSTANCE, this.commands); - if (result.error().isPresent()) throw new IllegalStateException(result.error().get().message()); - original.getAsJsonObject().add("commander:commands", result.get().orThrow()); - } - return original; + @ModifyReturnValue(at = @At("TAIL"), method = "toJson") + private JsonElement commander$encodeCommands(JsonElement original) { + if (!original.isJsonNull() && this.commands != null) { + var result = COMMANDER_CODEC.encodeStart(JsonOps.INSTANCE, this.commands); + if (result.error().isPresent()) + throw new IllegalStateException(result.error().get().message()); + original.getAsJsonObject().add("commander:commands", result.get().orThrow()); } + return original; + } - @ModifyReturnValue(at = @At("TAIL"), method = "fromJson") - private static AdvancementRewards commander$parseCommands(AdvancementRewards original, @Local(argsOnly = true) JsonObject object) { - if (object.has("commander:commands")) { - var result = COMMANDER_CODEC.parse(JsonOps.INSTANCE, object.get("commander:commands")); - if (result.error().isPresent()) throw new JsonParseException(result.error().get().message()); - ((AdvancementRewardsMixin)(Object)original).commands = result.get().orThrow(); - for (Command.Conditioned command : ((AdvancementRewardsMixin)(Object)original).commands) { - var r = command.validate(EventType.NULL); - if (r.error().isPresent()) throw new JsonParseException(r.error().get().message()); - } - } - return original; + @ModifyReturnValue(at = @At("TAIL"), method = "fromJson") + private static AdvancementRewards commander$parseCommands( + AdvancementRewards original, @Local(argsOnly = true) JsonObject object) { + if (object.has("commander:commands")) { + var result = COMMANDER_CODEC.parse(JsonOps.INSTANCE, object.get("commander:commands")); + if (result.error().isPresent()) + throw new JsonParseException(result.error().get().message()); + ((AdvancementRewardsMixin) (Object) original).commands = result.get().orThrow(); + for (Command.Conditioned command : ((AdvancementRewardsMixin) (Object) original).commands) { + var r = command.validate(EventType.NULL); + if (r.error().isPresent()) throw new JsonParseException(r.error().get().message()); + } } + return original; + } - @Inject(at = @At("TAIL"), method = "apply") - private void commander$applyCommands(ServerPlayerEntity player, CallbackInfo ci) { - if (this.commands == null) return; - LootContextParameterSet parameterSet = new LootContextParameterSet.Builder(player.getServerWorld()).add(LootContextParameters.THIS_ENTITY, player).add(LootContextParameters.ORIGIN, player.getPos()).build(LootContextTypes.ADVANCEMENT_REWARD); - LootContext context = new LootContext.Builder(parameterSet).build(null); + @Inject(at = @At("TAIL"), method = "apply") + private void commander$applyCommands(ServerPlayerEntity player, CallbackInfo ci) { + if (this.commands == null) return; + LootContextParameterSet parameterSet = new LootContextParameterSet.Builder( + player.getServerWorld()) + .add(LootContextParameters.THIS_ENTITY, player) + .add(LootContextParameters.ORIGIN, player.getPos()) + .build(LootContextTypes.ADVANCEMENT_REWARD); + LootContext context = new LootContext.Builder(parameterSet).build(null); - EventContext context1 = EventContext.builder(EventType.NULL) - .addParameter(EventKey.LOOT_CONTEXT, context) - .build(); + EventContext context1 = EventContext.builder(EventType.NULL) + .addParameter(EventKey.LOOT_CONTEXT, context) + .build(); - for (Command.Conditioned command : this.commands) { - command.execute(context1); - } + for (Command.Conditioned command : this.commands) { + command.execute(context1); } + } } diff --git a/src/main/java/me/melontini/commander/impl/mixin/ExecuteCommandMixin.java b/src/main/java/me/melontini/commander/impl/mixin/ExecuteCommandMixin.java index 04d022b..6d2bd87 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/ExecuteCommandMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/ExecuteCommandMixin.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.tree.CommandNode; +import java.util.Optional; import me.melontini.commander.api.expression.Expression; import me.melontini.commander.impl.Commander; import net.minecraft.command.CommandRegistryAccess; @@ -20,27 +21,54 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.Optional; - @Mixin(ExecuteCommand.class) public abstract class ExecuteCommandMixin { - @Shadow private static ArgumentBuilder addConditionLogic(CommandNode root, ArgumentBuilder builder, boolean positive, ExecuteCommand.Condition condition) { - throw new AssertionError(); - } + @Shadow + private static ArgumentBuilder addConditionLogic( + CommandNode root, + ArgumentBuilder builder, + boolean positive, + ExecuteCommand.Condition condition) { + throw new AssertionError(); + } - @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/server/command/DataCommand;SOURCE_OBJECT_TYPES:Ljava/util/List;", shift = At.Shift.BEFORE), method = "addConditionArguments") - private static void commander$addExpressionCondition(CommandNode root, LiteralArgumentBuilder argumentBuilder, boolean positive, CommandRegistryAccess commandRegistryAccess, CallbackInfoReturnable> cir) { - argumentBuilder.then(CommandManager.literal("cmd:expression").then(addConditionLogic(root, CommandManager.argument("expression", StringArgumentType.string()), positive, context -> { - var r = Expression.parse(StringArgumentType.getString(context, "expression")); - if (r.error().isPresent()) throw Commander.EXPRESSION_EXCEPTION.create(r.error().get().message()); + @Inject( + at = + @At( + value = "FIELD", + target = + "Lnet/minecraft/server/command/DataCommand;SOURCE_OBJECT_TYPES:Ljava/util/List;", + shift = At.Shift.BEFORE), + method = "addConditionArguments") + private static void commander$addExpressionCondition( + CommandNode root, + LiteralArgumentBuilder argumentBuilder, + boolean positive, + CommandRegistryAccess commandRegistryAccess, + CallbackInfoReturnable> cir) { + argumentBuilder.then(CommandManager.literal("cmd:expression") + .then(addConditionLogic( + root, + CommandManager.argument("expression", StringArgumentType.string()), + positive, + context -> { + var r = Expression.parse(StringArgumentType.getString(context, "expression")); + if (r.error().isPresent()) + throw Commander.EXPRESSION_EXCEPTION.create(r.error().get().message()); - LootContext context1 = new LootContext.Builder(new LootContextParameterSet.Builder(context.getSource().getWorld()) - .add(LootContextParameters.ORIGIN, context.getSource().getPosition()) - .addOptional(LootContextParameters.THIS_ENTITY, context.getSource().getEntity()) - .build(LootContextTypes.COMMAND)).build(null); + LootContext context1 = new LootContext.Builder(new LootContextParameterSet.Builder( + context.getSource().getWorld()) + .add(LootContextParameters.ORIGIN, context.getSource().getPosition()) + .addOptional( + LootContextParameters.THIS_ENTITY, context.getSource().getEntity()) + .build(LootContextTypes.COMMAND)) + .build(null); - return r.result().flatMap(expression -> Optional.ofNullable(expression.eval(context1))).map(Expression.Result::getAsBoolean).orElse(false); - }))); - } + return r.result() + .flatMap(expression -> Optional.ofNullable(expression.eval(context1))) + .map(Expression.Result::getAsBoolean) + .orElse(false); + }))); + } } diff --git a/src/main/java/me/melontini/commander/impl/mixin/ScoreboardCommandMixin.java b/src/main/java/me/melontini/commander/impl/mixin/ScoreboardCommandMixin.java index 5e63bbb..281c855 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/ScoreboardCommandMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/ScoreboardCommandMixin.java @@ -3,6 +3,10 @@ package me.melontini.commander.impl.mixin; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Optional; import me.melontini.commander.api.expression.Expression; import me.melontini.commander.impl.Commander; import net.minecraft.command.argument.ScoreHolderArgumentType; @@ -20,46 +24,80 @@ import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Optional; - @Mixin(ScoreboardCommand.class) public class ScoreboardCommandMixin { - @ModifyExpressionValue(method = "register", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/command/CommandManager;literal(Ljava/lang/String;)Lcom/mojang/brigadier/builder/LiteralArgumentBuilder;", ordinal = 8)) - private static LiteralArgumentBuilder addCommanderOperator(LiteralArgumentBuilder original) { - return original.then(CommandManager.literal("cmd:operate") - .then(CommandManager.argument("targets", ScoreHolderArgumentType.scoreHolders()).suggests(ScoreHolderArgumentType.SUGGESTION_PROVIDER) - .then(CommandManager.argument("objective", ScoreboardObjectiveArgumentType.scoreboardObjective()) - .then(CommandManager.argument("expression", StringArgumentType.string()).executes(context -> { - var targets = new ArrayList<>(ScoreHolderArgumentType.getScoreboardScoreHolders(context, "targets")); - var objective = ScoreboardObjectiveArgumentType.getWritableObjective(context, "objective"); + @ModifyExpressionValue( + method = "register", + at = + @At( + value = "INVOKE", + target = + "Lnet/minecraft/server/command/CommandManager;literal(Ljava/lang/String;)Lcom/mojang/brigadier/builder/LiteralArgumentBuilder;", + ordinal = 8)) + private static LiteralArgumentBuilder addCommanderOperator( + LiteralArgumentBuilder original) { + return original.then(CommandManager.literal("cmd:operate") + .then(CommandManager.argument("targets", ScoreHolderArgumentType.scoreHolders()) + .suggests(ScoreHolderArgumentType.SUGGESTION_PROVIDER) + .then(CommandManager.argument( + "objective", ScoreboardObjectiveArgumentType.scoreboardObjective()) + .then(CommandManager.argument("expression", StringArgumentType.string()) + .executes(context -> { + var targets = new ArrayList<>( + ScoreHolderArgumentType.getScoreboardScoreHolders(context, "targets")); + var objective = ScoreboardObjectiveArgumentType.getWritableObjective( + context, "objective"); - var r = Expression.parse(StringArgumentType.getString(context, "expression")); - if (r.error().isPresent()) throw Commander.EXPRESSION_EXCEPTION.create(r.error().get().message()); - var expression = r.result().orElseThrow(); + var r = Expression.parse(StringArgumentType.getString(context, "expression")); + if (r.error().isPresent()) + throw Commander.EXPRESSION_EXCEPTION.create( + r.error().get().message()); + var expression = r.result().orElseThrow(); - Scoreboard scoreboard = context.getSource().getServer().getScoreboard(); + Scoreboard scoreboard = context.getSource().getServer().getScoreboard(); - LootContext context1 = new LootContext.Builder(new LootContextParameterSet.Builder(context.getSource().getWorld()) - .add(LootContextParameters.ORIGIN, context.getSource().getPosition()) - .build(LootContextTypes.COMMAND)).build(null); + LootContext context1 = new LootContext.Builder( + new LootContextParameterSet.Builder( + context.getSource().getWorld()) + .add( + LootContextParameters.ORIGIN, + context.getSource().getPosition()) + .build(LootContextTypes.COMMAND)) + .build(null); - for (String target : targets) { - ScoreboardPlayerScore score = scoreboard.getPlayerScore(target, objective); - Optional.ofNullable(expression.eval(context1, Collections.singletonMap("score", score.getScore())).getAsDecimal()) - .map(BigDecimal::intValue).ifPresent(score::setScore); - } + for (String target : targets) { + ScoreboardPlayerScore score = scoreboard.getPlayerScore(target, objective); + Optional.ofNullable(expression + .eval(context1, Collections.singletonMap("score", score.getScore())) + .getAsDecimal()) + .map(BigDecimal::intValue) + .ifPresent(score::setScore); + } - if (targets.size() == 1) { - context.getSource().sendFeedback(() -> Text.translatable("commands.scoreboard.players.set.success.single", objective.toHoverableText(), targets.get(0), expression.original()), true); - } else { - context.getSource().sendFeedback(() -> Text.translatable("commands.scoreboard.players.set.success.multiple", objective.toHoverableText(), targets.size(), expression.original()), true); - } + if (targets.size() == 1) { + context + .getSource() + .sendFeedback( + () -> Text.translatable( + "commands.scoreboard.players.set.success.single", + objective.toHoverableText(), + targets.get(0), + expression.original()), + true); + } else { + context + .getSource() + .sendFeedback( + () -> Text.translatable( + "commands.scoreboard.players.set.success.multiple", + objective.toHoverableText(), + targets.size(), + expression.original()), + true); + } - return targets.size(); - }))))); - } + return targets.size(); + }))))); + } } diff --git a/src/main/java/me/melontini/commander/impl/mixin/evalex/EvaluationValueMixin.java b/src/main/java/me/melontini/commander/impl/mixin/evalex/EvaluationValueMixin.java index cfb77e8..05cbc7a 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/evalex/EvaluationValueMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/evalex/EvaluationValueMixin.java @@ -1,60 +1,72 @@ package me.melontini.commander.impl.mixin.evalex; import com.ezylang.evalex.data.EvaluationValue; -import me.melontini.commander.api.expression.Expression; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - import java.math.BigDecimal; import java.time.Duration; import java.time.Instant; +import me.melontini.commander.api.expression.Expression; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; @Mixin(value = EvaluationValue.class, remap = false) public abstract class EvaluationValueMixin implements Expression.Result { - @Shadow public abstract BigDecimal getNumberValue(); - @Shadow public abstract Boolean getBooleanValue(); - @Shadow public abstract String getStringValue(); - @Shadow public abstract Instant getDateTimeValue(); - @Shadow public abstract Duration getDurationValue(); - @Shadow public abstract boolean isNumberValue(); - @Shadow public abstract boolean isDateTimeValue(); - - @Shadow - public abstract Object getValue(); - - @Override - public BigDecimal getAsDecimal() { - return getNumberValue(); - } - - @Override - public boolean getAsBoolean() { - return getBooleanValue(); - } - - @Override - public String getAsString() { - return getStringValue(); - } - - @Override - public Instant getAsInstant() { - return getDateTimeValue(); - } - - @Override - public Duration getAsDuration() { - return getDurationValue(); - } - - @Override - public boolean isDecimalValue() { - return isNumberValue(); - } - - @Override - public boolean isInstantValue() { - return isDateTimeValue(); - } + @Shadow + public abstract BigDecimal getNumberValue(); + + @Shadow + public abstract Boolean getBooleanValue(); + + @Shadow + public abstract String getStringValue(); + + @Shadow + public abstract Instant getDateTimeValue(); + + @Shadow + public abstract Duration getDurationValue(); + + @Shadow + public abstract boolean isNumberValue(); + + @Shadow + public abstract boolean isDateTimeValue(); + + @Shadow + public abstract Object getValue(); + + @Override + public BigDecimal getAsDecimal() { + return getNumberValue(); + } + + @Override + public boolean getAsBoolean() { + return getBooleanValue(); + } + + @Override + public String getAsString() { + return getStringValue(); + } + + @Override + public Instant getAsInstant() { + return getDateTimeValue(); + } + + @Override + public Duration getAsDuration() { + return getDurationValue(); + } + + @Override + public boolean isDecimalValue() { + return isNumberValue(); + } + + @Override + public boolean isInstantValue() { + return isDateTimeValue(); + } } diff --git a/src/main/java/me/melontini/commander/impl/mixin/evalex/ExpressionMixin.java b/src/main/java/me/melontini/commander/impl/mixin/evalex/ExpressionMixin.java index ef550fe..d93878f 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/evalex/ExpressionMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/evalex/ExpressionMixin.java @@ -1,25 +1,25 @@ package me.melontini.commander.impl.mixin.evalex; import com.ezylang.evalex.Expression; +import java.util.Map; import me.melontini.commander.impl.expression.EvalUtils; import net.minecraft.loot.context.LootContext; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import java.util.Map; - @Mixin(value = Expression.class, remap = false) public abstract class ExpressionMixin implements me.melontini.commander.api.expression.Expression { - @Shadow public abstract String getExpressionString(); + @Shadow + public abstract String getExpressionString(); - @Override - public Result eval(LootContext context, Map parameters) { - return (Result) (Object) EvalUtils.evaluate(context, (Expression) (Object) this, parameters); - } + @Override + public Result eval(LootContext context, Map parameters) { + return (Result) (Object) EvalUtils.evaluate(context, (Expression) (Object) this, parameters); + } - @Override - public String original() { - return getExpressionString(); - } + @Override + public String original() { + return getExpressionString(); + } } diff --git a/src/main/java/me/melontini/commander/impl/util/Identity.java b/src/main/java/me/melontini/commander/impl/util/Identity.java index a949bc4..399e3a2 100644 --- a/src/main/java/me/melontini/commander/impl/util/Identity.java +++ b/src/main/java/me/melontini/commander/impl/util/Identity.java @@ -2,14 +2,14 @@ package me.melontini.commander.impl.util; public record Identity(V value) { - @Override - public boolean equals(Object object) { - if (!(object instanceof Identity identity)) return false; - return value == identity.value; - } + @Override + public boolean equals(Object object) { + if (!(object instanceof Identity identity)) return false; + return value == identity.value; + } - @Override - public int hashCode() { - return System.identityHashCode(value); - } + @Override + public int hashCode() { + return System.identityHashCode(value); + } } diff --git a/src/main/java/me/melontini/commander/impl/util/MagicCodecs.java b/src/main/java/me/melontini/commander/impl/util/MagicCodecs.java index 27f0ae4..76d8456 100644 --- a/src/main/java/me/melontini/commander/impl/util/MagicCodecs.java +++ b/src/main/java/me/melontini/commander/impl/util/MagicCodecs.java @@ -2,6 +2,7 @@ package me.melontini.commander.impl.util; import com.google.gson.*; import com.mojang.serialization.Codec; +import java.lang.reflect.Type; import lombok.experimental.UtilityClass; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.loot.LootGsons; @@ -9,36 +10,41 @@ import net.minecraft.loot.condition.LootCondition; import net.minecraft.registry.Registries; import net.minecraft.util.JsonSerializableType; -import java.lang.reflect.Type; - @UtilityClass public class MagicCodecs { - public static final GsonContextImpl lootContext = new GsonContextImpl(LootGsons.getConditionGsonBuilder().create()); + public static final GsonContextImpl lootContext = + new GsonContextImpl(LootGsons.getConditionGsonBuilder().create()); - public static final Codec LOOT_CONDITION = ExtraCodecs.jsonSerializerDispatch("condition", Registries.LOOT_CONDITION_TYPE.getCodec(), LootCondition::getType, JsonSerializableType::getJsonSerializer, lootContext); + public static final Codec LOOT_CONDITION = ExtraCodecs.jsonSerializerDispatch( + "condition", + Registries.LOOT_CONDITION_TYPE.getCodec(), + LootCondition::getType, + JsonSerializableType::getJsonSerializer, + lootContext); - public static final class GsonContextImpl implements JsonSerializationContext, JsonDeserializationContext { + public static final class GsonContextImpl + implements JsonSerializationContext, JsonDeserializationContext { - private final Gson gson; + private final Gson gson; - public GsonContextImpl(Gson gson) { - this.gson = gson; - } + public GsonContextImpl(Gson gson) { + this.gson = gson; + } - @Override - public JsonElement serialize(Object src) { - return gson.toJsonTree(src); - } + @Override + public JsonElement serialize(Object src) { + return gson.toJsonTree(src); + } - @Override - public JsonElement serialize(Object src, Type typeOfSrc) { - return gson.toJsonTree(src, typeOfSrc); - } + @Override + public JsonElement serialize(Object src, Type typeOfSrc) { + return gson.toJsonTree(src, typeOfSrc); + } - @Override - public R deserialize(JsonElement json, Type typeOfT) throws JsonParseException { - return gson.fromJson(json, typeOfT); - } + @Override + public R deserialize(JsonElement json, Type typeOfT) throws JsonParseException { + return gson.fromJson(json, typeOfT); } + } } diff --git a/src/main/java/me/melontini/commander/impl/util/NbtCodecs.java b/src/main/java/me/melontini/commander/impl/util/NbtCodecs.java index 4fd580f..0bd4f40 100644 --- a/src/main/java/me/melontini/commander/impl/util/NbtCodecs.java +++ b/src/main/java/me/melontini/commander/impl/util/NbtCodecs.java @@ -3,21 +3,28 @@ package me.melontini.commander.impl.util; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; -import net.minecraft.nbt.*; - import java.util.function.Function; +import net.minecraft.nbt.*; public class NbtCodecs { - public static final Codec ELEMENT_CODEC = Codec.PASSTHROUGH.xmap((dynamic) -> dynamic.convert(NbtOps.INSTANCE).getValue(), (element) -> new Dynamic<>(NbtOps.INSTANCE, element)); + public static final Codec ELEMENT_CODEC = Codec.PASSTHROUGH.xmap( + (dynamic) -> dynamic.convert(NbtOps.INSTANCE).getValue(), + (element) -> new Dynamic<>(NbtOps.INSTANCE, element)); - public static final Codec PRIMITIVE_CODEC = ELEMENT_CODEC.comapFlatMap(element -> { - if (element instanceof AbstractNbtNumber || element instanceof NbtString) return DataResult.success(element); + public static final Codec PRIMITIVE_CODEC = ELEMENT_CODEC.comapFlatMap( + element -> { + if (element instanceof AbstractNbtNumber || element instanceof NbtString) + return DataResult.success(element); return DataResult.error(() -> "Not an nbt primitive %s!".formatted(element)); - }, Function.identity()); + }, + Function.identity()); - public static final Codec COMPOUND_CODEC = ELEMENT_CODEC.comapFlatMap(element -> { - if (!(element instanceof NbtCompound compound)) return DataResult.error(() -> "Not an NbtCompound %s!".formatted(element)); + public static final Codec COMPOUND_CODEC = ELEMENT_CODEC.comapFlatMap( + element -> { + if (!(element instanceof NbtCompound compound)) + return DataResult.error(() -> "Not an NbtCompound %s!".formatted(element)); return DataResult.success(compound); - }, Function.identity()); + }, + Function.identity()); } diff --git a/src/main/java/me/melontini/commander/impl/util/ServerHelper.java b/src/main/java/me/melontini/commander/impl/util/ServerHelper.java index 2d5b8dc..a1a3166 100644 --- a/src/main/java/me/melontini/commander/impl/util/ServerHelper.java +++ b/src/main/java/me/melontini/commander/impl/util/ServerHelper.java @@ -7,12 +7,17 @@ import net.minecraft.text.Text; @UtilityClass public class ServerHelper { - public static void broadcastToOps(MinecraftServer server, Text text) { - server.getPlayerManager().broadcast(text, player -> { - if (server.getPlayerManager().isOperator(player.getGameProfile())) { + public static void broadcastToOps(MinecraftServer server, Text text) { + server + .getPlayerManager() + .broadcast( + text, + player -> { + if (server.getPlayerManager().isOperator(player.getGameProfile())) { return text; - } - return null; - }, false); - } + } + return null; + }, + false); + } } diff --git a/src/main/java/me/melontini/commander/impl/util/ThrowingOptional.java b/src/main/java/me/melontini/commander/impl/util/ThrowingOptional.java index 6d6eadf..14ce7de 100644 --- a/src/main/java/me/melontini/commander/impl/util/ThrowingOptional.java +++ b/src/main/java/me/melontini/commander/impl/util/ThrowingOptional.java @@ -1,5 +1,9 @@ package me.melontini.commander.impl.util; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.Stream; import lombok.EqualsAndHashCode; import me.melontini.dark_matter.api.base.util.functions.ThrowingConsumer; import me.melontini.dark_matter.api.base.util.functions.ThrowingFunction; @@ -7,138 +11,136 @@ import me.melontini.dark_matter.api.base.util.functions.ThrowingRunnable; import me.melontini.dark_matter.api.base.util.functions.ThrowingSupplier; import org.jetbrains.annotations.NotNull; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.Stream; - @EqualsAndHashCode public class ThrowingOptional { - private static final ThrowingOptional EMPTY = new ThrowingOptional<>(null); - - private final T value; - - public static ThrowingOptional empty() { - return (ThrowingOptional) EMPTY; - } - - public static ThrowingOptional of(T value) { - return new ThrowingOptional<>(Objects.requireNonNull(value)); - } - - public static ThrowingOptional ofNullable(T value) { - return value == null ? empty() : new ThrowingOptional<>(value); - } - - private ThrowingOptional(T value) { - this.value = value; - } - - public T get() { - if (value == null) { - throw new NoSuchElementException("No value present"); - } - return value; - } - - public boolean isPresent() { - return value != null; - } - - public boolean isEmpty() { - return value == null; - } + private static final ThrowingOptional EMPTY = new ThrowingOptional<>(null); - public void ifPresent(ThrowingConsumer action) throws E { - if (value != null) { - action.accept(value); - } - } - - public void ifPresentOrElse(ThrowingConsumer action, ThrowingRunnable emptyAction) throws E { - if (value != null) { - action.accept(value); - } else { - emptyAction.run(); - } - } - - public ThrowingOptional filter(ThrowingFunction predicate) throws E { - Objects.requireNonNull(predicate); - if (isEmpty()) { - return this; - } else { - return predicate.apply(value) ? this : empty(); - } - } - - public ThrowingOptional map(ThrowingFunction mapper) throws E { - Objects.requireNonNull(mapper); - if (isEmpty()) { - return empty(); - } else { - return ofNullable(mapper.apply(value)); - } - } - - public ThrowingOptional flatMap(ThrowingFunction, E> mapper) throws E { - Objects.requireNonNull(mapper); - if (isEmpty()) { - return empty(); - } else { - @SuppressWarnings("unchecked") - ThrowingOptional r = (ThrowingOptional) mapper.apply(value); - return Objects.requireNonNull(r); - } - } - - public ThrowingOptional or(ThrowingSupplier, E> supplier) throws E { - Objects.requireNonNull(supplier); - if (isPresent()) { - return this; - } else { - @SuppressWarnings("unchecked") - ThrowingOptional r = (ThrowingOptional) supplier.get(); - return Objects.requireNonNull(r); - } - } - - public Stream stream() { - if (isEmpty()) { - return Stream.empty(); - } else { - return Stream.of(value); - } - } - - public T orElse(T other) { - return value != null ? value : other; - } - - public T orElseGet(ThrowingSupplier supplier) throws E { - return value != null ? value : supplier.get(); - } - - public T orElseThrow() { - if (value == null) { - throw new NoSuchElementException("No value present"); - } - return value; - } - - public T orElseThrow(Supplier exceptionSupplier) throws X { - if (value != null) { - return value; - } else { - throw exceptionSupplier.get(); - } - } - - @Override - public String toString() { - return value != null - ? ("ThrowingOptional[" + value + "]") - : "ThrowingOptional.empty"; - } + private final T value; + + public static ThrowingOptional empty() { + return (ThrowingOptional) EMPTY; + } + + public static ThrowingOptional of(T value) { + return new ThrowingOptional<>(Objects.requireNonNull(value)); + } + + public static ThrowingOptional ofNullable(T value) { + return value == null ? empty() : new ThrowingOptional<>(value); + } + + private ThrowingOptional(T value) { + this.value = value; + } + + public T get() { + if (value == null) { + throw new NoSuchElementException("No value present"); + } + return value; + } + + public boolean isPresent() { + return value != null; + } + + public boolean isEmpty() { + return value == null; + } + + public void ifPresent(ThrowingConsumer action) throws E { + if (value != null) { + action.accept(value); + } + } + + public void ifPresentOrElse( + ThrowingConsumer action, ThrowingRunnable emptyAction) throws E { + if (value != null) { + action.accept(value); + } else { + emptyAction.run(); + } + } + + public ThrowingOptional filter( + ThrowingFunction predicate) throws E { + Objects.requireNonNull(predicate); + if (isEmpty()) { + return this; + } else { + return predicate.apply(value) ? this : empty(); + } + } + + public ThrowingOptional map( + ThrowingFunction mapper) throws E { + Objects.requireNonNull(mapper); + if (isEmpty()) { + return empty(); + } else { + return ofNullable(mapper.apply(value)); + } + } + + public ThrowingOptional flatMap( + ThrowingFunction, E> mapper) throws E { + Objects.requireNonNull(mapper); + if (isEmpty()) { + return empty(); + } else { + @SuppressWarnings("unchecked") + ThrowingOptional r = (ThrowingOptional) mapper.apply(value); + return Objects.requireNonNull(r); + } + } + + public ThrowingOptional or( + ThrowingSupplier, E> supplier) throws E { + Objects.requireNonNull(supplier); + if (isPresent()) { + return this; + } else { + @SuppressWarnings("unchecked") + ThrowingOptional r = (ThrowingOptional) supplier.get(); + return Objects.requireNonNull(r); + } + } + + public Stream stream() { + if (isEmpty()) { + return Stream.empty(); + } else { + return Stream.of(value); + } + } + + public T orElse(T other) { + return value != null ? value : other; + } + + public T orElseGet(ThrowingSupplier supplier) throws E { + return value != null ? value : supplier.get(); + } + + public T orElseThrow() { + if (value == null) { + throw new NoSuchElementException("No value present"); + } + return value; + } + + public T orElseThrow(Supplier exceptionSupplier) throws X { + if (value != null) { + return value; + } else { + throw exceptionSupplier.get(); + } + } + + @Override + public String toString() { + return value != null ? ("ThrowingOptional[" + value + "]") : "ThrowingOptional.empty"; + } } diff --git a/src/main/java/me/melontini/commander/impl/util/loot/ArithmeticaLootNumberProvider.java b/src/main/java/me/melontini/commander/impl/util/loot/ArithmeticaLootNumberProvider.java index 9704ba9..e7f18b4 100644 --- a/src/main/java/me/melontini/commander/impl/util/loot/ArithmeticaLootNumberProvider.java +++ b/src/main/java/me/melontini/commander/impl/util/loot/ArithmeticaLootNumberProvider.java @@ -8,19 +8,21 @@ import net.minecraft.loot.provider.number.LootNumberProvider; import net.minecraft.loot.provider.number.LootNumberProviderType; public record ArithmeticaLootNumberProvider(Arithmetica value) implements LootNumberProvider { - public static final MapCodec CODEC = Arithmetica.CODEC.xmap(ArithmeticaLootNumberProvider::new, ArithmeticaLootNumberProvider::value).fieldOf("value"); + public static final MapCodec CODEC = Arithmetica.CODEC + .xmap(ArithmeticaLootNumberProvider::new, ArithmeticaLootNumberProvider::value) + .fieldOf("value"); - @Override - public LootNumberProviderType getType() { - return Commander.ARITHMETICA_PROVIDER; - } + @Override + public LootNumberProviderType getType() { + return Commander.ARITHMETICA_PROVIDER; + } - @Override - public float nextFloat(LootContext context) { - return this.value.asFloat(context); - } + @Override + public float nextFloat(LootContext context) { + return this.value.asFloat(context); + } - public static ArithmeticaLootNumberProvider create(Arithmetica value) { - return new ArithmeticaLootNumberProvider(value); - } + public static ArithmeticaLootNumberProvider create(Arithmetica value) { + return new ArithmeticaLootNumberProvider(value); + } } diff --git a/src/main/java/me/melontini/commander/impl/util/loot/ExpressionLootCondition.java b/src/main/java/me/melontini/commander/impl/util/loot/ExpressionLootCondition.java index 62b9931..a61640d 100644 --- a/src/main/java/me/melontini/commander/impl/util/loot/ExpressionLootCondition.java +++ b/src/main/java/me/melontini/commander/impl/util/loot/ExpressionLootCondition.java @@ -8,15 +8,17 @@ import net.minecraft.loot.condition.LootConditionType; import net.minecraft.loot.context.LootContext; public record ExpressionLootCondition(Expression expression) implements LootCondition { - public static final MapCodec CODEC = Expression.CODEC.xmap(ExpressionLootCondition::new, ExpressionLootCondition::expression).fieldOf("value"); + public static final MapCodec CODEC = Expression.CODEC + .xmap(ExpressionLootCondition::new, ExpressionLootCondition::expression) + .fieldOf("value"); - @Override - public LootConditionType getType() { - return Commander.EXPRESSION_CONDITION; - } + @Override + public LootConditionType getType() { + return Commander.EXPRESSION_CONDITION; + } - @Override - public boolean test(LootContext context) { - return expression().eval(context).getAsBoolean(); - } + @Override + public boolean test(LootContext context) { + return expression().eval(context).getAsBoolean(); + } } diff --git a/src/main/java/me/melontini/commander/impl/util/mappings/AmbiguousRemapper.java b/src/main/java/me/melontini/commander/impl/util/mappings/AmbiguousRemapper.java index f599eaa..7a17148 100644 --- a/src/main/java/me/melontini/commander/impl/util/mappings/AmbiguousRemapper.java +++ b/src/main/java/me/melontini/commander/impl/util/mappings/AmbiguousRemapper.java @@ -3,5 +3,5 @@ package me.melontini.commander.impl.util.mappings; import org.jetbrains.annotations.Nullable; public interface AmbiguousRemapper { - @Nullable String getFieldOrMethod(Class cls, String name); + @Nullable String getFieldOrMethod(Class cls, String name); } diff --git a/src/main/java/me/melontini/commander/impl/util/mappings/MappingKeeper.java b/src/main/java/me/melontini/commander/impl/util/mappings/MappingKeeper.java index daff9ab..dfe1366 100644 --- a/src/main/java/me/melontini/commander/impl/util/mappings/MappingKeeper.java +++ b/src/main/java/me/melontini/commander/impl/util/mappings/MappingKeeper.java @@ -1,5 +1,11 @@ package me.melontini.commander.impl.util.mappings; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; +import java.util.Objects; +import java.util.zip.InflaterInputStream; import lombok.Cleanup; import lombok.SneakyThrows; import lombok.extern.log4j.Log4j2; @@ -12,68 +18,77 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Type; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.List; -import java.util.Objects; -import java.util.zip.InflaterInputStream; - @Log4j2 public record MappingKeeper(MemoryMappingTree mojmapTarget) implements AmbiguousRemapper { - public static final String NAMESPACE = FabricLoader.getInstance().getMappingResolver().getCurrentRuntimeNamespace(); + public static final String NAMESPACE = + FabricLoader.getInstance().getMappingResolver().getCurrentRuntimeNamespace(); - @SneakyThrows - public static MemoryMappingTree loadMojmapTarget(MemoryMappingTree offMojmap, MemoryMappingTree offTarget) { - log.info("Merging mappings..."); + @SneakyThrows + public static MemoryMappingTree loadMojmapTarget( + MemoryMappingTree offMojmap, MemoryMappingTree offTarget) { + log.info("Merging mappings..."); - var tree = new MemoryMappingTree(); - MemoryMappingTree temp = new MemoryMappingTree(); - offMojmap.accept(temp); - offTarget.accept(temp); - temp.accept(new MappingSourceNsSwitch(tree, "mojang", true)); - Objects.requireNonNull(tree.getClass("net/minecraft/server/MinecraftServer"), "No built-in MinecraftServer mapping?").setDstName("net/minecraft/server/MinecraftServer", tree.getNamespaceId(NAMESPACE)); - return tree; - } + var tree = new MemoryMappingTree(); + MemoryMappingTree temp = new MemoryMappingTree(); + offMojmap.accept(temp); + offTarget.accept(temp); + temp.accept(new MappingSourceNsSwitch(tree, "mojang", true)); + Objects.requireNonNull( + tree.getClass("net/minecraft/server/MinecraftServer"), + "No built-in MinecraftServer mapping?") + .setDstName("net/minecraft/server/MinecraftServer", tree.getNamespaceId(NAMESPACE)); + return tree; + } - @SneakyThrows - @Nullable public static MemoryMappingTree loadOffMojmap() { - log.info("Loading official->mojmap mappings..."); + @SneakyThrows + @Nullable public static MemoryMappingTree loadOffMojmap() { + log.info("Loading official->mojmap mappings..."); - var tree = new MemoryMappingTree(); - @Cleanup var reader = new InputStreamReader(new InflaterInputStream(Files.newInputStream(Commander.COMMANDER_PATH.resolve("mappings/server_mappings.bin"))), StandardCharsets.UTF_8); - MappingReader.read(reader, new MappingSourceNsSwitch(tree, "target")); - tree.setSrcNamespace("official"); - tree.setDstNamespaces(List.of("mojang")); - return tree; - } + var tree = new MemoryMappingTree(); + @Cleanup + var reader = new InputStreamReader( + new InflaterInputStream( + Files.newInputStream(Commander.COMMANDER_PATH.resolve("mappings/server_mappings.bin"))), + StandardCharsets.UTF_8); + MappingReader.read(reader, new MappingSourceNsSwitch(tree, "target")); + tree.setSrcNamespace("official"); + tree.setDstNamespaces(List.of("mojang")); + return tree; + } - @SneakyThrows - public static MemoryMappingTree loadOffTarget() { - log.info("Loading official->{} mappings...", NAMESPACE); + @SneakyThrows + public static MemoryMappingTree loadOffTarget() { + log.info("Loading official->{} mappings...", NAMESPACE); - var tree = new MemoryMappingTree(); - @Cleanup var reader = new InputStreamReader(Objects.requireNonNull(MappingKeeper.class.getClassLoader().getResourceAsStream("mappings/mappings.tiny"), "mappings/mappings.tiny is not available?"), StandardCharsets.UTF_8); - MappingReader.read(reader, tree); - return tree; - } + var tree = new MemoryMappingTree(); + @Cleanup + var reader = new InputStreamReader( + Objects.requireNonNull( + MappingKeeper.class.getClassLoader().getResourceAsStream("mappings/mappings.tiny"), + "mappings/mappings.tiny is not available?"), + StandardCharsets.UTF_8); + MappingReader.read(reader, tree); + return tree; + } - @Override - public @Nullable String getFieldOrMethod(Class cls, String name) { - var clsData = mojmapTarget.getClass(Type.getInternalName(cls), mojmapTarget.getNamespaceId(NAMESPACE)); - if (clsData == null) return null; + @Override + public @Nullable String getFieldOrMethod(Class cls, String name) { + var clsData = + mojmapTarget.getClass(Type.getInternalName(cls), mojmapTarget.getNamespaceId(NAMESPACE)); + if (clsData == null) return null; - for (MappingTree.MethodMapping method : clsData.getMethods()) { - if (Objects.equals(method.getSrcName(), name)) { - var srcDesc = method.getSrcDesc(); - if (srcDesc != null && srcDesc.startsWith("()") && !srcDesc.endsWith("V")) return method.getName(NAMESPACE); - } - } + for (MappingTree.MethodMapping method : clsData.getMethods()) { + if (Objects.equals(method.getSrcName(), name)) { + var srcDesc = method.getSrcDesc(); + if (srcDesc != null && srcDesc.startsWith("()") && !srcDesc.endsWith("V")) + return method.getName(NAMESPACE); + } + } - for (MappingTree.FieldMapping field : clsData.getFields()) { - if (Objects.equals(field.getSrcName(), name)) return field.getName(NAMESPACE); - } - return null; + for (MappingTree.FieldMapping field : clsData.getFields()) { + if (Objects.equals(field.getSrcName(), name)) return field.getName(NAMESPACE); } + return null; + } } diff --git a/src/main/java/me/melontini/commander/impl/util/mappings/MinecraftDownloader.java b/src/main/java/me/melontini/commander/impl/util/mappings/MinecraftDownloader.java index a7304a6..4625021 100644 --- a/src/main/java/me/melontini/commander/impl/util/mappings/MinecraftDownloader.java +++ b/src/main/java/me/melontini/commander/impl/util/mappings/MinecraftDownloader.java @@ -3,6 +3,14 @@ package me.melontini.commander.impl.util.mappings; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.zip.DeflaterOutputStream; import lombok.Cleanup; import lombok.SneakyThrows; import lombok.experimental.UtilityClass; @@ -13,37 +21,35 @@ import net.fabricmc.mappingio.MappingWriter; import net.fabricmc.mappingio.format.MappingFormat; import net.fabricmc.mappingio.tree.MemoryMappingTree; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; -import java.util.zip.DeflaterOutputStream; - @Log4j2 @UtilityClass public class MinecraftDownloader { - private static final URL MANIFEST = url("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"); + private static final URL MANIFEST = + url("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"); - @SneakyThrows - static URL url(String s) { - return new URL(s); - } + @SneakyThrows + static URL url(String s) { + return new URL(s); + } - @SneakyThrows - public static void downloadMappings() { - Path mappings = Commander.COMMANDER_PATH.resolve("mappings/server_mappings.bin"); - if (Files.exists(mappings)) return; - var url = url(getManifest().getAsJsonObject("downloads").getAsJsonObject("server_mappings").get("url").getAsString()); + @SneakyThrows + public static void downloadMappings() { + Path mappings = Commander.COMMANDER_PATH.resolve("mappings/server_mappings.bin"); + if (Files.exists(mappings)) return; + var url = url(getManifest() + .getAsJsonObject("downloads") + .getAsJsonObject("server_mappings") + .get("url") + .getAsString()); - var parent = Objects.requireNonNull(mappings.getParent()); - Files.createDirectories(parent); + var parent = Objects.requireNonNull(mappings.getParent()); + Files.createDirectories(parent); - log.info("Downloading {}...", Objects.requireNonNull(mappings.getFileName()).toString()); - Files.writeString(parent.resolve("LICENSE.txt"), """ + log.info("Downloading {}...", Objects.requireNonNull(mappings.getFileName()).toString()); + Files.writeString( + parent.resolve("LICENSE.txt"), + """ (c) 2020 Microsoft Corporation. These mappings are provided "as-is" and you bear the risk of using them. You may copy and use the mappings for development purposes, but you may not redistribute the mappings complete and unmodified. @@ -51,29 +57,32 @@ public class MinecraftDownloader { Use and modification of this document or the source code (in any form) of Minecraft: Java Edition is governed by the Minecraft End User License Agreement available at https://account.mojang.com/documents/minecraft_eula. """); - @Cleanup var reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8); - @Cleanup var outputStream = Files.newOutputStream(mappings); + @Cleanup var reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8); + @Cleanup var outputStream = Files.newOutputStream(mappings); - MemoryMappingTree tree = new MemoryMappingTree(); - MappingReader.read(reader, tree); + MemoryMappingTree tree = new MemoryMappingTree(); + MappingReader.read(reader, tree); - @Cleanup var output = new OutputStreamWriter(new DeflaterOutputStream(outputStream), StandardCharsets.UTF_8); - tree.accept(MappingWriter.create(output, MappingFormat.TSRG_2_FILE)); - } + @Cleanup + var output = + new OutputStreamWriter(new DeflaterOutputStream(outputStream), StandardCharsets.UTF_8); + tree.accept(MappingWriter.create(output, MappingFormat.TSRG_2_FILE)); + } - public static JsonObject getManifest() { - var o = downloadObject(MANIFEST); - for (JsonElement versions : o.getAsJsonArray("versions")) { - if (Commander.MINECRAFT_VERSION.equals(versions.getAsJsonObject().get("id").getAsString())) { - return downloadObject(url(versions.getAsJsonObject().get("url").getAsString())); - } - } - throw new IllegalStateException("Unknown version '%s'".formatted(Commander.MINECRAFT_VERSION)); + public static JsonObject getManifest() { + var o = downloadObject(MANIFEST); + for (JsonElement versions : o.getAsJsonArray("versions")) { + if (Commander.MINECRAFT_VERSION.equals( + versions.getAsJsonObject().get("id").getAsString())) { + return downloadObject(url(versions.getAsJsonObject().get("url").getAsString())); + } } + throw new IllegalStateException("Unknown version '%s'".formatted(Commander.MINECRAFT_VERSION)); + } - @SneakyThrows - private static JsonObject downloadObject(URL url) { - @Cleanup var reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8); - return JsonParser.parseReader(reader).getAsJsonObject(); - } + @SneakyThrows + private static JsonObject downloadObject(URL url) { + @Cleanup var reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8); + return JsonParser.parseReader(reader).getAsJsonObject(); + } }