From 0cb1ba65eb6d75f671634fb65d25bcbd2378e930 Mon Sep 17 00:00:00 2001 From: Matyrobbrt Date: Tue, 28 Jan 2025 12:45:01 +0200 Subject: [PATCH] 1.20.1 MDK using MDG Legacy --- README.md | 6 +- build.gradle | 82 ++++++++++++------- gradle.properties | 22 ++--- settings.gradle | 8 -- .../java/com/example/examplemod/Config.java | 36 ++++---- .../com/example/examplemod/ExampleMod.java | 74 ++++++++--------- .../{neoforge.mods.toml => mods.toml} | 23 ++---- src/main/templates/pack.mcmeta | 6 ++ 8 files changed, 131 insertions(+), 126 deletions(-) rename src/main/templates/META-INF/{neoforge.mods.toml => mods.toml} (78%) create mode 100644 src/main/templates/pack.mcmeta diff --git a/README.md b/README.md index b421122..00fbba4 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,15 @@ run `gradlew --refresh-dependencies` to refresh the local cache. `gradlew clean` Mapping Names: ============ -By default, the MDK is configured to use the official mapping names from Mojang for methods and fields +The MDK is configured to use the official mapping names from Mojang for methods and fields in the Minecraft codebase. These names are covered by a specific license. All modders should be aware of this license. For the latest license text, refer to the mapping file itself, or the reference copy here: https://github.com/NeoForged/NeoForm/blob/main/Mojang.md +MDG Legacy: +========== +This template uses [ModDevGradle Legacy](https://github.com/neoforged/ModDevGradle). Documentation can be found [here](https://github.com/neoforged/ModDevGradle/blob/main/LEGACY.md). + Additional Resources: ========== Community Documentation: https://docs.neoforged.net/ diff --git a/build.gradle b/build.gradle index a15ada0..b3e2e09 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'idea' id 'java-library' id 'maven-publish' - id 'net.neoforged.moddev' version '1.0.23' + id 'net.neoforged.moddev.legacyforge' version '2.0.76' } tasks.named('wrapper', Wrapper).configure { @@ -25,12 +25,12 @@ base { archivesName = mod_id } -// Mojang ships Java 21 to end users starting in 1.20.5, so mods should target Java 21. -java.toolchain.languageVersion = JavaLanguageVersion.of(21) +// Mojang ships Java 21 to end users in 1.20.1, so mods should target Java 17. +java.toolchain.languageVersion = JavaLanguageVersion.of(17) -neoForge { - // Specify the version of NeoForge to use. - version = project.neo_version +legacyForge { + // Specify the version of MinecraftForge to use. + version = project.minecraft_version + '-' + project.forge_version parchment { mappingsVersion = project.parchment_mappings_version @@ -47,13 +47,13 @@ neoForge { client() // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. - systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id } server { server() programArgument '--nogui' - systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id } // This run config launches GameTestServer and runs all registered gametests, then exits. @@ -61,7 +61,7 @@ neoForge { // The gametest system is also enabled by default for other run configs under the /test command. gameTestServer { type = "gameTestServer" - systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id } data { @@ -104,53 +104,77 @@ neoForge { // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } -// Sets up a dependency configuration called 'localRuntime'. -// This configuration should be used instead of 'runtimeOnly' to declare +// Sets up a dependency configuration called 'localRuntime' and a deobfuscating one called 'modLocalRuntime' +// These configurations should be used instead of 'runtimeOnly' to declare // a dependency that will be present for runtime testing but that is // "optional", meaning it will not be pulled by dependents of this mod. configurations { runtimeClasspath.extendsFrom localRuntime } +obfuscation { + createRemappingConfiguration(configurations.localRuntime) +} dependencies { + // If you wish to declare dependencies against mods, make sure to use the 'mod*' configurations so that they're remapped. + // See https://github.com/neoforged/ModDevGradle/blob/main/LEGACY.md#remapping-mod-dependencies for more information. + // Example optional mod dependency with JEI // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime - // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" - // compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" + // modCompileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" + // modCompileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" // We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it - // localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" + // modLocalRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" // Example mod dependency using a mod jar from ./libs with a flat dir repository // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar // The group id is ignored when searching -- in this case, it is "blank" - // implementation "blank:coolmod-${mc_version}:${coolmod_version}" + // modImplementation "blank:coolmod-${mc_version}:${coolmod_version}" // Example mod dependency using a file as dependency - // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") + // modImplementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") // Example project dependency using a sister or child project: - // implementation project(":myproject") + // modImplementation project(":myproject") // For more info: // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/dependency_management.html } +// Uncomment the lines below if you wish to configure mixin. The mixin file should be named modid.mixins.json. +/* +mixin { + add sourceSets.main, "${mod_id}.refmap.json" + config "${mod_id}.mixins.json" +} + +dependencies { + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' +} + +jar { + manifest.attributes([ + "MixinConfigs": "${mod_id}.mixins.json" + ]) +} +*/ + // This block of code expands all declared replace properties in the specified resource targets. // A missing property will result in an error. Properties are expanded using ${} Groovy notation. var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ - minecraft_version : minecraft_version, - minecraft_version_range: minecraft_version_range, - neo_version : neo_version, - neo_version_range : neo_version_range, - loader_version_range : loader_version_range, - mod_id : mod_id, - mod_name : mod_name, - mod_license : mod_license, - mod_version : mod_version, - mod_authors : mod_authors, - mod_description : mod_description + minecraft_version : minecraft_version, + minecraft_version_range : minecraft_version_range, + forge_version : forge_version, + forge_version_range : forge_version_range, + loader_version_range : loader_version_range, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, + mod_authors : mod_authors, + mod_description : mod_description ] inputs.properties replaceProperties expand replaceProperties @@ -161,7 +185,7 @@ var generateModMetadata = tasks.register("generateModMetadata", ProcessResources // this works with both building through Gradle and the IDE. sourceSets.main.resources.srcDir generateModMetadata // To avoid having to run "generateModMetadata" manually, make it run on every project reload -neoForge.ideSyncTask generateModMetadata +legacyForge.ideSyncTask generateModMetadata // Example configuration to allow publishing using the maven-publish plugin publishing { diff --git a/gradle.properties b/gradle.properties index 7dcb369..0f61595 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,22 +7,22 @@ org.gradle.configuration-cache=true #read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment # you can also find the latest versions at: https://parchmentmc.org/docs/getting-started -parchment_minecraft_version=1.21.1 -parchment_mappings_version=2024.11.17 +parchment_minecraft_version=1.20.1 +parchment_mappings_version=2023.09.03 # Environment Properties -# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge -# The Minecraft version must agree with the Neo version to get a valid artifact -minecraft_version=1.21.1 +# You can find the latest versions here: https://files.minecraftforge.net/net/minecraftforge/forge/index_1.20.1.html +# The Minecraft version must agree with the Forge version to get a valid artifact +minecraft_version=1.20.1 # The Minecraft version range can use any release version of Minecraft as bounds. # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly # as they do not follow standard versioning conventions. -minecraft_version_range=[1.21.1, 1.22) -# The Neo version must agree with the Minecraft version to get a valid artifact -neo_version=21.1.114 -# The Neo version range can use any version of Neo as bounds -neo_version_range=[21.1.0,) +minecraft_version_range=[1.20.1, 1.21) +# The Forge version must agree with the Minecraft version to get a valid artifact +forge_version=47.1.3 +# The Forge version range can use any version of Forge as bounds +forge_version_range=[47.1.3,) # The loader version range can only use the major version of FML as bounds -loader_version_range=[4,) +loader_version_range=[47,) ## Mod Properties diff --git a/settings.gradle b/settings.gradle index 90ae98f..6823ddb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,11 +1,3 @@ -pluginManagement { - repositories { - mavenLocal() - gradlePluginPortal() - maven { url = 'https://maven.neoforged.net/releases' } - } -} - plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' } diff --git a/src/main/java/com/example/examplemod/Config.java b/src/main/java/com/example/examplemod/Config.java index d70d1eb..ca8e088 100644 --- a/src/main/java/com/example/examplemod/Config.java +++ b/src/main/java/com/example/examplemod/Config.java @@ -1,42 +1,42 @@ package com.example.examplemod; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.config.ModConfigEvent; + import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.event.config.ModConfigEvent; -import net.neoforged.neoforge.common.ModConfigSpec; - // An example config class. This is not required, but it's a good idea to have one to keep your config organized. -// Demonstrates how to use Neo's config APIs -@EventBusSubscriber(modid = ExampleMod.MODID, bus = EventBusSubscriber.Bus.MOD) +// Demonstrates how to use Forge's config APIs +@Mod.EventBusSubscriber(modid = ExampleMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class Config { - private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); + private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); - private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER + private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER .comment("Whether to log the dirt block on common setup") .define("logDirtBlock", true); - private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER + private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER .comment("A magic number") .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - public static final ModConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER + public static final ForgeConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER .comment("What you want the introduction message to be for the magic number") .define("magicNumberIntroduction", "The magic number is... "); // a list of strings that are treated as resource locations for items - private static final ModConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER + private static final ForgeConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER .comment("A list of items to log on common setup.") .defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); - static final ModConfigSpec SPEC = BUILDER.build(); + static final ForgeConfigSpec SPEC = BUILDER.build(); public static boolean logDirtBlock; public static int magicNumber; @@ -45,7 +45,7 @@ public class Config private static boolean validateItemName(final Object obj) { - return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName)); + return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(new ResourceLocation(itemName)); } @SubscribeEvent @@ -57,7 +57,7 @@ public class Config // convert the list of strings into a set of items items = ITEM_STRINGS.get().stream() - .map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName))) + .map(itemName -> BuiltInRegistries.ITEM.get(new ResourceLocation(itemName))) .collect(Collectors.toSet()); } } diff --git a/src/main/java/com/example/examplemod/ExampleMod.java b/src/main/java/com/example/examplemod/ExampleMod.java index 835a48d..990fd63 100644 --- a/src/main/java/com/example/examplemod/ExampleMod.java +++ b/src/main/java/com/example/examplemod/ExampleMod.java @@ -1,13 +1,8 @@ package com.example.examplemod; -import org.slf4j.Logger; - import com.mojang.logging.LogUtils; - import net.minecraft.client.Minecraft; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; @@ -17,24 +12,24 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.MapColor; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.ModContainer; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.common.Mod; -import net.neoforged.fml.config.ModConfig; -import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; -import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.event.server.ServerStartingEvent; -import net.neoforged.neoforge.registries.DeferredBlock; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.slf4j.Logger; -// The value here should match an entry in the META-INF/neoforge.mods.toml file +// The value here should match an entry in the META-INF/mods.toml file @Mod(ExampleMod.MODID) public class ExampleMod { @@ -43,34 +38,33 @@ public class ExampleMod // Directly reference a slf4j logger private static final Logger LOGGER = LogUtils.getLogger(); // Create a Deferred Register to hold Blocks which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID); + public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID); // Create a Deferred Register to hold Items which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID); // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "examplemod" namespace public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); // Creates a new Block with the id "examplemod:example_block", combining the namespace and path - public static final DeferredBlock EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock("example_block", BlockBehaviour.Properties.of().mapColor(MapColor.STONE)); + public static final RegistryObject EXAMPLE_BLOCK = BLOCKS.register("example_block", () -> new Block(BlockBehaviour.Properties.of().mapColor(MapColor.STONE))); // Creates a new BlockItem with the id "examplemod:example_block", combining the namespace and path - public static final DeferredItem EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK); + public static final RegistryObject EXAMPLE_BLOCK_ITEM = ITEMS.register("example_block", () -> new BlockItem(EXAMPLE_BLOCK.get(), new Item.Properties())); // Creates a new food item with the id "examplemod:example_id", nutrition 1 and saturation 2 - public static final DeferredItem EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", new Item.Properties().food(new FoodProperties.Builder() - .alwaysEdible().nutrition(1).saturationModifier(2f).build())); + public static final RegistryObject EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties().food(new FoodProperties.Builder() + .alwaysEat().nutrition(1).saturationMod(2f).build()))); // Creates a creative tab with the id "examplemod:example_tab" for the example item, that is placed after the combat tab - public static final DeferredHolder EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder() - .title(Component.translatable("itemGroup.examplemod")) //The language key for the title of your CreativeModeTab + public static final RegistryObject EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder() .withTabsBefore(CreativeModeTabs.COMBAT) .icon(() -> EXAMPLE_ITEM.get().getDefaultInstance()) .displayItems((parameters, output) -> { output.accept(EXAMPLE_ITEM.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event }).build()); - // The constructor for the mod class is the first code that is run when your mod is loaded. - // FML will recognize some parameter types like IEventBus or ModContainer and pass them in automatically. - public ExampleMod(IEventBus modEventBus, ModContainer modContainer) + public ExampleMod() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + // Register the commonSetup method for modloading modEventBus.addListener(this::commonSetup); @@ -81,16 +75,14 @@ public class ExampleMod // Register the Deferred Register to the mod event bus so tabs get registered CREATIVE_MODE_TABS.register(modEventBus); - // Register ourselves for server and other game events we are interested in. - // Note that this is necessary if and only if we want *this* class (ExampleMod) to respond directly to events. - // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. - NeoForge.EVENT_BUS.register(this); + // Register ourselves for server and other game events we are interested in + MinecraftForge.EVENT_BUS.register(this); // Register the item to a creative tab modEventBus.addListener(this::addCreative); - // Register our mod's ModConfigSpec so that FML can create and load the config file for us - modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC); + // Register our mod's ForgeConfigSpec so that Forge can create and load the config file for us + ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); } private void commonSetup(final FMLCommonSetupEvent event) @@ -99,7 +91,7 @@ public class ExampleMod LOGGER.info("HELLO FROM COMMON SETUP"); if (Config.logDirtBlock) - LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT)); + LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT)); LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber); @@ -122,7 +114,7 @@ public class ExampleMod } // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent - @EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) + @Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public static class ClientModEvents { @SubscribeEvent diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/mods.toml similarity index 78% rename from src/main/templates/META-INF/neoforge.mods.toml rename to src/main/templates/META-INF/mods.toml index 1b9f6e9..e50048e 100644 --- a/src/main/templates/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/mods.toml @@ -46,29 +46,16 @@ authors="${mod_authors}" #optional # The description text for the mod (multi line!) (#mandatory) description='''${mod_description}''' -# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. -#[[mixins]] -#config="${mod_id}.mixins.json" - -# The [[accessTransformers]] block allows you to declare where your AT file is. -# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg -#[[accessTransformers]] -#file="META-INF/accesstransformer.cfg" - -# The coremods config file path is not configurable and is always loaded from META-INF/coremods.json - # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.${mod_id}]] #optional # the modid of the dependency - modId="neoforge" #mandatory - # The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive). - # 'required' requires the mod to exist, 'optional' does not - # 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning - type="required" #mandatory + modId="forge" #mandatory + # Does this dependency have to exist - if not, ordering below must be specified + mandatory=true #mandatory # Optional field describing why the dependency is required or why it is incompatible # reason="..." # The version range of the dependency - versionRange="${neo_version_range}" #mandatory + versionRange="${forge_version_range}" #mandatory # An ordering relationship for the dependency. # BEFORE - This mod is loaded BEFORE the dependency # AFTER - This mod is loaded AFTER the dependency @@ -79,7 +66,7 @@ description='''${mod_description}''' # Here's another dependency [[dependencies.${mod_id}]] modId="minecraft" - type="required" + mandatory=true # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange="${minecraft_version_range}" ordering="NONE" diff --git a/src/main/templates/pack.mcmeta b/src/main/templates/pack.mcmeta new file mode 100644 index 0000000..8e3dfe3 --- /dev/null +++ b/src/main/templates/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "${mod_name} resources", + "pack_format": 8 + } +}