From f74e9f301e03933712267a1e42dfe493173ed2b5 Mon Sep 17 00:00:00 2001 From: MulverineX Date: Wed, 7 Oct 2026 17:53:08 -0600 Subject: [PATCH] Fix #25 --- .../io/github/misode/packtest/PackTest.java | 12 +++ .../misode/packtest/PackTestExecutor.java | 11 ++- .../misode/packtest/PackTestLibrary.java | 84 +++++++------------ .../mixin/ReloadableServerResourcesMixin.java | 56 ------------- src/main/resources/packtest.mixins.json | 1 - 5 files changed, 50 insertions(+), 114 deletions(-) delete mode 100644 src/main/java/io/github/misode/packtest/mixin/ReloadableServerResourcesMixin.java diff --git a/src/main/java/io/github/misode/packtest/PackTest.java b/src/main/java/io/github/misode/packtest/PackTest.java index aec828a..2199dd9 100644 --- a/src/main/java/io/github/misode/packtest/PackTest.java +++ b/src/main/java/io/github/misode/packtest/PackTest.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.util.FileUtil; import net.minecraft.util.Util; import net.minecraft.commands.CommandBuildContext; @@ -56,8 +57,19 @@ public void onInitialize() { CommandRegistrationCallback.EVENT.register((dispatcher, buildContext, environment) -> registerCommands(dispatcher, buildContext) ); + ServerLifecycleEvents.SERVER_STARTED.register(server -> + server.execute(() -> loadTests(server))); + ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, resourceManager, success) -> { + if (success) { + server.execute(() -> loadTests(server)); + } + }); } + private static void loadTests(net.minecraft.server.MinecraftServer server) { + new PackTestLibrary(server.registryAccess()).load(server); + } + public static void generateCommandsReport() { Path path = Paths.get("generated", "reports", "commands.json"); CommandDispatcher dispatcher = new CommandDispatcher<>(); diff --git a/src/main/java/io/github/misode/packtest/PackTestExecutor.java b/src/main/java/io/github/misode/packtest/PackTestExecutor.java index 3f2f3e5..c71731a 100644 --- a/src/main/java/io/github/misode/packtest/PackTestExecutor.java +++ b/src/main/java/io/github/misode/packtest/PackTestExecutor.java @@ -5,6 +5,7 @@ import io.github.misode.packtest.commands.assertions.AssertResult; import io.github.misode.packtest.dummy.Dummy; import net.minecraft.commands.CommandResultCallback; +import net.minecraft.commands.CommandSource; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.coordinates.Coordinates; @@ -15,6 +16,7 @@ import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -24,6 +26,13 @@ public class PackTestExecutor { private static final SimpleCommandExceptionType ERROR_NOT_IN_TEST = new SimpleCommandExceptionType( Component.literal("Command can only be used inside a test")); + private static final CommandSource SILENT_SOURCE = new CommandSource() { + @Override public void sendSystemMessage(@NonNull Component message) {} + @Override public boolean acceptsSuccess() { return true; } + @Override public boolean acceptsFailure() { return true; } + @Override public boolean shouldInformAdmins() { return false; } + @Override public boolean alwaysAccepts() { return true; } + }; private static @Nullable PackTestExecutor current; private final List> awaits = new ArrayList<>(); @@ -78,7 +87,7 @@ private CommandSourceStack createCommandSourceStack(PackTestFunction function) { CommandSourceStack source = helper.getLevel().getServer().createCommandSourceStack() .withLevel(helper.getLevel()) .withPosition(helper.absoluteVec(Vec3.ZERO)) - .withSuppressedOutput(); + .withSource(SILENT_SOURCE); Optional coordinates = function.directives().dummy(); if (coordinates.isPresent()) { diff --git a/src/main/java/io/github/misode/packtest/PackTestLibrary.java b/src/main/java/io/github/misode/packtest/PackTestLibrary.java index 6d52740..a48194a 100644 --- a/src/main/java/io/github/misode/packtest/PackTestLibrary.java +++ b/src/main/java/io/github/misode/packtest/PackTestLibrary.java @@ -1,91 +1,63 @@ package io.github.misode.packtest; -import com.google.common.collect.*; import com.mojang.brigadier.CommandDispatcher; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; import net.minecraft.core.*; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.Identifier; -import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.permissions.PermissionSet; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; -import java.util.concurrent.Executor; +import java.util.concurrent.ForkJoinPool; -public class PackTestLibrary implements PreparableReloadListener { +public class PackTestLibrary { private static final FileToIdConverter LISTER = new FileToIdConverter("test", ".mcfunction"); + private static final Map LOADED = new HashMap<>(); + private final PackTestRegistries registries; - private final PermissionSet testCompilationPermissions; - private final CommandDispatcher dispatcher; - public PackTestLibrary( - HolderLookup.Provider registries, - PermissionSet testCompilationPermissions, - CommandDispatcher dispatcher) { + public PackTestLibrary(HolderLookup.Provider registries) { this.registries = new PackTestRegistries(registries); - this.testCompilationPermissions = testCompilationPermissions; - this.dispatcher = dispatcher; } - @Override - public @NotNull CompletableFuture reload( - @NotNull SharedState currentReload, - @NotNull Executor taskExecutor, - PreparationBarrier preparationBarrier, - @NotNull Executor reloadExecutor) { - ResourceManager manager = currentReload.resourceManager(); - CompletableFuture registryLoad = this.registries.load(manager, taskExecutor); - - CompletableFuture>> testFunctions = CompletableFuture - .supplyAsync(() -> LISTER.listMatchingResources(manager), taskExecutor) - .thenComposeAsync(map -> prepareTestFunctions(map, taskExecutor)); - - return CompletableFuture.allOf(registryLoad, testFunctions) - .thenCompose(preparationBarrier::wait) - .thenAcceptAsync((_) -> - this.registries.register(registryLoad.join(), collectTestFunctions(testFunctions.join())), - reloadExecutor); + public static @Nullable PackTestFunction getLoaded(Identifier id) { + return LOADED.get(id); } - private CompletableFuture>> prepareTestFunctions( - Map resources, - Executor taskExecutor) { - Map> result = new HashMap<>(); - CommandSourceStack compilationContext = Commands.createCompilationContext(this.testCompilationPermissions); + public void load(MinecraftServer server) { + ResourceManager manager = server.getResourceManager(); + RegistryAccess.Frozen registryLookup = this.registries + .load(manager, ForkJoinPool.commonPool()) + .join(); + CommandDispatcher dispatcher = server.getCommands().getDispatcher(); + CommandSourceStack source = server.createCommandSourceStack(); + Map resources = LISTER.listMatchingResources(manager); + Map loaded = new HashMap<>(); for (Map.Entry entry : resources.entrySet()) { Identifier id = LISTER.fileToId(entry.getKey()); - result.put(id, CompletableFuture.supplyAsync(() -> { + try { List lines = readLines(entry.getValue()); - return PackTestFunction.fromLines(this.dispatcher, compilationContext, lines); - }, taskExecutor)); - } - - return CompletableFuture.allOf(result.values().toArray(new CompletableFuture[0])).handle((_, _) -> result); - } - - private static Map collectTestFunctions(Map> futures) { - ImmutableMap.Builder result = ImmutableMap.builder(); - futures.forEach((id, future) -> future.handle((test, e) -> { - if (e == null) { - result.put(id, test); - } else { + PackTestFunction fn = PackTestFunction.fromLines(dispatcher, source, lines); + loaded.put(id, fn); + } catch (Exception e) { PackTest.LOGGER.error("Failed to load test {}", id, e); } - return null; - }).join()); - return result.build(); + } + + LOADED.clear(); + LOADED.putAll(loaded); + this.registries.register(registryLookup, loaded); + PackTest.LOGGER.info("Loaded {} test functions", loaded.size()); } private static List readLines(Resource resource) { diff --git a/src/main/java/io/github/misode/packtest/mixin/ReloadableServerResourcesMixin.java b/src/main/java/io/github/misode/packtest/mixin/ReloadableServerResourcesMixin.java deleted file mode 100644 index e9fa203..0000000 --- a/src/main/java/io/github/misode/packtest/mixin/ReloadableServerResourcesMixin.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.misode.packtest.mixin; - -import com.llamalad7.mixinextras.injector.ModifyReturnValue; -import io.github.misode.packtest.PackTestLibrary; -import net.minecraft.commands.Commands; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponentInitializers; -import net.minecraft.server.ReloadableServerRegistries; -import net.minecraft.server.ReloadableServerResources; -import net.minecraft.server.packs.resources.PreparableReloadListener; -import net.minecraft.server.permissions.PermissionSet; -import net.minecraft.world.flag.FeatureFlagSet; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -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.ArrayList; -import java.util.List; - -/** - * Adds {@link PackTestLibrary} to the /reload listeners - */ -@Mixin(ReloadableServerResources.class) -public class ReloadableServerResourcesMixin { - @Shadow - @Final - private Commands commands; - @Unique - private PackTestLibrary testLibrary; - - @Inject(method = "", at = @At("RETURN")) - private void init( - ReloadableServerRegistries.LoadResult loadingContext, - FeatureFlagSet enabledFeatures, - Commands.CommandSelection commandSelection, - List>> postponedTags, - PermissionSet functionCompilationPermissions, - List> newComponents, - CallbackInfo ci) { - this.testLibrary = new PackTestLibrary( - loadingContext.lookupWithUpdatedTags(), - functionCompilationPermissions, - this.commands.getDispatcher()); - } - - @ModifyReturnValue(method = "listeners", at = @At("RETURN")) - private List listeners(List list) { - List result = new ArrayList<>(list); - result.add(testLibrary); - return result; - } -} diff --git a/src/main/resources/packtest.mixins.json b/src/main/resources/packtest.mixins.json index 2e593f1..617c98b 100644 --- a/src/main/resources/packtest.mixins.json +++ b/src/main/resources/packtest.mixins.json @@ -11,7 +11,6 @@ "MappedRegistryMixin", "PackMixin", "PlayerListMixin", - "ReloadableServerResourcesMixin", "ServerFunctionLibraryMixin", "ServerPlayerMixin", "SimpleJsonResourceReloadListenerMixin",