diff --git a/patches/net/minecraft/server/Main.java.patch b/patches/net/minecraft/server/Main.java.patch index e32cfe17d8..08f6bb71e1 100644 --- a/patches/net/minecraft/server/Main.java.patch +++ b/patches/net/minecraft/server/Main.java.patch @@ -85,6 +85,22 @@ } catch (NbtException | ReportedNbtException | IOException ioexception) { LOGGER.error("Failed to load world data from {}", levelstoragesource$leveldirectory.oldDataFile(), ioexception); LOGGER.error( +@@ -173,6 +_,15 @@ + + PackRepository packrepository = ServerPacksSource.createPackRepository(levelstoragesource$levelstorageaccess); + ++ if (gametestEnabled) { ++ net.neoforged.neoforge.gametest.GameTestHooks.registerGametests(); ++ net.minecraft.core.BlockPos spawnPos = optionset.valueOf(spawnPosOpt); ++ MinecraftServer.spin(thread -> net.minecraft.gametest.framework.GameTestServer.create(thread, levelstoragesource$levelstorageaccess, packrepository, net.minecraft.gametest.framework.GameTestRegistry.getAllTestFunctions(), spawnPos)); ++ // If we're running a gametest server we don't need to load the resources normally (GameTestServer#create does it using a flat world) ++ // or create a shutdown thread as the gametest server will always exit itself ++ return; ++ } ++ + WorldStem worldstem; + try { + WorldLoader.InitConfig worldloader$initconfig = loadOrCreateConfig(dedicatedserversettings.getProperties(), dynamic1, flag, packrepository); @@ -214,6 +_,9 @@ worlddimensions = dedicatedserverproperties.createDimensions(p_359487_.datapackWorldgen()); } @@ -95,48 +111,9 @@ WorldDimensions.Complete worlddimensions$complete = worlddimensions.bake(registry); Lifecycle lifecycle = worlddimensions$complete.lifecycle().add(p_359487_.datapackWorldgen().allRegistriesLifecycle()); return new WorldLoader.DataLoadOutput<>( -@@ -246,24 +_,22 @@ - - WorldData worlddata = worldstem.worldData(); - levelstoragesource$levelstorageaccess.saveDataTag(registryaccess$frozen, worlddata); -- final DedicatedServer dedicatedserver = MinecraftServer.spin( -+ final MinecraftServer dedicatedserver = MinecraftServer.spin( - p_293760_ -> { -- DedicatedServer dedicatedserver1 = new DedicatedServer( -- p_293760_, -- levelstoragesource$levelstorageaccess, -- packrepository, -- worldstem, -- dedicatedserversettings, -- DataFixers.getDataFixer(), -- services, -- LoggerChunkProgressListener::createFromGameruleRadius -- ); -+ MinecraftServer dedicatedserver1; -+ if (gametestEnabled) { -+ net.neoforged.neoforge.gametest.GameTestHooks.registerGametests(); -+ net.minecraft.core.BlockPos spawnPos = optionset.valueOf(spawnPosOpt); -+ dedicatedserver1 = net.minecraft.gametest.framework.GameTestServer.create(p_293760_, levelstoragesource$levelstorageaccess, packrepository, net.minecraft.gametest.framework.GameTestRegistry.getAllTestFunctions(), spawnPos); -+ } else { -+ dedicatedserver1 = new DedicatedServer(p_293760_, levelstoragesource$levelstorageaccess, packrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::createFromGameruleRadius); -+ } - dedicatedserver1.setPort(optionset.valueOf(optionspec11)); - dedicatedserver1.setDemo(optionset.has(optionspec2)); - dedicatedserver1.setId(optionset.valueOf(optionspec12)); - boolean flag2 = !optionset.has(optionspec) && !optionset.valuesOf(optionspec15).contains("nogui"); -- if (flag2 && !GraphicsEnvironment.isHeadless()) { -- dedicatedserver1.showGui(); -+ if (dedicatedserver1 instanceof DedicatedServer dedicatedServer && flag2 && !GraphicsEnvironment.isHeadless()) { -+ dedicatedServer.showGui(); - } - - return dedicatedserver1; -@@ -272,7 +_,10 @@ - Thread thread = new Thread("Server Shutdown Thread") { +@@ -273,6 +_,7 @@ @Override public void run() { -+ // FORGE: Halting as GameTestServer will cause issues as it always calls System#exit on both crash and normal exit, so skip it -+ if (!(dedicatedserver instanceof net.minecraft.gametest.framework.GameTestServer)) dedicatedserver.halt(true); + org.apache.logging.log4j.LogManager.shutdown(); // we're manually managing the logging shutdown on the server. Make sure we do it here at the end. } diff --git a/tests/src/generated/resources/data/neotests_reloadable_reg_data_maps/data_maps/loot_table/effect_grant.json b/tests/src/generated/resources/data/neotests_reloadable_reg_data_maps/data_maps/loot_table/effect_grant.json new file mode 100644 index 0000000000..ff7693fcb2 --- /dev/null +++ b/tests/src/generated/resources/data/neotests_reloadable_reg_data_maps/data_maps/loot_table/effect_grant.json @@ -0,0 +1,9 @@ +{ + "values": { + "minecraft:blocks/copper_block": { + "duration": 100, + "id": "minecraft:nausea", + "show_icon": true + } + } +} \ No newline at end of file diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java index 2e4bf42bd9..ca5d9c6658 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/data/DataMapTests.java @@ -33,6 +33,8 @@ import net.minecraft.world.InteractionHand; import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.HoneycombItem; import net.minecraft.world.item.Item; @@ -43,12 +45,14 @@ import net.minecraft.world.level.block.WeatheringCopper; import net.minecraft.world.level.block.WeatheringCopperFullBlock; import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.storage.loot.LootTable; import net.neoforged.neoforge.common.DataMapHooks; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.data.DataMapProvider; import net.neoforged.neoforge.debug.EventTests; import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.player.UseItemOnBlockEvent; +import net.neoforged.neoforge.event.level.BlockEvent; import net.neoforged.neoforge.registries.datamaps.AdvancedDataMapType; import net.neoforged.neoforge.registries.datamaps.DataMapType; import net.neoforged.neoforge.registries.datamaps.DataMapValueMerger; @@ -302,6 +306,40 @@ protected void gather(HolderLookup.Provider provider) { }); } + @GameTest + @EmptyTemplate + @TestHolder(description = "Tests if data maps can be successfully attached to reloadable registries") + static void reloadableRegDataMaps(final DynamicTest test, final RegistrationHelper reg) { + final DataMapType effectGrant = reg.registerDataMap(DataMapType.builder( + ResourceLocation.fromNamespaceAndPath(reg.modId(), "effect_grant"), + Registries.LOOT_TABLE, MobEffectInstance.CODEC) + .build()); + + reg.addProvider(event -> new DataMapProvider(event.getGenerator().getPackOutput(), event.getLookupProvider()) { + @Override + protected void gather(HolderLookup.Provider provider) { + builder(effectGrant) + .add(Blocks.COPPER_BLOCK.getLootTable().orElseThrow(), new MobEffectInstance(MobEffects.CONFUSION, 100), false); + } + }); + + test.eventListeners().forge().addListener((final BlockEvent.EntityPlaceEvent event) -> { + var table = event.getPlacedBlock().getBlock().getLootTable(); + if (table.isEmpty()) return; + final var grant = event.getLevel().getServer().reloadableRegistries().lookup().lookupOrThrow(Registries.LOOT_TABLE).getOrThrow(table.get()).getData(effectGrant); + if (grant != null && event.getEntity() instanceof Player player) { + player.addEffect(grant); + } + }); + + test.onGameTest(helper -> { + final Player player = helper.makeMockPlayer(); + helper.useBlock(new BlockPos(0, 1, 0), player, Blocks.COPPER_BLOCK.asItem().getDefaultInstance()); + helper.assertMobEffectPresent(player, MobEffects.CONFUSION, "has confusion"); + helper.succeed(); + }); + } + @GameTest @EmptyTemplate @TestHolder(description = "Tests if custom compostables work")