From 4d7876eda708d95893bb197bf2e8824f4a997cf4 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 18:05:05 +0100 Subject: [PATCH 01/10] Fix data provider merge issue --- .../net/minecraft/data/DataGenerator.java.patch | 14 +++++++++++++- .../neoforge/data/event/GatherDataEvent.java | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/patches/net/minecraft/data/DataGenerator.java.patch b/patches/net/minecraft/data/DataGenerator.java.patch index b1a6783a18..5f1f22f0bc 100644 --- a/patches/net/minecraft/data/DataGenerator.java.patch +++ b/patches/net/minecraft/data/DataGenerator.java.patch @@ -16,7 +16,7 @@ stopwatch1.start(); hashcache.applyUpdate(hashcache.generateUpdate(p_254418_, p_253750_::run).join()); stopwatch1.stop(); -@@ -56,6 +_,34 @@ +@@ -56,6 +_,46 @@ public DataGenerator.PackGenerator getBuiltinDatapack(boolean p_253826_, String p_254134_) { Path path = this.vanillaPackOutput.getOutputFolder(PackOutput.Target.DATA_PACK).resolve("minecraft").resolve("datapacks").resolve(p_254134_); return new DataGenerator.PackGenerator(p_253826_, p_254134_, new PackOutput(path)); @@ -48,6 +48,18 @@ + DataGenerator.this.providersToRun.put(id, provider); + + return provider; ++ } ++ ++ public void merge(DataGenerator other) { ++ other.providersToRun.forEach((id, provider) -> { ++ if(!allProviderIds.add(id)) ++ throw new IllegalStateException("Duplicate provider: " + id); ++ ++ providersToRun.put(id, provider); ++ }); ++ ++ other.providersToRun.clear(); ++ other.allProviderIds.clear(); } static { diff --git a/src/main/java/net/neoforged/neoforge/data/event/GatherDataEvent.java b/src/main/java/net/neoforged/neoforge/data/event/GatherDataEvent.java index 7ae69bf146..64bb7a0b75 100644 --- a/src/main/java/net/neoforged/neoforge/data/event/GatherDataEvent.java +++ b/src/main/java/net/neoforged/neoforge/data/event/GatherDataEvent.java @@ -130,7 +130,7 @@ public void runAll() { paths.values().forEach(lst -> { DataGenerator parent = lst.get(0); for (int x = 1; x < lst.size(); x++) - lst.get(x).getProvidersView().forEach((name, provider) -> parent.addProvider(true, provider)); + parent.merge(lst.get(x)); try { parent.run(); } catch (IOException ex) { From 04fba14480e149f372568ebbaf08e3ed1405b3e6 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 18:05:45 +0100 Subject: [PATCH 02/10] Add helper for generating mod builtin packs --- patches/net/minecraft/data/DataGenerator.java.patch | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/patches/net/minecraft/data/DataGenerator.java.patch b/patches/net/minecraft/data/DataGenerator.java.patch index 5f1f22f0bc..58bccf1011 100644 --- a/patches/net/minecraft/data/DataGenerator.java.patch +++ b/patches/net/minecraft/data/DataGenerator.java.patch @@ -16,12 +16,17 @@ stopwatch1.start(); hashcache.applyUpdate(hashcache.generateUpdate(p_254418_, p_253750_::run).join()); stopwatch1.stop(); -@@ -56,6 +_,46 @@ +@@ -56,6 +_,51 @@ public DataGenerator.PackGenerator getBuiltinDatapack(boolean p_253826_, String p_254134_) { Path path = this.vanillaPackOutput.getOutputFolder(PackOutput.Target.DATA_PACK).resolve("minecraft").resolve("datapacks").resolve(p_254134_); return new DataGenerator.PackGenerator(p_253826_, p_254134_, new PackOutput(path)); + } + ++ public PackGenerator getBuiltinDatapack(boolean run, String namespace, String path) { ++ var packPath = vanillaPackOutput.getOutputFolder(PackOutput.Target.DATA_PACK).resolve(namespace).resolve("datapacks").resolve(path); ++ return new PackGenerator(run, namespace + '_' + path, new PackOutput(packPath)); ++ } ++ + public Map getProvidersView() { + return this.providersView; + } From 2f3ee0781ddf25a61454223cd78de1cf84cee28a Mon Sep 17 00:00:00 2001 From: Apex Date: Sat, 22 Jun 2024 21:54:55 +0100 Subject: [PATCH 03/10] Initial implementation --- .../world/flag/FeatureFlags.java.patch | 18 +++++++++++ .../neoforge/common/NeoForgeMod.java | 30 +++++++++++++++++++ .../resources/assets/neoforge/lang/en_us.json | 1 + .../datapacks/mod_experimental/pack.mcmeta | 13 ++++++++ 4 files changed, 62 insertions(+) create mode 100644 patches/net/minecraft/world/flag/FeatureFlags.java.patch create mode 100644 src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta diff --git a/patches/net/minecraft/world/flag/FeatureFlags.java.patch b/patches/net/minecraft/world/flag/FeatureFlags.java.patch new file mode 100644 index 0000000000..0c24418200 --- /dev/null +++ b/patches/net/minecraft/world/flag/FeatureFlags.java.patch @@ -0,0 +1,18 @@ +--- a/net/minecraft/world/flag/FeatureFlags.java ++++ b/net/minecraft/world/flag/FeatureFlags.java +@@ -13,6 +_,7 @@ + public static final Codec CODEC; + public static final FeatureFlagSet VANILLA_SET; + public static final FeatureFlagSet DEFAULT_FLAGS; ++ public static final FeatureFlag MOD_EXPERIMENTAL; + + public static String printMissingFlags(FeatureFlagSet p_250581_, FeatureFlagSet p_250326_) { + return printMissingFlags(REGISTRY, p_250581_, p_250326_); +@@ -33,6 +_,7 @@ + VANILLA = featureflagregistry$builder.createVanilla("vanilla"); + BUNDLE = featureflagregistry$builder.createVanilla("bundle"); + TRADE_REBALANCE = featureflagregistry$builder.createVanilla("trade_rebalance"); ++ MOD_EXPERIMENTAL = featureflagregistry$builder.create(ResourceLocation.fromNamespaceAndPath("neoforge", "mod_experimental")); + REGISTRY = featureflagregistry$builder.build(); + CODEC = REGISTRY.codec(); + VANILLA_SET = FeatureFlagSet.of(VANILLA); diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index 71861b234a..48d203b7d9 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -38,8 +38,15 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackLocationInfo; +import net.minecraft.server.packs.PackSelectionConfig; import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.PathPackResources; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; +import net.minecraft.server.packs.repository.BuiltInPackSource; +import net.minecraft.server.packs.repository.KnownPack; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.PackSource; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.InclusiveRange; @@ -136,6 +143,7 @@ import net.neoforged.neoforge.common.world.StructureModifier; import net.neoforged.neoforge.common.world.StructureModifiers; import net.neoforged.neoforge.data.event.GatherDataEvent; +import net.neoforged.neoforge.event.AddPackFindersEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent; import net.neoforged.neoforge.fluids.BaseFlowingFluid; import net.neoforged.neoforge.fluids.CauldronFluidContent; @@ -630,6 +638,28 @@ public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) { modEventBus.register(NeoForgeDataMaps.class); + modEventBus.addListener(AddPackFindersEvent.class, event -> { + if (event.getPackType() != PackType.SERVER_DATA) { + return; + } + + var modInfo = container.getModInfo(); + var resource = modInfo.getOwningFile().getFile().findResource("data/neoforge/datapacks/mod_experimental"); + var version = modInfo.getVersion(); + + var pack = Pack.readMetaAndCreate( + new PackLocationInfo( + "neoforge:mod_experimental", + Component.translatable("pack.neoforge.experiments.description"), + PackSource.FEATURE, + Optional.of(new KnownPack("neoforge", "mod_experimental", version.toString()))), + BuiltInPackSource.fromName(path -> new PathPackResources(path, resource)), + PackType.SERVER_DATA, + new PackSelectionConfig(false, Pack.Position.BOTTOM, true)); + + event.addRepositorySource(consumer -> consumer.accept(pack)); + }); + if (isPRBuild(container.getModInfo().getVersion().toString())) { isPRBuild = true; ModLoader.addLoadingIssue(ModLoadingIssue.warning("loadwarning.neoforge.prbuild").withAffectedMod(container.getModInfo())); diff --git a/src/main/resources/assets/neoforge/lang/en_us.json b/src/main/resources/assets/neoforge/lang/en_us.json index cc81b475d8..357d07dc6e 100644 --- a/src/main/resources/assets/neoforge/lang/en_us.json +++ b/src/main/resources/assets/neoforge/lang/en_us.json @@ -194,6 +194,7 @@ "neoforge.chatType.system": "%1$s", "pack.neoforge.description": "NeoForge data/resource pack", + "pack.neoforge.experimental.description": "NeoForge mod experiments data pack", "pack.neoforge.source.child": "child", "neoforge.network.negotiation.failure.mod": "Channel of mod \"%1$s\" failed to connect: %2$s", diff --git a/src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta b/src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta new file mode 100644 index 0000000000..0b8d3cd184 --- /dev/null +++ b/src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta @@ -0,0 +1,13 @@ +{ + "features": { + "enabled": [ + "neoforge:mod_experimental" + ] + }, + "pack": { + "description": { + "translate": "pack.neoforge.experimental.description" + }, + "pack_format": 48 + } +} \ No newline at end of file From c767412adab8fa30c197dd97b1ac9d1c02a74a36 Mon Sep 17 00:00:00 2001 From: Apex Date: Sat, 22 Jun 2024 22:23:28 +0100 Subject: [PATCH 04/10] Clean up packfinder code --- .../neoforge/common/NeoForgeMod.java | 33 ++++--------------- .../resources/assets/neoforge/lang/en_us.json | 3 +- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index 48d203b7d9..600c9164b6 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -38,13 +38,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.PackLocationInfo; -import net.minecraft.server.packs.PackSelectionConfig; import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.PathPackResources; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; -import net.minecraft.server.packs.repository.BuiltInPackSource; -import net.minecraft.server.packs.repository.KnownPack; import net.minecraft.server.packs.repository.Pack; import net.minecraft.server.packs.repository.PackSource; import net.minecraft.sounds.SoundEvent; @@ -638,27 +633,13 @@ public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) { modEventBus.register(NeoForgeDataMaps.class); - modEventBus.addListener(AddPackFindersEvent.class, event -> { - if (event.getPackType() != PackType.SERVER_DATA) { - return; - } - - var modInfo = container.getModInfo(); - var resource = modInfo.getOwningFile().getFile().findResource("data/neoforge/datapacks/mod_experimental"); - var version = modInfo.getVersion(); - - var pack = Pack.readMetaAndCreate( - new PackLocationInfo( - "neoforge:mod_experimental", - Component.translatable("pack.neoforge.experiments.description"), - PackSource.FEATURE, - Optional.of(new KnownPack("neoforge", "mod_experimental", version.toString()))), - BuiltInPackSource.fromName(path -> new PathPackResources(path, resource)), - PackType.SERVER_DATA, - new PackSelectionConfig(false, Pack.Position.BOTTOM, true)); - - event.addRepositorySource(consumer -> consumer.accept(pack)); - }); + modEventBus.addListener(AddPackFindersEvent.class, event -> event.addPackFinders( + ResourceLocation.fromNamespaceAndPath("neoforge", "data/neoforge/datapacks/mod_experimental"), + PackType.SERVER_DATA, + Component.translatable("pack.neoforge.experimental.name"), + PackSource.FEATURE, + false, + Pack.Position.BOTTOM)); if (isPRBuild(container.getModInfo().getVersion().toString())) { isPRBuild = true; diff --git a/src/main/resources/assets/neoforge/lang/en_us.json b/src/main/resources/assets/neoforge/lang/en_us.json index 357d07dc6e..ab51b53037 100644 --- a/src/main/resources/assets/neoforge/lang/en_us.json +++ b/src/main/resources/assets/neoforge/lang/en_us.json @@ -194,7 +194,8 @@ "neoforge.chatType.system": "%1$s", "pack.neoforge.description": "NeoForge data/resource pack", - "pack.neoforge.experimental.description": "NeoForge mod experiments data pack", + "pack.neoforge.experimental.name": "NeoForge mod experiments data pack", + "pack.neoforge.experimental.description": "Enables experimental mod items", "pack.neoforge.source.child": "child", "neoforge.network.negotiation.failure.mod": "Channel of mod \"%1$s\" failed to connect: %2$s", From 2ca5e54ab754476ab9c8368b686b10977c434c56 Mon Sep 17 00:00:00 2001 From: Apex Date: Sat, 22 Jun 2024 22:31:45 +0100 Subject: [PATCH 05/10] Add data provider for experiments DP --- .../datapacks/mod_experimental/pack.mcmeta | 6 +++- .../neoforge/common/NeoForgeMod.java | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) rename src/{main => generated}/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta (69%) diff --git a/src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta b/src/generated/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta similarity index 69% rename from src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta rename to src/generated/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta index 0b8d3cd184..032418bba8 100644 --- a/src/main/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta +++ b/src/generated/resources/data/neoforge/datapacks/mod_experimental/pack.mcmeta @@ -8,6 +8,10 @@ "description": { "translate": "pack.neoforge.experimental.description" }, - "pack_format": 48 + "pack_format": 48, + "supported_formats": [ + 0, + 2147483647 + ] } } \ No newline at end of file diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index 600c9164b6..9f1000d3e6 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -5,6 +5,7 @@ package net.neoforged.neoforge.common; +import com.google.gson.JsonObject; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; @@ -32,12 +33,15 @@ import net.minecraft.core.RegistryCodecs; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.Registries; +import net.minecraft.data.CachedOutput; import net.minecraft.data.DataGenerator; +import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.metadata.PackMetadataGenerator; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.FeatureFlagsMetadataSection; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; import net.minecraft.server.packs.repository.Pack; @@ -54,6 +58,8 @@ import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.item.Items; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockGetter; @@ -686,6 +692,33 @@ public void gatherData(GatherDataEvent event) { gen.addProvider(event.includeClient(), new NeoForgeSpriteSourceProvider(packOutput, lookupProvider, existingFileHelper)); gen.addProvider(event.includeClient(), new VanillaSoundDefinitionsProvider(packOutput, existingFileHelper)); gen.addProvider(event.includeClient(), new NeoForgeLanguageProvider(packOutput)); + + // mod experimental pack + // custom impl since using PackMetadataGenerator throws "duplicate provider" (getName() is final which is used for provider id) + gen.addProvider(true, new DataProvider() { + @Override + public CompletableFuture run(CachedOutput cache) { + var json = new JsonObject(); + + json.add(PackMetadataSection.TYPE.getMetadataSectionName(), PackMetadataSection.TYPE.toJson(new PackMetadataSection( + Component.translatable("pack.neoforge.experimental.description"), + DetectedVersion.BUILT_IN.getPackVersion(PackType.SERVER_DATA), + Optional.of(new InclusiveRange<>(0, Integer.MAX_VALUE))))); + + json.add(FeatureFlagsMetadataSection.TYPE.getMetadataSectionName(), FeatureFlagsMetadataSection.TYPE.toJson(new FeatureFlagsMetadataSection(FeatureFlagSet.of(FeatureFlags.MOD_EXPERIMENTAL)))); + + return DataProvider.saveStable(cache, json, packOutput.getOutputFolder(PackOutput.Target.DATA_PACK) + .resolve("neoforge") + .resolve("datapacks") + .resolve("mod_experimental") + .resolve("pack.mcmeta")); + } + + @Override + public String getName() { + return "mod_experimental_pack"; + } + }); } // done in an event instead of deferred to only enable if a mod requests it From b3e254d02cad75cac1568c09041fd67d14edad67 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 17:49:05 +0100 Subject: [PATCH 06/10] Add documentation to FeatureFlags.MOD_EXPERIMENTAL --- .../minecraft/world/flag/FeatureFlags.java.patch | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/patches/net/minecraft/world/flag/FeatureFlags.java.patch b/patches/net/minecraft/world/flag/FeatureFlags.java.patch index 0c24418200..eaf12e2c5e 100644 --- a/patches/net/minecraft/world/flag/FeatureFlags.java.patch +++ b/patches/net/minecraft/world/flag/FeatureFlags.java.patch @@ -1,9 +1,22 @@ --- a/net/minecraft/world/flag/FeatureFlags.java +++ b/net/minecraft/world/flag/FeatureFlags.java -@@ -13,6 +_,7 @@ +@@ -13,6 +_,20 @@ public static final Codec CODEC; public static final FeatureFlagSet VANILLA_SET; public static final FeatureFlagSet DEFAULT_FLAGS; ++ /** ++ * A feature flag for use with experimental features that may introduce unexpected or potentially bug-inducing behaviors.
++ * Unlike the standard set of flags, which can change frequently, this flag remains consistent across major version updates.
++ *

++ * Modders can reference this flag during built-in feature registration.
++ * However, they must provide their own flagged datapacks to associate datapack features (such as recipes and enchantments) with this flag.
++ * These datapacks can be provided either as optional files or via the {@linkplain net.neoforged.neoforge.event.AddPackFindersEvent} event. ++ *

++ *

++ * It is highly recommended that modders document which features are experimental and which ones are not.
++ * Due to the nature of this flag being a ‘catch-all’, it enables any and all modded experiments that may exist. ++ *

++ */ + public static final FeatureFlag MOD_EXPERIMENTAL; public static String printMissingFlags(FeatureFlagSet p_250581_, FeatureFlagSet p_250326_) { From 6a03141fade71125966ea1e892d2081b90407731 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 17:49:30 +0100 Subject: [PATCH 07/10] Update en_us.json --- src/main/resources/assets/neoforge/lang/en_us.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/neoforge/lang/en_us.json b/src/main/resources/assets/neoforge/lang/en_us.json index ab51b53037..b3b439aa90 100644 --- a/src/main/resources/assets/neoforge/lang/en_us.json +++ b/src/main/resources/assets/neoforge/lang/en_us.json @@ -194,8 +194,8 @@ "neoforge.chatType.system": "%1$s", "pack.neoforge.description": "NeoForge data/resource pack", - "pack.neoforge.experimental.name": "NeoForge mod experiments data pack", - "pack.neoforge.experimental.description": "Enables experimental mod items", + "pack.neoforge.experimental.name": "Experimental mod features", + "pack.neoforge.experimental.description": "Enables mod provided experimental features", "pack.neoforge.source.child": "child", "neoforge.network.negotiation.failure.mod": "Channel of mod \"%1$s\" failed to connect: %2$s", From 5f08bf8a17d211a34422bf044875aa3fed2b9fd7 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 18:17:54 +0100 Subject: [PATCH 08/10] Clean up data gen code --- .../neoforge/common/NeoForgeMod.java | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index 9f1000d3e6..cc96ba7b06 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -5,7 +5,6 @@ package net.neoforged.neoforge.common; -import com.google.gson.JsonObject; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; @@ -33,9 +32,7 @@ import net.minecraft.core.RegistryCodecs; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.core.registries.Registries; -import net.minecraft.data.CachedOutput; import net.minecraft.data.DataGenerator; -import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.metadata.PackMetadataGenerator; import net.minecraft.network.chat.Component; @@ -694,31 +691,12 @@ public void gatherData(GatherDataEvent event) { gen.addProvider(event.includeClient(), new NeoForgeLanguageProvider(packOutput)); // mod experimental pack - // custom impl since using PackMetadataGenerator throws "duplicate provider" (getName() is final which is used for provider id) - gen.addProvider(true, new DataProvider() { - @Override - public CompletableFuture run(CachedOutput cache) { - var json = new JsonObject(); - - json.add(PackMetadataSection.TYPE.getMetadataSectionName(), PackMetadataSection.TYPE.toJson(new PackMetadataSection( + gen.getBuiltinDatapack(true, NeoForgeVersion.MOD_ID, "mod_experimental").addProvider(output -> new PackMetadataGenerator(output) + .add(PackMetadataSection.TYPE, new PackMetadataSection( Component.translatable("pack.neoforge.experimental.description"), DetectedVersion.BUILT_IN.getPackVersion(PackType.SERVER_DATA), - Optional.of(new InclusiveRange<>(0, Integer.MAX_VALUE))))); - - json.add(FeatureFlagsMetadataSection.TYPE.getMetadataSectionName(), FeatureFlagsMetadataSection.TYPE.toJson(new FeatureFlagsMetadataSection(FeatureFlagSet.of(FeatureFlags.MOD_EXPERIMENTAL)))); - - return DataProvider.saveStable(cache, json, packOutput.getOutputFolder(PackOutput.Target.DATA_PACK) - .resolve("neoforge") - .resolve("datapacks") - .resolve("mod_experimental") - .resolve("pack.mcmeta")); - } - - @Override - public String getName() { - return "mod_experimental_pack"; - } - }); + Optional.of(new InclusiveRange<>(0, Integer.MAX_VALUE)))) + .add(FeatureFlagsMetadataSection.TYPE, new FeatureFlagsMetadataSection(FeatureFlagSet.of(FeatureFlags.MOD_EXPERIMENTAL)))); } // done in an event instead of deferred to only enable if a mod requests it From 9f78110b5476b9fcaca956324fd7e4d638b3afee Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 18:18:09 +0100 Subject: [PATCH 09/10] Fix pack position --- src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index cc96ba7b06..32e3e1afc7 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -642,7 +642,7 @@ public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) { Component.translatable("pack.neoforge.experimental.name"), PackSource.FEATURE, false, - Pack.Position.BOTTOM)); + Pack.Position.TOP)); if (isPRBuild(container.getModInfo().getVersion().toString())) { isPRBuild = true; From d2b5348857ba3b5c9d0f134f8f2c35be833cba29 Mon Sep 17 00:00:00 2001 From: Apex Date: Tue, 25 Jun 2024 18:18:23 +0100 Subject: [PATCH 10/10] Add simple test mods --- .../recipes/misc/diamond_from_dirt.json | 32 ++++++ .../recipe/diamond_from_dirt.json | 14 +++ .../experimental_features/pack.mcmeta | 11 ++ .../recipes/misc/dirt_from_diamond.json | 32 ++++++ .../recipe/dirt_from_diamond.json | 14 +++ .../experimental_features/pack.mcmeta | 11 ++ .../debug/resources/ExperimentalTests.java | 102 ++++++++++++++++++ 7 files changed, 216 insertions(+) create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/advancement/recipes/misc/diamond_from_dirt.json create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/recipe/diamond_from_dirt.json create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/pack.mcmeta create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/advancement/recipes/misc/dirt_from_diamond.json create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/recipe/dirt_from_diamond.json create mode 100644 tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/pack.mcmeta create mode 100644 tests/src/main/java/net/neoforged/neoforge/debug/resources/ExperimentalTests.java diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/advancement/recipes/misc/diamond_from_dirt.json b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/advancement/recipes/misc/diamond_from_dirt.json new file mode 100644 index 0000000000..199ed1078c --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/advancement/recipes/misc/diamond_from_dirt.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_dirt": { + "conditions": { + "items": [ + { + "items": "minecraft:dirt" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "neotests_experimental_tests_moda:diamond_from_dirt" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_dirt" + ] + ], + "rewards": { + "recipes": [ + "neotests_experimental_tests_moda:diamond_from_dirt" + ] + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/recipe/diamond_from_dirt.json b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/recipe/diamond_from_dirt.json new file mode 100644 index 0000000000..cd3f3ace93 --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/data/neotests_experimental_tests_moda/recipe/diamond_from_dirt.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "category": "misc", + "group": "experimental", + "ingredients": [ + { + "item": "minecraft:dirt" + } + ], + "result": { + "count": 1, + "id": "minecraft:diamond" + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/pack.mcmeta b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/pack.mcmeta new file mode 100644 index 0000000000..a36adc101b --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_moda/datapacks/experimental_features/pack.mcmeta @@ -0,0 +1,11 @@ +{ + "features": { + "enabled": [ + "neoforge:mod_experimental" + ] + }, + "pack": { + "description": "Enables experimental features (neotests_experimental_tests_moda)", + "pack_format": 48 + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/advancement/recipes/misc/dirt_from_diamond.json b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/advancement/recipes/misc/dirt_from_diamond.json new file mode 100644 index 0000000000..df42f33abd --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/advancement/recipes/misc/dirt_from_diamond.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_diamond": { + "conditions": { + "items": [ + { + "items": "#c:gems/diamond" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "neotests_experimental_tests_modb:dirt_from_diamond" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_diamond" + ] + ], + "rewards": { + "recipes": [ + "neotests_experimental_tests_modb:dirt_from_diamond" + ] + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/recipe/dirt_from_diamond.json b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/recipe/dirt_from_diamond.json new file mode 100644 index 0000000000..5865837baa --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/data/neotests_experimental_tests_modb/recipe/dirt_from_diamond.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "category": "misc", + "group": "experimental", + "ingredients": [ + { + "tag": "c:gems/diamond" + } + ], + "result": { + "count": 1, + "id": "minecraft:dirt" + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/pack.mcmeta b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/pack.mcmeta new file mode 100644 index 0000000000..1bd211dae7 --- /dev/null +++ b/tests/src/generated/resources/data/neotests_experimental_tests_modb/datapacks/experimental_features/pack.mcmeta @@ -0,0 +1,11 @@ +{ + "features": { + "enabled": [ + "neoforge:mod_experimental" + ] + }, + "pack": { + "description": "Enables experimental features (neotests_experimental_tests_modb)", + "pack_format": 48 + } +} \ No newline at end of file diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/resources/ExperimentalTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/resources/ExperimentalTests.java new file mode 100644 index 0000000000..d64a3bd794 --- /dev/null +++ b/tests/src/main/java/net/neoforged/neoforge/debug/resources/ExperimentalTests.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.debug.resources; + +import java.util.concurrent.CompletableFuture; +import java.util.function.UnaryOperator; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.metadata.PackMetadataGenerator; +import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.data.recipes.ShapelessRecipeBuilder; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.PackSource; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.neoforged.neoforge.common.Tags; +import net.neoforged.neoforge.data.event.GatherDataEvent; +import net.neoforged.neoforge.event.AddPackFindersEvent; +import net.neoforged.testframework.DynamicTest; +import net.neoforged.testframework.annotation.ForEachTest; +import net.neoforged.testframework.annotation.TestHolder; +import org.apache.commons.lang3.function.TriConsumer; + +@ForEachTest +public final class ExperimentalTests { + @TestHolder(value = "experimental_tests_base", description = "Test providing experimental items and blocks") + private static void baseMod(DynamicTest test) { + var registration = test.registrationHelper(); + var items = registration.items(); + + items.registerSimpleItem("experimental_item", new Item.Properties().requiredFeatures(FeatureFlags.MOD_EXPERIMENTAL)); + + var block = registration.blocks().registerSimpleBlock("experimental_block", BlockBehaviour.Properties.ofFullCopy(Blocks.STONE).requiredFeatures(FeatureFlags.MOD_EXPERIMENTAL)); + items.registerSimpleBlockItem(block); + } + + @TestHolder(value = "experimental_tests_moda", description = "Test providing experimental feature pack (dirt -> diamond recipe)") + private static void modA(DynamicTest test) { + commonMod(test, (event, pack, lookupProvider) -> pack.addProvider(output -> new RecipeProvider(output, lookupProvider) { + @Override + protected void buildRecipes(RecipeOutput output) { + // recipe for dirt -> diamond enabled when MOD_EXPERIMENTAL is enabled + ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Items.DIAMOND) + .requires(Items.DIRT) + .unlockedBy("has_dirt", has(Items.DIRT)) + .group("experimental") + .save(output, ResourceLocation.fromNamespaceAndPath(test.createModId(), "diamond_from_dirt")); + } + })); + } + + @TestHolder(value = "experimental_tests_modb", description = "Test providing experimental feature pack (diamond -> dirt recipe)") + private static void modB(DynamicTest test) { + commonMod(test, (event, pack, lookupProvider) -> pack.addProvider(output -> new RecipeProvider(output, lookupProvider) { + @Override + protected void buildRecipes(RecipeOutput output) { + // recipe for diamond -> dirt enabled when MOD_EXPERIMENTAL is enabled + ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Items.DIRT) + .requires(Tags.Items.GEMS_DIAMOND) + .unlockedBy("has_diamond", has(Tags.Items.GEMS_DIAMOND)) + .group("experimental") + .save(output, ResourceLocation.fromNamespaceAndPath(test.createModId(), "dirt_from_diamond")); + } + })); + } + + private static void commonMod(DynamicTest test, TriConsumer> gatherData) { + var packName = "experimental_features"; + var modBus = test.framework().modEventBus(); + var modId = test.createModId(); + + // register pack finder for experimental features pack + modBus.addListener(AddPackFindersEvent.class, event -> event.addPackFinders( + ResourceLocation.fromNamespaceAndPath("neotests", "data/" + modId + "/datapacks/" + packName), + PackType.SERVER_DATA, + Component.literal("Experimental Features (" + modId + ")"), + PackSource.create(UnaryOperator.identity(), false), + false, + Pack.Position.BOTTOM)); + + modBus.addListener(GatherDataEvent.class, event -> { + var generator = event.getGenerator(); + var pack = generator.getBuiltinDatapack(event.includeServer(), modId, packName); + // generate pack metadata for experimental features pack + pack.addProvider(output -> PackMetadataGenerator.forFeaturePack(output, Component.literal("Enables experimental features (" + modId + ")"), FeatureFlagSet.of(FeatureFlags.MOD_EXPERIMENTAL))); + // generate any additional data for this pack + gatherData.accept(generator, pack, event.getLookupProvider()); + }); + } +}