Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

Commit

Permalink
Add cmd:operate to the scoreboard command.
Browse files Browse the repository at this point in the history
- Use a proper exception in `ExecuteCommandMixin`
  • Loading branch information
melontini committed Jul 15, 2024
1 parent f83f00c commit 159c0d7
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ User Changes:

* Added `arrayFindAny` and `arrayFindFirst` functions to expressions. As the name suggests, those functions will try to find an element of an array or return `null` if the array is empty.
* Java `Iterable`s can now be converted to arrays.
* Added `remove` to `cmd:data`.
* Added `cmd:operate` to the `scoreboard players` command.
* Added registry access for expressions! Now you can access the game's static and dynamic content registries by using new `Registry` and `DynamicRegistry` functions.
* Why is this useful? For example, this allows you to compare item stacks based on their item type:
```
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/me/melontini/commander/impl/Commander.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import lombok.Cleanup;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -25,6 +26,7 @@
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 me.melontini.dark_matter.api.minecraft.util.TextUtil;
import net.fabricmc.fabric.api.attachment.v1.AttachmentRegistry;
import net.fabricmc.fabric.api.attachment.v1.AttachmentType;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
Expand Down Expand Up @@ -65,6 +67,8 @@ public class Commander {
public static final AttachmentType<NbtCompound> DATA_ATTACHMENT = AttachmentRegistry.<NbtCompound>builder()
.initializer(NbtCompound::new).persistent(NbtCodecs.COMPOUND_CODEC).buildAndRegister(id("persistent"));

public static final DynamicCommandExceptionType EXPRESSION_EXCEPTION = new DynamicCommandExceptionType(object -> TextUtil.literal(String.valueOf(object)));

@Getter
private AmbiguousRemapper mappingKeeper;
@Getter @Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.CommandNode;
import me.melontini.commander.api.expression.Expression;
import me.melontini.dark_matter.api.minecraft.util.TextUtil;
import me.melontini.commander.impl.Commander;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameterSet;
Expand All @@ -31,10 +31,7 @@ public abstract class ExecuteCommandMixin {
private static void commander$addExpressionCondition(CommandNode<ServerCommandSource> root, LiteralArgumentBuilder<ServerCommandSource> argumentBuilder, boolean positive, CommandRegistryAccess commandRegistryAccess, CallbackInfoReturnable<ArgumentBuilder<ServerCommandSource, ?>> 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()) {
context.getSource().sendError(TextUtil.literal(r.error().orElseThrow().message()));
throw new IllegalArgumentException();
}
if (r.error().isPresent()) throw Commander.EXPRESSION_EXCEPTION.create(r.error().orElseThrow().message());

LootContext context1 = new LootContext.Builder(new LootContextParameterSet.Builder(context.getSource().getWorld())
.add(LootContextParameters.ORIGIN, context.getSource().getPosition())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
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 me.melontini.commander.impl.Commander;
import me.melontini.commander.impl.expression.EvalUtils;
import net.minecraft.command.argument.ScoreHolderArgumentType;
import net.minecraft.command.argument.ScoreboardObjectiveArgumentType;
import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameterSet;
import net.minecraft.loot.context.LootContextParameters;
import net.minecraft.loot.context.LootContextTypes;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardPlayerScore;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ScoreboardCommand;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.util.ArrayList;

@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<ServerCommandSource> addCommanderOperator(LiteralArgumentBuilder<ServerCommandSource> 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 = EvalUtils.parseExpression(StringArgumentType.getString(context, "expression"));
if (r.error().isPresent()) throw Commander.EXPRESSION_EXCEPTION.create(r.error().orElseThrow().message());
var expression = r.result().orElseThrow();

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);

for (String target : targets) {
ScoreboardPlayerScore score = scoreboard.getPlayerScore(target, objective);
score.setScore(EvalUtils.evaluate(context1, expression.with("score", score.getScore())).getNumberValue().intValue());
}

if (targets.size() == 1) {
context.getSource().sendFeedback(() -> Text.translatable("commands.scoreboard.players.set.success.single", objective.toHoverableText(), targets.get(0), r.result().orElseThrow().getExpressionString()), true);
} else {
context.getSource().sendFeedback(() -> Text.translatable("commands.scoreboard.players.set.success.multiple", objective.toHoverableText(), targets.size(), r.result().orElseThrow().getExpressionString()), true);
}

return targets.size();
})))));
}
}
1 change: 1 addition & 0 deletions src/main/resources/commander.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"mixins": [
"AdvancementRewardsMixin",
"ExecuteCommandMixin",
"ScoreboardCommandMixin",
"evalex.EvaluationValueAccessor",
"evalex.EvaluationValueMixin",
"evalex.ExpressionAccessor",
Expand Down

0 comments on commit 159c0d7

Please sign in to comment.