diff --git a/gradle/mappings.gradle b/gradle/mappings.gradle index 57d1c3f..20d4626 100644 --- a/gradle/mappings.gradle +++ b/gradle/mappings.gradle @@ -23,6 +23,7 @@ import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch import net.fabricmc.mappingio.format.MappingFormat import net.fabricmc.mappingio.tree.MemoryMappingTree +import java.nio.charset.StandardCharsets import java.nio.file.Files import java.util.zip.DeflaterOutputStream @@ -35,12 +36,12 @@ tasks.register("downloadCommanderMappings") { Files.createDirectories(processed.toPath().getParent()) MemoryMappingTree tree = new MemoryMappingTree() - MappingReader.read(new InputStreamReader(new URL(getManifest().getAsJsonObject("downloads").getAsJsonObject("server_mappings").get("url").getAsString()).openStream()), new MappingSourceNsSwitch(tree, "target", true)) + MappingReader.read(new InputStreamReader(new URL(getManifest().getAsJsonObject("downloads").getAsJsonObject("server_mappings").get("url").getAsString()).openStream(), StandardCharsets.UTF_8), new MappingSourceNsSwitch(tree, "target", true)) tree.setSrcNamespace("official") tree.setDstNamespaces(List.of("mojang")) OutputStream stream = Files.newOutputStream(processed.toPath()) - tree.accept(MappingWriter.create(new OutputStreamWriter(new DeflaterOutputStream(stream)), MappingFormat.TINY_FILE)) + tree.accept(MappingWriter.create(new OutputStreamWriter(new DeflaterOutputStream(stream), StandardCharsets.UTF_8), MappingFormat.TINY_FILE)) } } @@ -62,5 +63,5 @@ JsonObject getManifest() { } static JsonObject downloadObject(URL url) { - return JsonParser.parseReader(new InputStreamReader(url.openStream())).getAsJsonObject() + return JsonParser.parseReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)).getAsJsonObject() } \ No newline at end of file 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 13f1055..34e0593 100644 --- a/src/main/java/me/melontini/commander/api/command/Selector.java +++ b/src/main/java/me/melontini/commander/api/command/Selector.java @@ -25,7 +25,7 @@ public interface Selector extends Function { } @Override - default ServerCommandSource apply(LootContext context) { + default @Nullable ServerCommandSource apply(LootContext context) { return this.select(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 fd41732..04232a6 100644 --- a/src/main/java/me/melontini/commander/api/event/EventContext.java +++ b/src/main/java/me/melontini/commander/api/event/EventContext.java @@ -5,7 +5,7 @@ import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import java.util.Map; +import java.util.IdentityHashMap; public interface EventContext { @@ -14,13 +14,15 @@ public interface EventContext { return new EventContextImpl.Builder(type); } + EventType type(); + @NotNull T getParameter(EventKey key); @NotNull LootContext lootContext(); void setReturnValue(Object value); T getReturnValue(T def); - EventContext with(Map, Object> parameters); + EventContext with(IdentityHashMap, Object> parameters); interface Builder { Builder addParameter(EventKey key, T value); 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 ba8ada5..6bd083f 100644 --- a/src/main/java/me/melontini/commander/api/event/EventType.java +++ b/src/main/java/me/melontini/commander/api/event/EventType.java @@ -4,6 +4,7 @@ import com.mojang.serialization.Codec; 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; @@ -32,7 +33,7 @@ public interface EventType extends Context { } interface Builder { - Builder extension(Codec extension, Function>, C> finalizer); + Builder extension(@Nullable Codec extension, Function>, C> finalizer); Builder cancelTerm(Codec returnCodec); 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 7a6c117..3b37d3d 100644 --- a/src/main/java/me/melontini/commander/api/event/Subscription.java +++ b/src/main/java/me/melontini/commander/api/event/Subscription.java @@ -3,12 +3,13 @@ package me.melontini.commander.api.event; 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 T getData(MinecraftServer server, EventType type) { + static @Nullable T getData(MinecraftServer server, EventType type) { return DynamicEventManager.getData(server, type); } 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 83c08cd..35315a5 100644 --- a/src/main/java/me/melontini/commander/api/util/EventExecutors.java +++ b/src/main/java/me/melontini/commander/api/util/EventExecutors.java @@ -6,21 +6,23 @@ import me.melontini.commander.api.event.EventContext; import me.melontini.commander.api.event.EventKey; import me.melontini.commander.api.event.EventType; import me.melontini.commander.api.event.Subscription; +import me.melontini.commander.impl.event.data.types.EventTypes; import me.melontini.dark_matter.api.base.util.MakeSure; import net.minecraft.loot.context.LootContext; import net.minecraft.util.ActionResult; import net.minecraft.world.World; -import org.jetbrains.annotations.NotNull; +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, @NotNull World world, Supplier supplier) { + public static void runVoid(EventType type, World world, Supplier supplier) { if (world.isClient()) return; - List subscribers = Subscription.getData(MakeSure.notNull(world.getServer()), type); + 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) @@ -29,10 +31,10 @@ public class EventExecutors { for (Command.Conditioned subscriber : subscribers) subscriber.execute(context); } - public static boolean runBoolean(EventType type, boolean def, @NotNull World world, Supplier supplier) { + public static boolean runBoolean(EventType type, boolean def, World world, Supplier supplier) { if (world.isClient()) return def; - List subscribers = Subscription.getData(MakeSure.notNull(world.getServer()), type); + 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) @@ -40,7 +42,7 @@ public class EventExecutors { .build(); for (Command.Conditioned subscriber : subscribers) { subscriber.execute(context); - boolean val = context.getReturnValue(def); + boolean val = Boolean.TRUE.equals(context.getReturnValue(def)); if (val != def) return val; } return def; @@ -50,10 +52,10 @@ public class EventExecutors { return runBoolean(type, true, world, supplier); } - public static > T runEnum(EventType type, T def, @NotNull World world, Supplier supplier) { + public static > T runEnum(EventType type, @Nullable T def, World world, Supplier supplier) { if (world.isClient()) return def; - List subscribers = Subscription.getData(MakeSure.notNull(world.getServer()), type); + 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) 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 6db2699..a646f93 100644 --- a/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java +++ b/src/main/java/me/melontini/commander/impl/builtin/BuiltInCommands.java @@ -21,7 +21,6 @@ public class BuiltInCommands { 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); 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 b06975d..e2cc0a6 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 @@ -13,6 +13,7 @@ import net.minecraft.loot.context.LootContextTypes; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; import java.util.Set; @@ -29,7 +30,7 @@ public class ArithmeticaCommand { dispatcher.register(CommandManager.literal("cmd:arithmetica").requires(source -> source.hasPermissionLevel(2)).then(cmd)); } - private static int execute(CommandContext context, String expression, String cast) { + private static int execute(CommandContext context, String expression, @Nullable String cast) { try { var r = PatternParser.parseExpression(expression, cast); if (r.error().isPresent()) { 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 0fcdd56..514b0df 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 @@ -17,6 +17,7 @@ import net.minecraft.loot.context.LootContextTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.ActionResult; import net.minecraft.util.math.Vec3d; +import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -64,7 +65,7 @@ public class EntityEvents { })); } - private static LootContext makeContext(Entity entity, Vec3d origin, DamageSource source) { + 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) { 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 367518d..d8676b5 100644 --- a/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java +++ b/src/main/java/me/melontini/commander/impl/command/ConditionedCommand.java @@ -36,11 +36,13 @@ public record ConditionedCommand(Optional condition, Command othe } }.codec(); + @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 f80b5ab..ac07185 100644 --- a/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java +++ b/src/main/java/me/melontini/commander/impl/command/ConditionedSelector.java @@ -25,6 +25,7 @@ public record ConditionedSelector(Optional condition, Selector ot 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(); 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 0f1cc46..d5a6e78 100644 --- a/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java +++ b/src/main/java/me/melontini/commander/impl/event/EventContextImpl.java @@ -9,7 +9,6 @@ import net.minecraft.loot.context.LootContext; import org.jetbrains.annotations.NotNull; import java.util.IdentityHashMap; -import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @Accessors(fluent = true) @@ -17,33 +16,38 @@ public final class EventContextImpl implements EventContext { @Getter private final EventType type; - private final Map, Object> parameters; + private final IdentityHashMap, Object> parameters; - private EventContextImpl(EventType type, Map, Object> parameters) { + private EventContextImpl(EventType type, IdentityHashMap, Object> parameters) { this.parameters = parameters; this.type = type; } - public EventContextImpl with(Map, Object> parameters) { - var map = new IdentityHashMap<>(this.parameters); + @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; @@ -55,7 +59,7 @@ public final class EventContextImpl implements EventContext { } public static final class Builder implements EventContext.Builder { - private final Map, Object> map = new IdentityHashMap<>(); + private final IdentityHashMap, Object> map = new IdentityHashMap<>(); private final EventType type; public Builder(EventType type) { @@ -66,11 +70,13 @@ public final class EventContextImpl implements EventContext { } } + @Override public Builder addParameter(EventKey key, T value) { this.map.put(key, value); return this; } + @Override 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 d839e11..cf95f9b 100644 --- a/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java +++ b/src/main/java/me/melontini/commander/impl/event/EventTypeImpl.java @@ -7,6 +7,7 @@ import me.melontini.commander.impl.event.data.types.EventTypes; import me.melontini.dark_matter.api.base.util.Context; 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; @@ -33,17 +34,20 @@ public record EventTypeImpl(Context context) implements EventType { public static class Builder implements EventType.Builder { private final Context.Builder builder = Context.builder(); - public Builder extension(Codec extension, Function>, C> finalizer) { + @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); 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 37f8d6f..c021874 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 @@ -11,6 +11,7 @@ import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.minecraft.resource.ResourceManager; import net.minecraft.server.MinecraftServer; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.stream.Collectors; @@ -20,17 +21,17 @@ public class DynamicEventManager extends JsonCodecDataLoader RELOADER = ReloaderType.create(new Identifier("commander:events")); - final Map customData = new IdentityHashMap<>(); + final IdentityHashMap customData = new IdentityHashMap<>(); public DynamicEventManager() { super(RELOADER.identifier(), SubscriptionImpl.CODEC); } - public static T getData(MinecraftServer server, EventType type) { + public static @Nullable T getData(MinecraftServer server, EventType type) { return server.dm$getReloader(DynamicEventManager.RELOADER).getData(type); } - public T getData(EventType type) { + public @Nullable T getData(EventType type) { return (T) this.customData.get(type); } 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 2773a18..40518e5 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 @@ -8,6 +8,7 @@ import me.melontini.commander.api.event.Subscription; import me.melontini.commander.impl.event.data.types.EventTypes; 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; @@ -15,7 +16,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; -public record SubscriptionImpl(EventType type, 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); public static final MapCodec> BASE_CODEC = new MapCodec>() { 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 14edb1f..f5499f5 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 @@ -9,6 +9,8 @@ import me.melontini.commander.api.command.CommandType; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.util.Identifier; +import java.util.Objects; + @UtilityClass public final class CommandTypes { @@ -17,11 +19,11 @@ public final class CommandTypes { public static final Codec CODEC = TYPE_CODEC.dispatch("type", Command::type, CommandType::codec); public static Identifier getId(CommandType type) { - return COMMANDS.inverse().get(type); + return Objects.requireNonNull(COMMANDS.inverse().get(type), () -> "Unregistered CommandType %s!".formatted(type)); } public static CommandType getType(Identifier identifier) { - return COMMANDS.get(identifier); + return Objects.requireNonNull(COMMANDS.get(identifier), () -> "Unknown CommandType %s!".formatted(identifier)); } public static CommandType register(Identifier identifier, CommandType 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 48cf05b..e554c13 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 @@ -7,8 +7,10 @@ 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 @@ -18,14 +20,14 @@ public final class EventTypes { public static final Codec CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, EVENTS); public static Identifier getId(EventType type) { - return EVENTS.inverse().get(type); + return Objects.requireNonNull(EVENTS.inverse().get(type), () -> "Unregistered EventType %s!".formatted(type)); } public static EventType getType(Identifier identifier) { - return EVENTS.get(identifier); + return Objects.requireNonNull(EVENTS.get(identifier), "Unknown EventType %s!".formatted(identifier)); } - public static Set types() { + public static @UnmodifiableView Set types() { return Collections.unmodifiableSet(EVENTS.values()); } 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 2068f10..4595383 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 @@ -7,13 +7,15 @@ import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import net.minecraft.loot.context.LootContextParameter; import net.minecraft.util.Identifier; +import java.util.Objects; + public class ExtractionTypes { private static final BiMap> KNOWN_PARAMETERS = HashBiMap.create(); public static final Codec> CODEC = ExtraCodecs.mapLookup(Identifier.CODEC, KNOWN_PARAMETERS); public static LootContextParameter getParameter(Identifier identifier) { - return KNOWN_PARAMETERS.get(identifier); + return Objects.requireNonNull(KNOWN_PARAMETERS.get(identifier), () -> "No such loot context parameter %s!".formatted(identifier)); } public static void register(LootContextParameter parameter) { 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 b8e799f..d0dcd44 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 @@ -15,7 +15,6 @@ public final class SelectorTypes { 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)); 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 2d7e805..321c1d4 100644 --- a/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java +++ b/src/main/java/me/melontini/commander/impl/expression/EvalUtils.java @@ -24,9 +24,11 @@ import me.melontini.commander.impl.util.functions.RangedRandomFunction; import me.melontini.commander.impl.util.functions.StructContainsKeyFunction; import net.minecraft.loot.context.LootContext; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; import java.util.Map; +import java.util.Objects; import java.util.function.Function; public class EvalUtils { @@ -123,12 +125,12 @@ public class EvalUtils { public static EvaluationValue evaluate(LootContext context, Expression exp) { try { - ((EvalUtils.MapBasedDataAccessor)exp.getDataAccessor()).local.set(context); + MapBasedDataAccessor.LOCAL.set(context); return exp.evaluate(); } catch (EvaluationException | ParseException e) { - throw new CmdEvalException(e.getMessage(), e); + throw new CmdEvalException(Objects.requireNonNullElseGet(e.getMessage(), () -> "Failed to evaluate expression %s".formatted(exp.getExpressionString().replace("__idcl__", ":"))), e); } finally { - ((EvalUtils.MapBasedDataAccessor)exp.getDataAccessor()).local.remove(); + MapBasedDataAccessor.LOCAL.remove(); } } @@ -152,15 +154,15 @@ public class EvalUtils { new Identifier("level"), LootContext::getWorld, new Identifier("luck"), LootContext::getLuck ); - public final ThreadLocal local = new ThreadLocal<>(); + public static final ThreadLocal LOCAL = new ThreadLocal<>(); @Override - public EvaluationValue getData(String variable) { + public @Nullable EvaluationValue getData(String variable) { var id = new Identifier(variable.replace("__idcl__", ":")); var func = overrides.get(id); - if (func != null) return CONFIGURATION.getEvaluationValueConverter().convertObject(func.apply(local.get()), CONFIGURATION); + if (func != null) return CONFIGURATION.getEvaluationValueConverter().convertObject(func.apply(LOCAL.get()), CONFIGURATION); - var object = local.get().get(ExtractionTypes.getParameter(id)); + var object = LOCAL.get().get(ExtractionTypes.getParameter(id)); if (object == null) return null; return CONFIGURATION.getEvaluationValueConverter().convertObject(object, CONFIGURATION); } @@ -182,7 +184,7 @@ public class EvalUtils { } @Override - public FunctionIfc getFunction(String functionName) { + public @Nullable FunctionIfc getFunction(String functionName) { return functions.get(functionName); } diff --git a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java index 2337211..0593108 100644 --- a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java +++ b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java @@ -4,6 +4,7 @@ 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.NonNull; import lombok.Synchronized; import lombok.extern.log4j.Log4j2; import me.melontini.commander.impl.Commander; @@ -109,7 +110,7 @@ public class ReflectiveMapStructure implements Map { return true; } - private static Tuple, Accessor> findFieldOrMethod(Class cls, String name) { + private static @Nullable Tuple, Accessor> findFieldOrMethod(Class cls, String name) { String mapped; Class target = cls; do { @@ -128,7 +129,8 @@ public class ReflectiveMapStructure implements Map { return findAccessor(cls, name); } - private static Tuple, Accessor> findAccessor(Class cls, String mapped) { + @Nullable + private static Tuple, Accessor> findAccessor(@NonNull Class cls, String mapped) { for (Method method : cls.getMethods()) { if (!method.getName().equals(mapped)) continue; if (Modifier.isStatic(method.getModifiers())) continue; @@ -162,7 +164,7 @@ public class ReflectiveMapStructure implements Map { if (field == null) throw new RuntimeException("%s has no public field or method '%s'".formatted(this.object.getClass().getSimpleName(), key)); return EvalUtils.CONFIGURATION.getEvaluationValueConverter().convertObject(field.access(this.object), EvalUtils.CONFIGURATION); } catch (IllegalAccessException | InvocationTargetException e) { - throw new CmdEvalException(e.getMessage()); + throw new CmdEvalException(Objects.requireNonNullElse(e.getMessage(), "Failed to reflectively access member!")); } } @@ -225,7 +227,7 @@ public class ReflectiveMapStructure implements Map { this.invalid.add(key); } - public Accessor getAccessor(String key) { + public @Nullable Accessor getAccessor(String key) { return this.accessors == null ? null : this.accessors.get(key); } 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 3c64d04..16fc3b0 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 @@ -7,6 +7,7 @@ import java.util.function.Function; public record DynamicMacro(String original, Function start) implements BrigadierMacro { + @Override public String build(LootContext context) { return start.apply(context).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 abeddfd..84fc9e9 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 @@ -4,6 +4,7 @@ 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.util.function.Consumer; import java.util.function.Function; @@ -48,7 +49,7 @@ public class PatternParser { return b.toString(); } - public static DataResult> parseExpression(String expression, String cast) { + public static DataResult> parseExpression(String expression, @Nullable String cast) { var result = EvalUtils.parseExpression(expression); if (cast != null) { return switch (cast) { 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 037b597..88ae5e3 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java @@ -62,7 +62,7 @@ public class AdvancementRewardsMixin { @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); + 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) 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 585a1fc..9984292 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,10 +8,12 @@ import net.minecraft.loot.provider.number.LootNumberProviderType; public record ArithmeticaLootNumberProvider(Arithmetica value) implements LootNumberProvider { + @Override public LootNumberProviderType getType() { return Commander.ARITHMETICA_PROVIDER; } + @Override public float nextFloat(LootContext context) { return this.value.asFloat(context); } 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 a56fb48..f599eaa 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 @@ -1,5 +1,7 @@ package me.melontini.commander.impl.util.mappings; +import org.jetbrains.annotations.Nullable; + public interface AmbiguousRemapper { - 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 8ee759e..964eaf4 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 @@ -9,9 +9,11 @@ import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.tree.MappingTree; 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.nio.file.Path; import java.util.Objects; @@ -31,18 +33,19 @@ public record MappingKeeper(MemoryMappingTree mojmapTarget) implements Ambiguous offMojmap.accept(temp); if (!NAMESPACE.equals("mojang")) offTarget.accept(temp); temp.accept(new MappingSourceNsSwitch(tree, "mojang", true)); - tree.getClass("net/minecraft/server/MinecraftServer").setDstName("net/minecraft/server/MinecraftServer", tree.getNamespaceId(NAMESPACE)); + 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() { if (NAMESPACE.equals("mojang")) return null; log.info("Loading official->mojmap mappings..."); Path path = FabricLoader.getInstance().getModContainer("commander").orElseThrow().findPath("commander/mappings/%s.bin".formatted(getVersion())).orElseThrow(); var tree = new MemoryMappingTree(); - MappingReader.read(new InputStreamReader(new InflaterInputStream(Files.newInputStream(path))), tree); + MappingReader.read(new InputStreamReader(new InflaterInputStream(Files.newInputStream(path)), StandardCharsets.UTF_8), tree); return tree; } @@ -51,11 +54,12 @@ public record MappingKeeper(MemoryMappingTree mojmapTarget) implements Ambiguous log.info("Loading official->{} mappings...", NAMESPACE); var tree = new MemoryMappingTree(); - MappingReader.read(new InputStreamReader(Objects.requireNonNull(MappingKeeper.class.getClassLoader().getResourceAsStream("mappings/mappings.tiny"), "mappings/mappings.tiny is not available?")), tree); + MappingReader.read(new InputStreamReader(Objects.requireNonNull(MappingKeeper.class.getClassLoader().getResourceAsStream("mappings/mappings.tiny"), "mappings/mappings.tiny is not available?"), StandardCharsets.UTF_8), tree); return tree; } - public String getFieldOrMethod(Class cls, String name) { + @Override + public @Nullable String getFieldOrMethod(Class cls, String name) { var clsData = mojmapTarget.getClass(Type.getInternalName(cls), mojmapTarget.getNamespaceId(NAMESPACE)); if (clsData == null) return null; @@ -73,7 +77,7 @@ public record MappingKeeper(MemoryMappingTree mojmapTarget) implements Ambiguous } public static String getVersion() { - JsonObject o = JsonParser.parseReader(new InputStreamReader(MappingKeeper.class.getResourceAsStream("/version.json"))).getAsJsonObject(); + JsonObject o = JsonParser.parseReader(new InputStreamReader(MappingKeeper.class.getResourceAsStream("/version.json"), StandardCharsets.UTF_8)).getAsJsonObject(); return o.getAsJsonPrimitive("id").getAsString(); } } -- 2.51.2 From 1c9edff873919929e3793f1815d3c1c63d158122 Mon Sep 17 00:00:00 2001 From: melontini <104443436+melontini@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:10:14 +0700 Subject: [PATCH 2/6] All the changes from other places. --- .github/workflows/build.yml | 129 +----------------- .github/workflows/build_pr.yml | 23 ---- .github/workflows/publish.yml | 23 ++++ build.gradle | 83 +++++++++-- gradle.properties | 2 +- spotbugs.xml | 11 ++ .../melontini/commander/impl/Commander.java | 20 ++- .../expression/ReflectiveMapStructure.java | 4 +- src/main/resources/fabric.mod.json | 2 +- 9 files changed, 136 insertions(+), 161 deletions(-) delete mode 100644 .github/workflows/build_pr.yml create mode 100644 .github/workflows/publish.yml create mode 100644 spotbugs.xml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 400f789..1385a79 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,127 +1,12 @@ name: build -on: - push: - workflow_dispatch: - inputs: - version_type: - description: "The type of this version. e.g alpha" - type: choice - default: beta - options: - - release - - beta - - alpha - required: false +on: [ push, pull_request ] jobs: build: - runs-on: ubuntu-latest - if: | - !contains(github.event.head_commit.message, '[ci skip]') - outputs: - version_info: ${{ steps.get_version.outputs.version_info }} - version_plain: ${{ steps.get_version.outputs.version_plain }} - steps: - - name: checkout repository - uses: actions/checkout@v4.1.1 - - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v2.1.1 - - name: setup jdk - uses: actions/setup-java@v4.1.0 - with: - distribution: 'temurin' - java-version: 17 - cache: gradle - - name: make gradle wrapper executable - run: chmod +x ./gradlew - - name: build - run: ./gradlew build - - name: get version #https://stackoverflow.com/questions/71089787/how-to-get-version-name-from-android-gradle-file-in-github-actions - id: get_version - run: | - echo "version_info=$(${{github.workspace}}/gradlew -q printVersionName)" >> $GITHUB_OUTPUT - echo "version_plain=$(${{github.workspace}}/gradlew -q printVersion)" >> $GITHUB_OUTPUT - - name: capture build artifacts - uses: actions/upload-artifact@v4.3.1 - with: - name: Artifacts - path: build/libs/ - - name: capture processed mappings - uses: actions/upload-artifact@v4.3.1 - with: - name: Mappings - path: .gradle/commander/mappings/ - - packages: - needs: build - runs-on: ubuntu-latest - steps: - - name: checkout repository - uses: actions/checkout@v4.1.1 - - name: setup jdk - uses: actions/setup-java@v4.1.0 - with: - distribution: 'temurin' - java-version: 17 - cache: gradle - - uses: actions/download-artifact@v4.1.4 - with: - name: Mappings - path: .gradle/commander/mappings/ - - uses: geekyeggo/delete-artifact@v5 - with: - name: Mappings - - name: make gradle wrapper executable - run: chmod +x ./gradlew - - name: publish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - ./gradlew publish - - publish: - needs: build - runs-on: ubuntu-latest - if: ${{ github.event_name == 'workflow_dispatch' }} - steps: - - name: checkout repository - uses: actions/checkout@v4.1.1 - - uses: actions/download-artifact@v4.1.4 - with: - name: Artifacts - path: build/libs - - - name: publish release - uses: Kir-Antipov/mc-publish@v3.3.0 - with: - version-type: ${{ inputs.version_type }} - changelog-file: CHANGELOG.md - name: ${{ needs.build.outputs.version_info }} - version: ${{ needs.build.outputs.version_plain }} - - game-versions: | - 1.20.1 - - loaders: | - fabric - - java: | - 17 - - files: | - build/libs/!(*-@(dev|sources|javadoc|dependencies|full-dependencies)).jar - build/libs/*-@(dev|sources|javadoc).jar - - github-tag: ${{ needs.build.outputs.version_plain }} - github-token: ${{ secrets.GITHUB_TOKEN }} - github-commitish: ${{ github.sha }} - github-prerelease: false - - modrinth-id: 86bUtxWv - modrinth-token: ${{ secrets.MODRINTH_TOKEN }} - modrinth-featured: true - modrinth-unfeature-mode: subset - modrinth-dependencies: | - fabric-api(required) - dark-matter(embedded) + uses: constellation-mc/actions/.github/workflows/gradle-build.yml@main + with: + java: 17 + gradle_tasks: spotbugs + reviewdog: | + cat ./build/reports/spotbugs/main/spotbugs.sarif | reviewdog -name="spotbugs" -f=sarif -reporter=github-check -level=warning \ No newline at end of file diff --git a/.github/workflows/build_pr.yml b/.github/workflows/build_pr.yml deleted file mode 100644 index 1a4bf50..0000000 --- a/.github/workflows/build_pr.yml +++ /dev/null @@ -1,23 +0,0 @@ - -name: build pull request -on: [ pull_request ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: checkout repository - uses: actions/checkout@v4.1.1 - - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v2.1.1 - - name: setup jdk 17 - uses: actions/setup-java@v4.1.0 - with: - distribution: 'temurin' - java-version: 17 - cache: gradle - - name: make gradle wrapper executable - run: chmod +x ./gradlew - - name: build - run: | - ./gradlew build \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..5cc4533 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,23 @@ + +name: publish +on: + workflow_dispatch: + inputs: + version_type: + description: "The type of this version. e.g alpha" + type: choice + default: BETA + options: + - STABLE + - BETA + - ALPHA + - NONE + required: false + +jobs: + publish: + uses: constellation-mc/actions/.github/workflows/mc-publish.yml@main + with: + java: 17 + version_type: ${{ inputs.version_type }} + secrets: inherit \ No newline at end of file diff --git a/build.gradle b/build.gradle index 3f8014e..2156e15 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,14 @@ plugins { id 'maven-publish' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false id 'io.freefair.lombok' version '8.3' + id 'com.github.spotbugs-base' version '6.0.12' + id 'com.diffplug.spotless' version '6.25.0' + id "me.modmuss50.mod-publish-plugin" version "0.5.1" } import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.github.spotbugs.snom.SpotBugsTask +import me.modmuss50.mpp.ReleaseType def local = !System.getenv().containsKey("GITHUB_RUN_NUMBER"); @@ -75,6 +80,38 @@ dependencies { implementation shade("net.fabricmc:mapping-io:${project.mappingio_version}") } +tasks.register("spotbugs", SpotBugsTask) { task -> + sourceSets.each { + task.sourceDirs.from(task.sourceDirs.files, it.allSource.sourceDirectories) + task.classDirs.from(task.classDirs.files, it.output) + task.auxClassPaths.from(task.auxClassPaths.files, it.compileClasspath) + } + excludeFilter = file("spotbugs.xml") + ignoreFailures = true + reports { + if (local) { + html { + required = true + outputLocation = file("$buildDir/reports/spotbugs/main/spotbugs.html") + stylesheet = 'fancy-hist.xsl' + } + } else { + sarif { + required = true + outputLocation = file("$buildDir/reports/spotbugs/main/spotbugs.sarif") + } + } + } +} + +spotless { + java { + removeUnusedImports() + trimTrailingWhitespace() + formatAnnotations() + } +} + loom { accessWidenerPath = file("src/main/resources/commander.accesswidener") } @@ -150,15 +187,45 @@ publishing { } } - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - maven { - name = "GitHubPackages" - url = "https://maven.pkg.github.com/constellation-mc/commander" - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + if (!local) { + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/constellation-mc/commander" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } } } } } + +publishMods { + file = remapJar.archiveFile + additionalFiles.from(remapSourcesJar.archiveFile) + + changelog = file("CHANGELOG.md").text + type = ReleaseType.valueOf(providers.environmentVariable("VERSION_TYPE").getOrElse("BETA")) + modLoaders.add("fabric") + + displayName = "${project.mod_version} (${project.minecraft_version})" + + modrinth { + projectId = "86bUtxWv" + accessToken = providers.environmentVariable("MODRINTH_TOKEN") + minecraftVersions.add("${project.minecraft_version}") + + requires("fabric-api") + embeds("dark-matter") + } + github { + repository = "constellation-mc/commander" + accessToken = providers.environmentVariable("GITHUB_TOKEN") + commitish = providers.environmentVariable("GITHUB_SHA").getOrElse("${project.minecraft_version}-fabric") + + type = STABLE + } + + dryRun = local +} diff --git a/gradle.properties b/gradle.properties index a86ee38..cdc4464 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.15.7 # Mod Properties -mod_version=0.2.2 +mod_version=0.3.0 maven_group=me.melontini archives_base_name=commander # Dependencies diff --git a/spotbugs.xml b/spotbugs.xml new file mode 100644 index 0000000..73cc232 --- /dev/null +++ b/spotbugs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/me/melontini/commander/impl/Commander.java b/src/main/java/me/melontini/commander/impl/Commander.java index bb2709c..1ff1fbc 100644 --- a/src/main/java/me/melontini/commander/impl/Commander.java +++ b/src/main/java/me/melontini/commander/impl/Commander.java @@ -1,6 +1,7 @@ package me.melontini.commander.impl; import lombok.Getter; +import lombok.experimental.Accessors; import lombok.extern.log4j.Log4j2; import me.melontini.commander.api.expression.Arithmetica; import me.melontini.commander.api.expression.LootContextParameterRegistry; @@ -14,10 +15,10 @@ import me.melontini.commander.impl.util.loot.ExpressionLootCondition; import me.melontini.commander.impl.util.mappings.AmbiguousRemapper; import me.melontini.commander.impl.util.mappings.MappingKeeper; import me.melontini.dark_matter.api.base.util.Exceptions; +import me.melontini.dark_matter.api.base.util.MakeSure; import me.melontini.dark_matter.api.base.util.PrependingLogger; import me.melontini.dark_matter.api.data.codecs.ExtraCodecs; import me.melontini.dark_matter.api.data.loading.ServerReloadersEvent; -import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.minecraft.loot.condition.LootConditionType; @@ -36,8 +37,9 @@ import java.util.concurrent.CompletableFuture; import static net.minecraft.loot.context.LootContextParameters.*; +@Accessors(fluent = true) @Log4j2 -public class Commander implements ModInitializer { +public class Commander { public static final PrependingLogger LOGGER = PrependingLogger.get(); public static final LootNumberProviderType ARITHMETICA_PROVIDER = LootNumberProviderTypes.register("commander:arithmetica", ExtraCodecs.toJsonSerializer(Arithmetica.CODEC.xmap(ArithmeticaLootNumberProvider::new, ArithmeticaLootNumberProvider::value))); @@ -46,13 +48,23 @@ public class Commander implements ModInitializer { public static final Path COMMANDER_PATH = FabricLoader.getInstance().getGameDir().resolve(".commander"); @Getter - private static AmbiguousRemapper mappingKeeper; + private AmbiguousRemapper mappingKeeper; public static Identifier id(String path) { return new Identifier("commander", path); } - @Override + private static Commander instance; + + public static void init() { + instance = new Commander(); + instance.onInitialize(); + } + + public static Commander get() { + return MakeSure.notNull(instance); + } + public void onInitialize() { if (!Files.exists(COMMANDER_PATH)) { Exceptions.run(() -> Files.createDirectories(COMMANDER_PATH)); diff --git a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java index 0593108..706b625 100644 --- a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java +++ b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java @@ -114,7 +114,7 @@ public class ReflectiveMapStructure implements Map { String mapped; Class target = cls; do { - if ((mapped = Commander.getMappingKeeper().getFieldOrMethod(target, name)) != null) return findAccessor(target, mapped); + if ((mapped = Commander.get().mappingKeeper().getFieldOrMethod(target, name)) != null) return findAccessor(target, mapped); var targetItfs = target.getInterfaces(); if (targetItfs.length == 0) continue; @@ -122,7 +122,7 @@ public class ReflectiveMapStructure implements Map { while (!interfaces.isEmpty()) { var itf = interfaces.poll(); - if ((mapped = Commander.getMappingKeeper().getFieldOrMethod(itf, name)) != null) return findAccessor(itf, mapped); + if ((mapped = Commander.get().mappingKeeper().getFieldOrMethod(itf, name)) != null) return findAccessor(itf, mapped); if ((targetItfs = itf.getInterfaces()).length > 0) interfaces.addAll(List.of(targetItfs)); } } while ((target = target.getSuperclass()) != null); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 8af4617..74ec5b5 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "environment": "*", "entrypoints": { "main": [ - "me.melontini.commander.impl.Commander" + "me.melontini.commander.impl.Commander::init" ] }, "mixins": [ -- 2.51.2 From 4476019e405cc886acfd59b816018e62407a5751 Mon Sep 17 00:00:00 2001 From: melontini <104443436+melontini@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:30:11 +0700 Subject: [PATCH 3/6] Unify and fixup casts. --- .../builtin/brigadier/ArithmeticaCommand.java | 5 +---- .../impl/expression/macro/PatternParser.java | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) 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 e2cc0a6..5be6574 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 @@ -15,15 +15,12 @@ import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; -import java.util.Set; - public class ArithmeticaCommand { public static void register(CommandDispatcher dispatcher) { - Set casts = Set.of("long", "int", "bool", "double"); var cmd = CommandManager.argument("expression", StringArgumentType.string()).executes(context -> execute(context, StringArgumentType.getString(context, "expression"), null)); - for (String cast : casts) { + for (String cast : PatternParser.CONVERTERS.keySet()) { cmd.then(CommandManager.literal(cast).executes(context -> execute(context, StringArgumentType.getString(context, "expression"), cast))); } 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 84fc9e9..2c9749b 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,11 +1,15 @@ package me.melontini.commander.impl.expression.macro; +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.Consumer; import java.util.function.Function; import java.util.regex.Matcher; @@ -16,6 +20,12 @@ import static me.melontini.commander.impl.expression.EvalUtils.evaluate; public class PatternParser { public static final Pattern PATTERN = Pattern.compile("\\$(?:\\(([a-z]+)\\))?\\{\\{([^{}]*)\\}\\}"); + public static final Map> CONVERTERS = ImmutableMap.of( + "bool", v -> String.valueOf(v.getBooleanValue()), + "long", v -> String.valueOf(v.getNumberValue().setScale(0, RoundingMode.DOWN)), + "int", v -> String.valueOf(v.getNumberValue().setScale(0, RoundingMode.DOWN)), + "double", v -> v.getNumberValue().toString() + ); public static final int CAST = 1; public static final int EXPRESSION = 2; @@ -52,13 +62,9 @@ public class PatternParser { public static DataResult> parseExpression(String expression, @Nullable String cast) { var result = EvalUtils.parseExpression(expression); if (cast != null) { - return switch (cast) { - case "long" -> result.map(exp -> context -> String.valueOf(evaluate(context, exp).getNumberValue().longValue())); - case "int" -> result.map(exp -> context -> String.valueOf(evaluate(context, exp).getNumberValue().intValue())); - case "double" -> result.map(exp -> context -> String.valueOf(evaluate(context, exp).getNumberValue().doubleValue())); - case "bool" -> result.map(exp -> context -> String.valueOf(evaluate(context, exp).getBooleanValue())); - default -> DataResult.error(() -> "Unknown cast type %s".formatted(cast)); - }; + var c = CONVERTERS.get(cast); + if (c == null) return DataResult.error(() -> "Unknown cast type %s".formatted(cast)); + return result.map(exp -> context -> c.apply(evaluate(context, exp))); } return result.map(exp -> context -> evaluate(context, exp).getStringValue()); } -- 2.51.2 From ea3fd3265443b7c2f317b755caaae03eb5038c71 Mon Sep 17 00:00:00 2001 From: melontini <104443436+melontini@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:30:24 +0700 Subject: [PATCH 4/6] Spotless --- .../impl/expression/ReflectiveMapStructure.java | 15 +++++---------- .../impl/mixin/AdvancementRewardsMixin.java | 6 ++---- .../impl/util/mappings/MappingKeeper.java | 3 +-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java index 706b625..a9dbdf6 100644 --- a/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java +++ b/src/main/java/me/melontini/commander/impl/expression/ReflectiveMapStructure.java @@ -129,8 +129,7 @@ public class ReflectiveMapStructure implements Map { return findAccessor(cls, name); } - @Nullable - private static Tuple, Accessor> findAccessor(@NonNull Class cls, String mapped) { + @Nullable private static Tuple, Accessor> findAccessor(@NonNull Class cls, String mapped) { for (Method method : cls.getMethods()) { if (!method.getName().equals(mapped)) continue; if (Modifier.isStatic(method.getModifiers())) continue; @@ -168,8 +167,7 @@ public class ReflectiveMapStructure implements Map { } } - @Nullable - @Override + @Nullable @Override public Object put(String key, Object value) { throw new UnsupportedOperationException(); } @@ -189,20 +187,17 @@ public class ReflectiveMapStructure implements Map { throw new UnsupportedOperationException(); } - @NotNull - @Override + @NotNull @Override public Set keySet() { return Collections.emptySet(); } - @NotNull - @Override + @NotNull @Override public Collection values() { return Collections.emptyList(); } - @NotNull - @Override + @NotNull @Override public Set> entrySet() { return Collections.emptySet(); } 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 88ae5e3..245d6a0 100644 --- a/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java +++ b/src/main/java/me/melontini/commander/impl/mixin/AdvancementRewardsMixin.java @@ -29,11 +29,9 @@ import java.util.List; @Mixin(AdvancementRewards.class) public class AdvancementRewardsMixin { - @Unique - private static final Codec> COMMANDER_CODEC = ExtraCodecs.list(Command.CODEC); + @Unique private static final Codec> COMMANDER_CODEC = ExtraCodecs.list(Command.CODEC); - @Unique - private List commands; + @Unique private List commands; @ModifyReturnValue(at = @At("TAIL"), method = "toJson") private JsonElement commander$encodeCommands(JsonElement original) { 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 964eaf4..b1f0764 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 @@ -38,8 +38,7 @@ public record MappingKeeper(MemoryMappingTree mojmapTarget) implements Ambiguous } @SneakyThrows - @Nullable - public static MemoryMappingTree loadOffMojmap() { + @Nullable public static MemoryMappingTree loadOffMojmap() { if (NAMESPACE.equals("mojang")) return null; log.info("Loading official->mojmap mappings..."); Path path = FabricLoader.getInstance().getModContainer("commander").orElseThrow().findPath("commander/mappings/%s.bin".formatted(getVersion())).orElseThrow(); -- 2.51.2 From 4265f0e12fb86920b124155d0246f4205e2802db Mon Sep 17 00:00:00 2001 From: melontini <104443436+melontini@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:54:09 +0700 Subject: [PATCH 5/6] Add entity & fire parameters to `cmd:explode` --- .../builtin/brigadier/ExplodeCommand.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) 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 0e36795..5201c94 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 @@ -1,27 +1,40 @@ package me.melontini.commander.impl.builtin.brigadier; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.FloatArgumentType; +import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.Vec3ArgumentType; +import net.minecraft.entity.Entity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +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(), context.getSource().getPosition(), 4)) + .executes(context -> execute(context.getSource().getWorld(), null, context.getSource().getPosition(), 4, false)) .then(CommandManager.argument("pos", Vec3ArgumentType.vec3()) - .executes(context -> execute(context.getSource().getWorld(), Vec3ArgumentType.getVec3(context, "pos"), 4)) + .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(), Vec3ArgumentType.getVec3(context, "pos"), FloatArgumentType.getFloat(context, "power")))))); + .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, Vec3d vec, float power) { - world.createExplosion(null, vec.getX(), vec.getY(), vec.getZ(), - power, World.ExplosionSourceType.TNT); + 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; } } -- 2.51.2 From b775df753600c444566d4d3abc54e29f4c6cc205 Mon Sep 17 00:00:00 2001 From: melontini <104443436+melontini@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:57:09 +0700 Subject: [PATCH 6/6] CHANGELOG.md --- CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0208e1c..7e49c4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,6 @@ ### What's New: -* Exposed Expressions in the `api` package. -* You can now specify `commander:commands` in advancement rewards. -* Mappings are no longer downloaded on startup. -* Added shaded licenses. -* Fixed conditioned selector crash on 1.20.4. \ No newline at end of file +* Added entity parameter to `cmd:explode`. The entity will be marked as the "creator" of the explosion and other entities will redirect their anger to the entity if affected by the explosion. +* Added fire parameter to `cmd:explode`. Creates fire, if true. +* Fixed `double` casts converting numbers to scientific notation. +* `long` and `int` casts no longer actually convert to their types, instead they truncate the trailing zeros. \ No newline at end of file