package net.minecraft.gametest.framework; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.Arrays; import java.util.List; import java.util.Optional; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.functions.CommandFunction; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.TestEnvironmentDefinition.SetGameRules.Entry; import net.minecraft.gametest.framework.TestEnvironmentDefinition.Weather.Type; import net.minecraft.resources.RegistryFileCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerFunctionManager; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.ExtraCodecs; import net.minecraft.world.level.GameRules; import org.slf4j.Logger; public interface TestEnvironmentDefinition { Codec DIRECT_CODEC = BuiltInRegistries.TEST_ENVIRONMENT_DEFINITION_TYPE .byNameCodec() .dispatch(TestEnvironmentDefinition::codec, mapCodec -> mapCodec); Codec> CODEC = RegistryFileCodec.create(Registries.TEST_ENVIRONMENT, DIRECT_CODEC); static MapCodec bootstrap(Registry> registry) { Registry.register(registry, "all_of", TestEnvironmentDefinition.AllOf.CODEC); Registry.register(registry, "game_rules", TestEnvironmentDefinition.SetGameRules.CODEC); Registry.register(registry, "time_of_day", TestEnvironmentDefinition.TimeOfDay.CODEC); Registry.register(registry, "weather", TestEnvironmentDefinition.Weather.CODEC); return Registry.register(registry, "function", TestEnvironmentDefinition.Functions.CODEC); } void setup(ServerLevel level); default void teardown(ServerLevel level) { } MapCodec codec(); public record AllOf(List> definitions) implements TestEnvironmentDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group(TestEnvironmentDefinition.CODEC.listOf().fieldOf("definitions").forGetter(TestEnvironmentDefinition.AllOf::definitions)) .apply(instance, TestEnvironmentDefinition.AllOf::new) ); public AllOf(TestEnvironmentDefinition... definitons) { this(Arrays.stream(definitons).map(Holder::direct).toList()); } @Override public void setup(ServerLevel level) { this.definitions.forEach(holder -> ((TestEnvironmentDefinition)holder.value()).setup(level)); } @Override public void teardown(ServerLevel level) { this.definitions.forEach(holder -> ((TestEnvironmentDefinition)holder.value()).teardown(level)); } @Override public MapCodec codec() { return CODEC; } } public record Functions(Optional setupFunction, Optional teardownFunction) implements TestEnvironmentDefinition { private static final Logger LOGGER = LogUtils.getLogger(); public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( ResourceLocation.CODEC.optionalFieldOf("setup").forGetter(TestEnvironmentDefinition.Functions::setupFunction), ResourceLocation.CODEC.optionalFieldOf("teardown").forGetter(TestEnvironmentDefinition.Functions::teardownFunction) ) .apply(instance, TestEnvironmentDefinition.Functions::new) ); @Override public void setup(ServerLevel level) { this.setupFunction.ifPresent(resourceLocation -> run(level, resourceLocation)); } @Override public void teardown(ServerLevel level) { this.teardownFunction.ifPresent(resourceLocation -> run(level, resourceLocation)); } private static void run(ServerLevel level, ResourceLocation function) { MinecraftServer minecraftServer = level.getServer(); ServerFunctionManager serverFunctionManager = minecraftServer.getFunctions(); Optional> optional = serverFunctionManager.get(function); if (optional.isPresent()) { CommandSourceStack commandSourceStack = minecraftServer.createCommandSourceStack().withPermission(2).withSuppressedOutput().withLevel(level); serverFunctionManager.execute((CommandFunction)optional.get(), commandSourceStack); } else { LOGGER.error("Test Batch failed for non-existent function {}", function); } } @Override public MapCodec codec() { return CODEC; } } public record SetGameRules(List> boolRules, List> intRules) implements TestEnvironmentDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( Entry.codec(GameRules.BooleanValue.class, Codec.BOOL).listOf().fieldOf("bool_rules").forGetter(TestEnvironmentDefinition.SetGameRules::boolRules), Entry.codec(GameRules.IntegerValue.class, Codec.INT).listOf().fieldOf("int_rules").forGetter(TestEnvironmentDefinition.SetGameRules::intRules) ) .apply(instance, TestEnvironmentDefinition.SetGameRules::new) ); @Override public void setup(ServerLevel level) { GameRules gameRules = level.getGameRules(); MinecraftServer minecraftServer = level.getServer(); for (Entry entry : this.boolRules) { gameRules.getRule(entry.key()).set((Boolean)entry.value(), minecraftServer); } for (Entry entry : this.intRules) { gameRules.getRule(entry.key()).set((Integer)entry.value(), minecraftServer); } } @Override public void teardown(ServerLevel level) { GameRules gameRules = level.getGameRules(); MinecraftServer minecraftServer = level.getServer(); for (Entry entry : this.boolRules) { gameRules.getRule(entry.key()).setFrom(GameRules.getType(entry.key()).createRule(), minecraftServer); } for (Entry entry : this.intRules) { gameRules.getRule(entry.key()).setFrom(GameRules.getType(entry.key()).createRule(), minecraftServer); } } @Override public MapCodec codec() { return CODEC; } public static > Entry entry(GameRules.Key key, S value) { return new Entry(key, value); } } public record TimeOfDay(int time) implements TestEnvironmentDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group(ExtraCodecs.NON_NEGATIVE_INT.fieldOf("time").forGetter(TestEnvironmentDefinition.TimeOfDay::time)) .apply(instance, TestEnvironmentDefinition.TimeOfDay::new) ); @Override public void setup(ServerLevel level) { level.setDayTime(this.time); } @Override public MapCodec codec() { return CODEC; } } public record Weather(Type weather) implements TestEnvironmentDefinition { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group(Type.CODEC.fieldOf("weather").forGetter(TestEnvironmentDefinition.Weather::weather)) .apply(instance, TestEnvironmentDefinition.Weather::new) ); @Override public void setup(ServerLevel level) { this.weather.apply(level); } @Override public void teardown(ServerLevel level) { level.resetWeatherCycle(); } @Override public MapCodec codec() { return CODEC; } } }