Skip to content

Commit

Permalink
Refactor how helper is accessed in commands
Browse files Browse the repository at this point in the history
  • Loading branch information
misode committed Dec 26, 2023
1 parent 6dae19d commit fec042e
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 90 deletions.
2 changes: 2 additions & 0 deletions src/main/java/io/github/misode/packtest/PackTestFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ private Consumer<GameTestHelper> createTestBody(int permissionLevel, CommandDisp
.withSuppressedOutput()
.withCallback((success, result) -> hasFailed.set(!success));

((PackTestSourceStack)sourceStack).packtest$setHelper(helper);

InstantiatedFunction<CommandSourceStack> instantiatedFn;
try {
instantiatedFn = function.instantiate(null, dispatcher, sourceStack);
Expand Down
51 changes: 4 additions & 47 deletions src/main/java/io/github/misode/packtest/PackTestLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
import com.google.common.collect.*;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.gametest.framework.GameTestRegistry;
import net.minecraft.gametest.framework.StructureUtils;
import net.minecraft.gametest.framework.TestFunction;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -15,13 +11,15 @@
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.block.entity.StructureBlockEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Executor;
Expand All @@ -37,7 +35,6 @@ public class PackTestLibrary implements PreparableReloadListener {
private Set<String> namespaces = Sets.newHashSet();
private Map<String, Consumer<ServerLevel>> beforeBatch = Maps.newHashMap();
private Map<String, Consumer<ServerLevel>> afterBatch = Maps.newHashMap();
private final Map<String, GameTestHelper> testHelperMap = Maps.newHashMap();

public PackTestLibrary(int permissionLevel, CommandDispatcher<CommandSourceStack> dispatcher) {
this.permissionLevel = permissionLevel;
Expand All @@ -52,46 +49,6 @@ public void setDispatcher(CommandDispatcher<CommandSourceStack> dispatcher) {
this.dispatcher = dispatcher;
}

public void registerTestHelper(String testName, GameTestHelper helper) {
this.testHelperMap.put(testName, helper);
}
public void unregisterTestHelper(String testName) {
this.testHelperMap.remove(testName);
}
public Optional<GameTestHelper> getTestHelper(String testName) {
GameTestHelper helper = this.testHelperMap.get(testName);
if (helper == null) {
PackTest.LOGGER.warn("No helper registered for {}", testName);
}
return Optional.ofNullable(helper);
}

public Optional<GameTestHelper> getHelperAt(CommandSourceStack sourceStack) {
BlockPos blockPos = BlockPos.containing(sourceStack.getPosition());
return getHelperAt(blockPos, sourceStack.getLevel());
}

public Optional<GameTestHelper> getHelperAt(BlockPos pos, ServerLevel level) {
Optional<BlockPos> structurePos = StructureUtils.findStructureBlockContainingPos(pos, 15, level);
if (structurePos.isEmpty()) {
PackTest.LOGGER.warn("No structure at {}", pos);
return Optional.empty();
}
StructureBlockEntity structureBlockEntity = (StructureBlockEntity)level.getBlockEntity(structurePos.get());
if (structureBlockEntity == null) {
PackTest.LOGGER.warn("No block entity at {}", structurePos);
return Optional.empty();
}
String metadata = structureBlockEntity.getMetaData();
Optional<TestFunction> testFunction = GameTestRegistry.findTestFunction(metadata);
if (testFunction.isEmpty()) {
PackTest.LOGGER.warn("No test function for {}", metadata);
return Optional.empty();
}
String testName = testFunction.get().getTestName();
return this.getTestHelper(testName);
}

@Override
public @NotNull CompletableFuture<Void> reload(PreparableReloadListener.PreparationBarrier barrier, ResourceManager resources, ProfilerFiller profiler1, ProfilerFiller profiler2, Executor executor1, Executor executor2) {
CompletableFuture<Map<ResourceLocation, CompletableFuture<PackTestFunction>>> prep = CompletableFuture.supplyAsync(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.github.misode.packtest;

import net.minecraft.gametest.framework.GameTestHelper;
import org.jetbrains.annotations.Nullable;

public interface PackTestSourceStack {
@Nullable GameTestHelper packtest$getHelper();
void packtest$setHelper(GameTestHelper helper);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import io.github.misode.packtest.PackTestArgumentSource;
import io.github.misode.packtest.PackTestLibrary;
import io.github.misode.packtest.PackTestSourceStack;
import net.minecraft.advancements.critereon.MinMaxBounds;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
Expand All @@ -23,6 +23,7 @@
import net.minecraft.commands.execution.Frame;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.commands.data.DataCommands;
Expand Down Expand Up @@ -216,8 +217,10 @@ public void run(CommandSourceStack sourceStack, ContextChain<CommandSourceStack>
CommandContext<CommandSourceStack> ctx = chain.getTopContext().copyFor(sourceStack);
var result = this.predicate.apply(ctx);
result.get(this.expectOk).ifPresentOrElse(message -> {
PackTestLibrary.INSTANCE.getHelperAt(sourceStack)
.ifPresent(helper -> helper.fail(message));
GameTestHelper helper = ((PackTestSourceStack)sourceStack).packtest$getHelper();
if (helper != null) {
helper.fail(message);
}
sourceStack.callback().onFailure();
Frame frame = execution.currentFrame();
frame.returnFailure();
Expand Down
24 changes: 13 additions & 11 deletions src/main/java/io/github/misode/packtest/commands/FailCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.ContextChain;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.github.misode.packtest.PackTestLibrary;
import io.github.misode.packtest.PackTestSourceStack;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.ComponentArgument;
import net.minecraft.commands.execution.ChainModifiers;
import net.minecraft.commands.execution.CustomCommandExecutor;
import net.minecraft.commands.execution.ExecutionControl;
import net.minecraft.commands.execution.Frame;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentUtils;

Expand All @@ -29,17 +30,18 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
static class FailCustomExecutor implements CustomCommandExecutor.CommandAdapter<CommandSourceStack> {
public void run(CommandSourceStack sourceStack, ContextChain<CommandSourceStack> chain, ChainModifiers modifiers, ExecutionControl<CommandSourceStack> execution) {
CommandContext<CommandSourceStack> ctx = chain.getTopContext().copyFor(sourceStack);
PackTestLibrary.INSTANCE.getHelperAt(sourceStack).ifPresent(helper -> {
try {
Component message = ComponentUtils.updateForEntity(
ctx.getSource(),
ComponentArgument.getComponent(ctx, "message"),
null,
0
);
GameTestHelper helper = ((PackTestSourceStack)sourceStack).packtest$getHelper();
try {
Component message = ComponentUtils.updateForEntity(
ctx.getSource(),
ComponentArgument.getComponent(ctx, "message"),
null,
0
);
if (helper != null) {
helper.fail(message.getString());
} catch (CommandSyntaxException ignored) {}
});
}
} catch (CommandSyntaxException ignored) {}
sourceStack.callback().onFailure();
Frame frame = execution.currentFrame();
frame.returnFailure();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.ContextChain;
import io.github.misode.packtest.PackTestLibrary;
import io.github.misode.packtest.PackTestSourceStack;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.execution.ChainModifiers;
Expand All @@ -27,7 +27,10 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher, Co

static class SucceedCustomExecutor implements CustomCommandExecutor.CommandAdapter<CommandSourceStack> {
public void run(CommandSourceStack sourceStack, ContextChain<CommandSourceStack> chain, ChainModifiers modifiers, ExecutionControl<CommandSourceStack> execution) {
PackTestLibrary.INSTANCE.getHelperAt(sourceStack).ifPresent(GameTestHelper::succeed);
GameTestHelper helper = ((PackTestSourceStack)sourceStack).packtest$getHelper();
if (helper != null) {
helper.succeed();
}
sourceStack.callback().onSuccess(1);
Frame frame = execution.currentFrame();
frame.returnSuccess(1);
Expand All @@ -37,13 +40,12 @@ public void run(CommandSourceStack sourceStack, ContextChain<CommandSourceStack>

private static Command<CommandSourceStack> when(boolean expectOk, AssertCommand.AssertPredicate predicate) {
return ctx -> {
PackTestLibrary.INSTANCE.getHelperAt(ctx.getSource()).ifPresent(helper -> {
helper.succeedWhen(() -> {
predicate.apply(ctx).get(expectOk).ifPresent(message -> {
throw new GameTestAssertException(message);
});
});
});
GameTestHelper helper = ((PackTestSourceStack)ctx.getSource()).packtest$getHelper();
if (helper != null) {
helper.succeedWhen(() -> predicate.apply(ctx).get(expectOk).ifPresent(message -> {
throw new GameTestAssertException(message);
}));
}
return 1;
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import io.github.misode.packtest.PackTestSourceStack;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.gametest.framework.GameTestHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(CommandSourceStack.class)
public class CommandSourceStackMixin implements PackTestSourceStack {
@Unique
private GameTestHelper helper;

public GameTestHelper packtest$getHelper() {
return this.helper;
}

public void packtest$setHelper(GameTestHelper helper) {
this.helper = helper;
}

@ModifyReturnValue(method = "withSource", at = @At("RETURN"))
private CommandSourceStack withSource(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withEntity", at = @At("RETURN"))
private CommandSourceStack withEntity(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withPosition", at = @At("RETURN"))
private CommandSourceStack withPosition(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withRotation", at = @At("RETURN"))
private CommandSourceStack withRotation(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withCallback(Lnet/minecraft/commands/CommandResultCallback;)Lnet/minecraft/commands/CommandSourceStack;", at = @At("RETURN"))
private CommandSourceStack withCallback(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withSuppressedOutput", at = @At("RETURN"))
private CommandSourceStack withSuppressedOutput(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withPermission", at = @At("RETURN"))
private CommandSourceStack withPermission(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withMaximumPermission", at = @At("RETURN"))
private CommandSourceStack withMaximumPermission(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withAnchor", at = @At("RETURN"))
private CommandSourceStack withAnchor(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withLevel", at = @At("RETURN"))
private CommandSourceStack withLevel(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}

@ModifyReturnValue(method = "withSigningContext", at = @At("RETURN"))
private CommandSourceStack withSigningContext(CommandSourceStack original) {
((CommandSourceStackMixin)(Object)original).helper = this.helper;
return original;
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,16 @@
package io.github.misode.packtest.mixin;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import io.github.misode.packtest.PackTestLibrary;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.gametest.framework.GameTestInfo;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

/**
* Registers the {@link GameTestHelper} for each test so custom commands can access it.
* Prevents crash when test has already started.
*/
@Mixin(GameTestInfo.class)
public abstract class GameTestInfoMixin {
@Shadow
public String getTestName() {
throw new AssertionError("Nope.");
}

@ModifyExpressionValue(method = "startTest", at = @At(value="NEW", target = "(Lnet/minecraft/gametest/framework/GameTestInfo;)Lnet/minecraft/gametest/framework/GameTestHelper;"))
private GameTestHelper createHelper(GameTestHelper helper) {
PackTestLibrary.INSTANCE.registerTestHelper(this.getTestName(), helper);
return helper;
}

@Inject(method = "finish", at = @At("HEAD"))
private void finish(CallbackInfo ci) {
PackTestLibrary.INSTANCE.unregisterTestHelper(this.getTestName());
}

@Inject(method = "startTest", cancellable = true, at = @At(value = "INVOKE", target = "Ljava/lang/IllegalStateException;<init>(Ljava/lang/String;)V"))
private void startTest(CallbackInfo ci) {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/packtest.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"BlockPredicateArgumentMixin",
"BlockPredicateArgumentTagMixin",
"CommandsMixin",
"CommandSourceStackMixin",
"EntityArgumentMixin",
"EntitySelectorMixin",
"GameTestBatchMixin",
Expand Down

0 comments on commit fec042e

Please sign in to comment.