User: rednesto Date: 01 Oct 24 09:34 Revision: f510e314041f65bb940a2ef370af44e85b183b32 Summary: Bump templates TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=9752&personal=false Index: templates/Gradle.gitignore.ft =================================================================== --- templates/Gradle.gitignore.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/Gradle.gitignore.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -118,6 +118,7 @@ # Common working directory run/ +runs/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar Index: templates/architectury/neoforge/build.gradle.ft =================================================================== --- templates/architectury/neoforge/build.gradle.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/architectury/neoforge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -34,7 +34,7 @@ dependencies { neoForge "net.neoforged:neoforge:$rootProject.neoforge_version" -#if ($VERSIONS.architecturyApi) +#if ($VERSIONS.useArchitecturyApi) modImplementation "dev.architectury:architectury-neoforge:$rootProject.architectury_api_version" #end Index: templates/fabric/.mcdev.template.json =================================================================== --- templates/fabric/.mcdev.template.json (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/fabric/.mcdev.template.json (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -51,24 +51,25 @@ { "name": "SPLIT_SOURCES", "type": "boolean", - "default": true + "default": true, + "visible": { + "dependsOn": ["VERSIONS"], + "condition": "$VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0" + } }, { "name": "CLIENT_SOURCE_SET", "type": "string", "visible": false, "derives": { - "parents": ["SPLIT_SOURCES"], + "parents": ["VERSIONS", "SPLIT_SOURCES"], "select": [ { - "condition": "$SPLIT_SOURCES", + "condition": "$SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0", "value": "client" - }, - { - "condition": "!$SPLIT_SOURCES", - "value": "main" } - ] + ], + "default": "main" } }, { @@ -175,7 +176,10 @@ }, { "template": "../gradle-wrapper.properties.ft", - "destination": "gradle/wrapper/gradle-wrapper.properties" + "destination": "gradle/wrapper/gradle-wrapper.properties", + "properties": { + "GRADLE_VERSION": "8.10.2" + } }, { "template": "fabric.mod.json.ft", @@ -189,7 +193,7 @@ { "template": "mixins.json.ft", "destination": "src/client/resources/${MOD_ID}.client.mixins.json", - "condition": "$USE_MIXINS && $SPLIT_SOURCES", + "condition": "$USE_MIXINS && $SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0", "properties": { "CLIENT": true } Index: templates/fabric/build.gradle.ft =================================================================== --- templates/fabric/build.gradle.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/fabric/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -10,7 +10,7 @@ archivesName = project.archives_base_name } -#if ($SPLIT_SOURCES) +#if ($SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0) loom { splitEnvironmentSourceSets() @@ -42,7 +42,6 @@ modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" #if (${VERSIONS.useFabricApi}) - // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" #end } Index: templates/fabric/build.gradle.kts.ft =================================================================== --- templates/fabric/build.gradle.kts.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/fabric/build.gradle.kts.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -23,7 +23,7 @@ withSourcesJar() } -#if ($SPLIT_SOURCES) +#if ($SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0) loom { splitEnvironmentSourceSets() @@ -56,7 +56,6 @@ modImplementation("net.fabricmc:fabric-language-kotlin:${project.property("kotlin_loader_version")}") #if (${VERSIONS.useFabricApi}) - // Fabric API. This is technically optional, but you probably want it anyway. modImplementation("net.fabricmc.fabric-api:fabric-api:${project.property("fabric_version")}") #end } Index: templates/fabric/fabric.mod.json.ft =================================================================== --- templates/fabric/fabric.mod.json.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/fabric/fabric.mod.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -23,7 +23,7 @@ #if (${USE_MIXINS}) "mixins": [ "${MOD_ID}.mixins.json" -#if (${SPLIT_SOURCES}) +#if ($SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0) ,{ "config": "${MOD_ID}.client.mixins.json", "environment": "client" Index: templates/fabric/mixins.json.ft =================================================================== --- templates/fabric/mixins.json.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/fabric/mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -7,11 +7,11 @@ "package": "${MAIN_CLASS.packageName}.mixin.client", #end "compatibilityLevel": "JAVA_${JAVA_VERSION}", -#if (!$SPLIT_SOURCES || !$CLIENT) +#if (!($SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0) || !$CLIENT) "mixins": [ ], #end -#if (!$SPLIT_SOURCES || $CLIENT) +#if (!($SPLIT_SOURCES && $VERSIONS.minecraftVersion.compareTo($mcver.MC1_18) >= 0) || $CLIENT) "client": [ ], #end Index: templates/forge/.mcdev.template.json =================================================================== --- templates/forge/.mcdev.template.json (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/forge/.mcdev.template.json (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -176,9 +176,9 @@ "openInEditor": true }, { - "template": "Config (1.20.2+).java.ft", + "template": "Config (1.20.1+).java.ft", "destination": "src/main/java/${MAIN_CLASS.packagePath}/Config.java", - "condition": "$VERSIONS.minecraft.compareTo($mcver.MC1_20_2) >= 0 && $VERSIONS.minecraft.compareTo($mcver.MC1_21) < 0", + "condition": "$VERSIONS.minecraft.compareTo($mcver.MC1_20_1) >= 0 && $VERSIONS.minecraft.compareTo($mcver.MC1_21) < 0", "openInEditor": true }, { Index: templates/forge/Config (1.20.1+).java.ft =================================================================== --- templates/forge/Config (1.20.1+).java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/forge/Config (1.20.1+).java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,64 @@ +package ${MAIN_CLASS.packageName}; + +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 net.minecraftforge.registries.ForgeRegistries; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +// 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 Forge's config APIs +@Mod.EventBusSubscriber(modid = ${MAIN_CLASS.className}.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class Config +{ + private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.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 ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER + .comment("A magic number") + .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); + + 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 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 ForgeConfigSpec SPEC = BUILDER.build(); + + public static boolean logDirtBlock; + public static int magicNumber; + public static String magicNumberIntroduction; + public static Set items; + + private static boolean validateItemName(final Object obj) + { + return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName)); + } + + @SubscribeEvent + static void onLoad(final ModConfigEvent event) + { + logDirtBlock = LOG_DIRT_BLOCK.get(); + magicNumber = MAGIC_NUMBER.get(); + magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); + + // convert the list of strings into a set of items + items = ITEM_STRINGS.get().stream() + .map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName))) + .collect(Collectors.toSet()); + } +} Index: templates/forge/Config (1.20.2+).java.ft =================================================================== --- templates/forge/Config (1.20.2+).java.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/forge/Config (1.20.2+).java.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) @@ -1,64 +0,0 @@ -package ${MAIN_CLASS.packageName}; - -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 net.minecraftforge.registries.ForgeRegistries; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -// 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 Forge's config APIs -@Mod.EventBusSubscriber(modid = ${MAIN_CLASS.className}.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class Config -{ - private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.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 ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER - .comment("A magic number") - .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - - 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 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 ForgeConfigSpec SPEC = BUILDER.build(); - - public static boolean logDirtBlock; - public static int magicNumber; - public static String magicNumberIntroduction; - public static Set items; - - private static boolean validateItemName(final Object obj) - { - return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName)); - } - - @SubscribeEvent - static void onLoad(final ModConfigEvent event) - { - logDirtBlock = LOG_DIRT_BLOCK.get(); - magicNumber = MAGIC_NUMBER.get(); - magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); - - // convert the list of strings into a set of items - items = ITEM_STRINGS.get().stream() - .map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName))) - .collect(Collectors.toSet()); - } -} Index: templates/forge/MainClass (1.20+).java.ft =================================================================== --- templates/forge/MainClass (1.20+).java.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/forge/MainClass (1.20+).java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -41,7 +41,7 @@ public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID); // Create a Deferred Register to hold Items which will all be registered under the "${MOD_ID}" namespace 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 + // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "${MOD_ID}" namespace public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); // Creates a new Block with the id "${MOD_ID}:example_block", combining the namespace and path @@ -49,11 +49,11 @@ // Creates a new BlockItem with the id "${MOD_ID}:example_block", combining the namespace and path 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 + // Creates a new food item with the id "${MOD_ID}:example_id", nutrition 1 and saturation 2 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 + // Creates a creative tab with the id "${MOD_ID}:example_tab" for the example item, that is placed after the combat tab public static final RegistryObject EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder() .withTabsBefore(CreativeModeTabs.COMBAT) .icon(() -> EXAMPLE_ITEM.get().getDefaultInstance()) Index: templates/forge/MainClass (1.20.6+).java.ft =================================================================== --- templates/forge/MainClass (1.20.6+).java.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/forge/MainClass (1.20.6+).java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -41,7 +41,7 @@ public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID); // Create a Deferred Register to hold Items which will all be registered under the "${MOD_ID}" namespace 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 + // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "${MOD_ID}" namespace public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); // Creates a new Block with the id "${MOD_ID}:example_block", combining the namespace and path @@ -49,20 +49,26 @@ // Creates a new BlockItem with the id "${MOD_ID}:example_block", combining the namespace and path 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 + // Creates a new food item with the id "${MOD_ID}:example_id", nutrition 1 and saturation 2 public static final RegistryObject EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties().food(new FoodProperties.Builder() .alwaysEdible().nutrition(1).saturationModifier(2f).build()))); - // Creates a creative tab with the id "examplemod:example_tab" for the example item, that is placed after the combat tab + // Creates a creative tab with the id "${MOD_ID}:example_tab" for the example item, that is placed after the combat tab 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()); - +#set($LOADING_CONTEXT_INJECTION = ${VERSIONS.forge.compareTo($semver.parse("52.0.9"))} >= 0 || + (${VERSIONS.forge.compareTo($semver.parse("50.1.17"))} >= 0 && ${VERSIONS.forge.compareTo($semver.parse("51.0.0"))} < 0)) +#if ($LOADING_CONTEXT_INJECTION) + public ${MAIN_CLASS.className}(FMLJavaModLoadingContext context) { + IEventBus modEventBus = context.getModEventBus(); +#else public ${MAIN_CLASS.className}() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); +#end // Register the commonSetup method for modloading modEventBus.addListener(this::commonSetup); @@ -81,7 +87,11 @@ modEventBus.addListener(this::addCreative); // Register our mod's ForgeConfigSpec so that Forge can create and load the config file for us +#if ($LOADING_CONTEXT_INJECTION) + context.registerConfig(ModConfig.Type.COMMON, Config.SPEC); +#else ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC); +#end } private void commonSetup(final FMLCommonSetupEvent event) { Index: templates/forge/build.gradle.ft =================================================================== --- templates/forge/build.gradle.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/forge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -47,7 +47,12 @@ // Use non-default mappings at your own risk. They may not always work. // Simply re-run your setup task after changing the mappings to update your workspace. mappings channel: mapping_channel, version: mapping_version +#if ($VERSIONS.minecraft.compareTo($mcver.MC1_20_6) >= 0) + // Tell FG to not automatically create the reobf tasks, as we now use Official mappings at runtime, If you don't use them at dev time then you'll have to fix your reobf yourself. + reobf = false +#end + // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game. // In most cases, it is not necessary to enable. // enableEclipsePrepareRuns = true @@ -184,7 +189,7 @@ annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' #end -#if ($VERSIONS.minecraft.compareTo($mcver.mC1_20_6) >= 0) +#if ($VERSIONS.minecraft.compareTo($mcver.MC1_20_6) >= 0) // Hack fix for now, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transtive dependencies request 6.0+ implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } #end @@ -222,9 +227,11 @@ "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) } +#if ($VERSIONS.minecraft.compareTo($mcver.MC1_20_6) < 0) // This is the preferred method to reobfuscate your jar file finalizedBy 'reobfJar' +#end } tasks.withType(JavaCompile).configureEach { Index: templates/gradle-wrapper.properties.ft =================================================================== --- templates/gradle-wrapper.properties.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/gradle-wrapper.properties.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -1,1 +1,4 @@ -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +#if (!$GRADLE_VERSION) +#set ($GRADLE_VERSION = "8.8") +#end +distributionUrl=https\://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip Index: templates/messages.properties =================================================================== --- templates/messages.properties (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/messages.properties (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -24,6 +24,7 @@ platform.bungeecord.label=Bungeecord platform.fabric.label=Fabric platform.forge.label=Forge +platform.multiloader.label=MultiLoader platform.neoforge.label=NeoForge platform.sponge.label=Sponge platform.velocity.label=Velocity Index: templates/multiloader/.mcdev.template.json =================================================================== --- templates/multiloader/.mcdev.template.json (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/.mcdev.template.json (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,257 @@ +{ + "version": 1, + "group": "mod", + "properties": [ + { + "name": "BUILD_COORDS", + "type": "build_system_coordinates", + "order": 10 + }, + { + "name": "MC_VERSION", + "type": "semantic_version", + "options": [ + "1.21" + ] + }, + { + "name": "MOD_ID", + "type": "string", + "validator": "[a-z][a-z0-9-_]{1,63}", + "derives": { + "parents": ["PROJECT_NAME"], + "method": "replace", + "parameters": { + "regex": "[^a-z0-9-_]+", + "replacement": "_", + "maxLength": 64, + "lowercase": true + } + } + }, + { + "name": "MOD_NAME", + "type": "string", + "inheritFrom": "PROJECT_NAME" + }, + { + "name": "MAIN_CLASS", + "type": "class_fqn", + "derives": { + "parents": ["BUILD_COORDS", "MOD_ID"], + "method": "suggestClassName" + } + }, + { + "name": "LICENSE", + "type": "license" + }, + { + "label": "creator.ui.optional_settings.label", + "collapsible": true, + "groupProperties": [ + { + "name": "DESCRIPTION", + "type": "string", + "default": "" + }, + { + "name": "AUTHORS", + "type": "inline_string_list", + "default": "" + }, + { + "name": "WEBSITE", + "type": "string", + "default": "" + } + ] + }, + { + "name": "JAVA_VERSION", + "type": "integer", + "order": 20, + "default": 17, + "visible": false, + "derives": { + "parents": ["MC_VERSION"], + "method": "recommendJavaVersionForMcVersion", + "default": 17 + } + }, + { + "name": "JDK", + "type": "jdk", + "order": 20, + "default": "JAVA_VERSION" + } + ], + "files": [ + { + "template": "../Gradle.gitignore.ft", + "destination": ".gitignore", + "condition": "$USE_GIT" + }, + { + "template": "../gradle-wrapper.properties.ft", + "destination": "gradle/wrapper/gradle-wrapper.properties" + }, + { + "template": "../licenses/${LICENSE.id}.txt.ft", + "destination": "LICENSE.txt" + }, + { + "template": "build.gradle.ft", + "destination": "build.gradle" + }, + { + "template": "settings.gradle.ft", + "destination": "settings.gradle" + }, + { + "template": "${MC_VERSION} gradle.properties.ft", + "destination": "gradle.properties" + }, + { + "template": "buildSrc/build.gradle.ft", + "destination": "buildSrc/build.gradle" + }, + { + "template": "buildSrc/multiloader-common.gradle.ft", + "destination": "buildSrc/src/main/groovy/multiloader-common.gradle" + }, + { + "template": "buildSrc/multiloader-loader.gradle.ft", + "destination": "buildSrc/src/main/groovy/multiloader-loader.gradle" + }, + { + "template": "common/build.gradle.ft", + "destination": "common/build.gradle" + }, + { + "template": "common/MixinMinecraft.java.ft", + "destination": "common/src/main/java/${MAIN_CLASS.packagePath}/mixin/MixinMinecraft.java" + }, + { + "template": "common/IPlatformHelper.java.ft", + "destination": "common/src/main/java/${MAIN_CLASS.packagePath}/platform/services/IPlatformHelper.java" + }, + { + "template": "common/Services.java.ft", + "destination": "common/src/main/java/${MAIN_CLASS.packagePath}/platform/Services.java" + }, + { + "template": "common/CommonClass.java.ft", + "destination": "common/src/main/java/${MAIN_CLASS.packagePath}/CommonClass.java" + }, + { + "template": "common/Constants.java.ft", + "destination": "common/src/main/java/${MAIN_CLASS.packagePath}/Constants.java" + }, + { + "template": "common/mixins.json.ft", + "destination": "common/src/main/resources/${MOD_ID}.mixins.json" + }, + { + "template": "common/pack.mcmeta.ft", + "destination": "common/src/main/resources/pack.mcmeta" + }, + { + "template": "fabric/build.gradle.ft", + "destination": "fabric/build.gradle" + }, + { + "template": "fabric/ExampleMod.java.ft", + "destination": "fabric/src/main/java/${MAIN_CLASS.path}.java" + }, + { + "template": "fabric/FabricPlatformHelper.java.ft", + "destination": "fabric/src/main/java/${MAIN_CLASS.packagePath}/platform/FabricPlatformHelper.java" + }, + { + "template": "fabric/MixinTitleScreen.java.ft", + "destination": "fabric/src/main/java/${MAIN_CLASS.packagePath}/mixin/MixinTitleScreen.java" + }, + { + "template": "fabric/service.IPlatformHelper.ft", + "destination": "fabric/src/main/resources/META-INF/services/${MAIN_CLASS.packageName}.platform.services.IPlatformHelper" + }, + { + "template": "fabric/fabric.mixins.json.ft", + "destination": "fabric/src/main/resources/${MOD_ID}.fabric.mixins.json" + }, + { + "template": "fabric/fabric.mod.json.ft", + "destination": "fabric/src/main/resources/fabric.mod.json" + }, + { + "template": "forge/build.gradle.ft", + "destination": "forge/build.gradle" + }, + { + "template": "forge/ExampleMod.java.ft", + "destination": "forge/src/main/java/${MAIN_CLASS.path}.java" + }, + { + "template": "forge/ForgePlatformHelper.java.ft", + "destination": "forge/src/main/java/${MAIN_CLASS.packagePath}/platform/ForgePlatformHelper.java" + }, + { + "template": "forge/MixinTitleScreen.java.ft", + "destination": "forge/src/main/java/${MAIN_CLASS.packagePath}/mixin/MixinTitleScreen.java" + }, + { + "template": "forge/service.IPlatformHelper.ft", + "destination": "forge/src/main/resources/META-INF/services/${MAIN_CLASS.packageName}.platform.services.IPlatformHelper" + }, + { + "template": "forge/forge.mixins.json.ft", + "destination": "forge/src/main/resources/${MOD_ID}.forge.mixins.json" + }, + { + "template": "forge/mods.toml.ft", + "destination": "forge/src/main/resources/META-INF/mods.toml" + }, + { + "template": "neoforge/build.gradle.ft", + "destination": "neoforge/build.gradle" + }, + { + "template": "neoforge/ExampleMod.java.ft", + "destination": "neoforge/src/main/java/${MAIN_CLASS.path}.java" + }, + { + "template": "neoforge/NeoForgePlatformHelper.java.ft", + "destination": "neoforge/src/main/java/${MAIN_CLASS.packagePath}/platform/NeoForgePlatformHelper.java" + }, + { + "template": "neoforge/MixinTitleScreen.java.ft", + "destination": "neoforge/src/main/java/${MAIN_CLASS.packagePath}/mixin/MixinTitleScreen.java" + }, + { + "template": "neoforge/service.IPlatformHelper.ft", + "destination": "neoforge/src/main/resources/META-INF/services/${MAIN_CLASS.packageName}.platform.services.IPlatformHelper" + }, + { + "template": "neoforge/neoforge.mixins.json.ft", + "destination": "neoforge/src/main/resources/${MOD_ID}.neoforge.mixins.json" + }, + { + "template": "neoforge/neoforge.mods.toml.ft", + "destination": "neoforge/src/main/resources/META-INF/neoforge.mods.toml" + } + ], + "finalizers": [ + { + "type": "import_gradle_project" + }, + { + "type": "run_gradle_tasks", + "tasks": ["wrapper", "genIntellijRuns"] + }, + { + "type": "git_add_all", + "condition": "$USE_GIT" + } + ] +} Index: templates/multiloader/1.21 gradle.properties.ft =================================================================== --- templates/multiloader/1.21 gradle.properties.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/1.21 gradle.properties.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,39 @@ +# Important Notes: +# Every field you add must be added to the root build.gradle expandProps map. + +# Project +version=${BUILD_COORDS.version} +group=${BUILD_COORDS.groupId} +java_version=21 + +# Common +minecraft_version=1.21 +mod_name=${MOD_NAME} +mod_author=${AUTHORS} +mod_id=${MOD_ID} +license=${LICENSE.id} +credits= +description=${DESCRIPTION} +minecraft_version_range=[1.21, 1.22) +## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here +## https://projects.neoforged.net/neoforged/neoform +neo_form_version=1.21-20240613.152323 +# The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions +parchment_minecraft=1.21 +parchment_version=2024.06.23 + +# Fabric +fabric_version=0.100.1+1.21 +fabric_loader_version=0.15.11 + +# Forge +forge_version=51.0.17 +forge_loader_version_range=[51,) + +# NeoForge +neoforge_version=21.0.37-beta +neoforge_loader_version_range=[4,) + +# Gradle +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false Index: templates/multiloader/build.gradle.ft =================================================================== --- templates/multiloader/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,6 @@ +plugins { + // see https://fabricmc.net/develop/ for new versions + id 'fabric-loom' version '1.7-SNAPSHOT' apply false + // see https://projects.neoforged.net/neoforged/moddevgradle for new versions + id 'net.neoforged.moddev' version '0.1.110' apply false +} Index: templates/multiloader/buildSrc/build.gradle.ft =================================================================== --- templates/multiloader/buildSrc/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/buildSrc/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,3 @@ +plugins { + id 'groovy-gradle-plugin' +} Index: templates/multiloader/buildSrc/multiloader-common.gradle.ft =================================================================== --- templates/multiloader/buildSrc/multiloader-common.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/buildSrc/multiloader-common.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,123 @@ +plugins { + id 'java-library' + id 'maven-publish' +} + +base { + archivesName = "${mod_id}-${project.name}-${minecraft_version}" +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(java_version) + withSourcesJar() + withJavadocJar() +} + +repositories { + mavenCentral() + // https://docs.gradle.org/current/userguide/declaring_repositories.html#declaring_content_exclusively_found_in_one_repository + exclusiveContent { + forRepository { + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public' + } + } + filter { includeGroupAndSubgroups('org.spongepowered') } + } + exclusiveContent { + forRepositories( + maven { + name = 'ParchmentMC' + url = 'https://maven.parchmentmc.org/' + }, + maven { + name = "NeoForge" + url = 'https://maven.neoforged.net/releases' + } + ) + filter { includeGroup('org.parchmentmc.data') } + } + maven { + name = 'BlameJared' + url = 'https://maven.blamejared.com' + } +} + +// Declare capabilities on the outgoing configurations. +// Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> + configurations."$variant".outgoing { + capability("$group:${base.archivesName.get()}:$version") + capability("$group:$mod_id-${project.name}-${minecraft_version}:$version") + capability("$group:$mod_id:$version") + } + publishing.publications.configureEach { + suppressPomMetadataWarningsFor(variant) + } +} + +sourcesJar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${mod_name}" } + } +} + +jar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${mod_name}" } + } + + manifest { + attributes([ + 'Specification-Title' : mod_name, + 'Specification-Vendor' : mod_author, + 'Specification-Version' : project.jar.archiveVersion, + 'Implementation-Title' : project.name, + 'Implementation-Version': project.jar.archiveVersion, + 'Implementation-Vendor' : mod_author, + 'Built-On-Minecraft' : minecraft_version + ]) + } +} + +processResources { + var expandProps = [ + 'version' : version, + 'group' : project.group, //Else we target the task's group. + 'minecraft_version' : minecraft_version, + 'minecraft_version_range' : minecraft_version_range, + 'fabric_version' : fabric_version, + 'fabric_loader_version' : fabric_loader_version, + 'mod_name' : mod_name, + 'mod_author' : mod_author, + 'mod_id' : mod_id, + 'license' : license, + 'description' : project.description, + 'neoforge_version' : neoforge_version, + 'neoforge_loader_version_range': neoforge_loader_version_range, + "forge_version": forge_version, + "forge_loader_version_range": forge_loader_version_range, + 'credits' : credits, + 'java_version' : java_version + ] + + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', '*.mixins.json']) { + expand expandProps + } + inputs.properties(expandProps) +} + +publishing { + publications { + register('mavenJava', MavenPublication) { + artifactId base.archivesName.get() + from components.java + } + } + repositories { + maven { + url System.getenv('local_maven_url') + } + } +} Index: templates/multiloader/buildSrc/multiloader-loader.gradle.ft =================================================================== --- templates/multiloader/buildSrc/multiloader-loader.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/buildSrc/multiloader-loader.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,44 @@ +plugins { + id 'multiloader-common' +} + +configurations { + commonJava{ + canBeResolved = true + } + commonResources{ + canBeResolved = true + } +} + +dependencies { + compileOnly(project(':common')) { + capabilities { + requireCapability "$group:$mod_id" + } + } + commonJava project(path: ':common', configuration: 'commonJava') + commonResources project(path: ':common', configuration: 'commonResources') +} + +tasks.named('compileJava', JavaCompile) { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +processResources { + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +tasks.named('javadoc', Javadoc).configure { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +tasks.named('sourcesJar', Jar) { + dependsOn(configurations.commonJava) + from(configurations.commonJava) + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} Index: templates/multiloader/common/CommonClass.java.ft =================================================================== --- templates/multiloader/common/CommonClass.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/CommonClass.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,29 @@ +package ${MAIN_CLASS.packageName}; + +import ${MAIN_CLASS.packageName}.platform.Services; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.Items; + +// This class is part of the common project meaning it is shared between all supported loaders. Code written here can only +// import and access the vanilla codebase, libraries used by vanilla, and optionally third party libraries that provide +// common compatible binaries. This means common code can not directly use loader specific concepts such as Forge events +// however it will be compatible with all supported mod loaders. +public class CommonClass { + + // The loader specific projects are able to import and use any code from the common project. This allows you to + // write the majority of your code here and load it from your loader specific projects. This example has some + // code that gets invoked by the entry point of the loader specific projects. + public static void init() { + Constants.LOG.info("Hello from Common init on {}! we are currently in a {} environment!", Services.PLATFORM.getPlatformName(), Services.PLATFORM.getEnvironmentName()); + Constants.LOG.info("The ID for diamonds is {}", BuiltInRegistries.ITEM.getKey(Items.DIAMOND)); + + // It is common for all supported loaders to provide a similar feature that can not be used directly in the + // common code. A popular way to get around this is using Java's built-in service loader feature to create + // your own abstraction layer. You can learn more about this in our provided services class. In this example + // we have an interface in the common code and use a loader specific implementation to delegate our call to + // the platform specific approach. + if (Services.PLATFORM.isModLoaded("${MOD_ID}")) { + Constants.LOG.info("Hello to ${MOD_ID}"); + } + } +} Index: templates/multiloader/common/Constants.java.ft =================================================================== --- templates/multiloader/common/Constants.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/Constants.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,11 @@ +package ${MAIN_CLASS.packageName}; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Constants { + + public static final String MOD_ID = "${MOD_ID}"; + public static final String MOD_NAME = "${MOD_NAME}"; + public static final Logger LOG = LoggerFactory.getLogger(MOD_NAME); +} Index: templates/multiloader/common/IPlatformHelper.java.ft =================================================================== --- templates/multiloader/common/IPlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/IPlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,35 @@ +package ${MAIN_CLASS.packageName}.platform.services; + +public interface IPlatformHelper { + + /** + * Gets the name of the current platform + * + * @return The name of the current platform. + */ + String getPlatformName(); + + /** + * Checks if a mod with the given id is loaded. + * + * @param modId The mod to check if it is loaded. + * @return True if the mod is loaded, false otherwise. + */ + boolean isModLoaded(String modId); + + /** + * Check if the game is currently in a development environment. + * + * @return True if in a development environment, false otherwise. + */ + boolean isDevelopmentEnvironment(); + + /** + * Gets the name of the environment type as a string. + * + * @return The name of the environment type. + */ + default String getEnvironmentName() { + return isDevelopmentEnvironment() ? "development" : "production"; + } +} Index: templates/multiloader/common/MixinMinecraft.java.ft =================================================================== --- templates/multiloader/common/MixinMinecraft.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/MixinMinecraft.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,18 @@ +package ${MAIN_CLASS.packageName}.mixin; + +import ${MAIN_CLASS.packageName}.Constants; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MixinMinecraft { + + @Inject(at = @At("TAIL"), method = "") + private void init(CallbackInfo info) { + Constants.LOG.info("This line is printed by the ${MOD_NAME} common mixin!"); + Constants.LOG.info("MC Version: {}", Minecraft.getInstance().getVersionType()); + } +} Index: templates/multiloader/common/Services.java.ft =================================================================== --- templates/multiloader/common/Services.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/Services.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,29 @@ +package ${MAIN_CLASS.packageName}.platform; + +import ${MAIN_CLASS.packageName}.Constants; +import ${MAIN_CLASS.packageName}.platform.services.IPlatformHelper; + +import java.util.ServiceLoader; + +// Service loaders are a built-in Java feature that allow us to locate implementations of an interface that vary from one +// environment to another. In the context of MultiLoader we use this feature to access a mock API in the common code that +// is swapped out for the platform specific implementation at runtime. +public class Services { + + // In this example we provide a platform helper which provides information about what platform the mod is running on. + // For example this can be used to check if the code is running on Forge vs Fabric, or to ask the modloader if another + // mod is loaded. + public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class); + + // This code is used to load a service for the current environment. Your implementation of the service must be defined + // manually by including a text file in META-INF/services named with the fully qualified class name of the service. + // Inside the file you should write the fully qualified class name of the implementation to load for the platform. For + // example our file on Forge points to ForgePlatformHelper while Fabric points to FabricPlatformHelper. + public static T load(Class clazz) { + final T loadedService = ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + Constants.LOG.debug("Loaded {} for service {}", loadedService, clazz); + return loadedService; + } +} Index: templates/multiloader/common/build.gradle.ft =================================================================== --- templates/multiloader/common/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,41 @@ +plugins { + id 'multiloader-common' + id 'net.neoforged.moddev' +} + +neoForge { + neoFormVersion = neo_form_version + // Automatically enable AccessTransformers if the file exists + def at = file('src/main/resources/META-INF/accesstransformer.cfg') + if (at.exists()) { + accessTransformers.add(at.absolutePath) + } + parchment { + minecraftVersion = parchment_minecraft + mappingsVersion = parchment_version + } +} + +dependencies { + compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' + // fabric and neoforge both bundle mixinextras, so it is safe to use it in common + compileOnly group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' + annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' +} + +configurations { + commonJava { + canBeResolved = false + canBeConsumed = true + } + commonResources { + canBeResolved = false + canBeConsumed = true + } +} + +artifacts { + commonJava sourceSets.main.java.sourceDirectories.singleFile + commonResources sourceSets.main.resources.sourceDirectories.singleFile +} + Index: templates/multiloader/common/mixins.json.ft =================================================================== --- templates/multiloader/common/mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "${MAIN_CLASS.packageName}.mixin", + "refmap": "${mod_id}.refmap.json", + "compatibilityLevel": "JAVA_18", + "mixins": [], + "client": [ + "MixinMinecraft" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} Index: templates/multiloader/common/pack.mcmeta.ft =================================================================== --- templates/multiloader/common/pack.mcmeta.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/common/pack.mcmeta.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "${mod_name}", + "pack_format": 8 + } +} Index: templates/multiloader/fabric/ExampleMod.java.ft =================================================================== --- templates/multiloader/fabric/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,18 @@ +package ${MAIN_CLASS.packageName}; + +import net.fabricmc.api.ModInitializer; + +public class ${MAIN_CLASS.className} implements ModInitializer { + + @Override + public void onInitialize() { + + // This method is invoked by the Fabric mod loader when it is ready + // to load your mod. You can access Fabric and Common code in this + // project. + + // Use Fabric to bootstrap the Common mod. + Constants.LOG.info("Hello Fabric world!"); + CommonClass.init(); + } +} Index: templates/multiloader/fabric/FabricPlatformHelper.java.ft =================================================================== --- templates/multiloader/fabric/FabricPlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/FabricPlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,22 @@ +package ${MAIN_CLASS.packageName}.platform; + +import ${MAIN_CLASS.packageName}.platform.services.IPlatformHelper; +import net.fabricmc.loader.api.FabricLoader; + +public class FabricPlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + return "Fabric"; + } + + @Override + public boolean isModLoaded(String modId) { + return FabricLoader.getInstance().isModLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + return FabricLoader.getInstance().isDevelopmentEnvironment(); + } +} Index: templates/multiloader/fabric/MixinTitleScreen.java.ft =================================================================== --- templates/multiloader/fabric/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,19 @@ +package ${MAIN_CLASS.packageName}.mixin; + +import ${MAIN_CLASS.packageName}.Constants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TitleScreen.class) +public class MixinTitleScreen { + + @Inject(at = @At("HEAD"), method = "init()V") + private void init(CallbackInfo info) { + Constants.LOG.info("This line is printed by the ${MOD_NAME} mixin from Fabric!"); + Constants.LOG.info("MC Version: {}", Minecraft.getInstance().getVersionType()); + } +} Index: templates/multiloader/fabric/build.gradle.ft =================================================================== --- templates/multiloader/fabric/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,37 @@ +plugins { + id 'multiloader-loader' + id 'fabric-loom' +} +dependencies { + minecraft "com.mojang:minecraft:${minecraft_version}" + mappings loom.layered { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") + } + modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" +} + +loom { + def aw = project(':common').file("src/main/resources/${mod_id}.accesswidener") + if (aw.exists()) { + accessWidenerPath.set(aw) + } + mixin { + defaultRefmapName.set("${mod_id}.refmap.json") + } + runs { + client { + client() + setConfigName('Fabric Client') + ideConfigGenerated(true) + runDir('runs/client') + } + server { + server() + setConfigName('Fabric Server') + ideConfigGenerated(true) + runDir('runs/server') + } + } +} Index: templates/multiloader/fabric/fabric.mixins.json.ft =================================================================== --- templates/multiloader/fabric/fabric.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/fabric.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "${MAIN_CLASS.packageName}.mixin", + "refmap": "${mod_id}.refmap.json", + "compatibilityLevel": "JAVA_21", + "mixins": [], + "client": [ + "MixinTitleScreen" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} Index: templates/multiloader/fabric/fabric.mod.json.ft =================================================================== --- templates/multiloader/fabric/fabric.mod.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/fabric.mod.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,35 @@ +{ + "schemaVersion": 1, + "id": "${mod_id}", + "version": "${version}", + "name": "${mod_name}", + "description": "${description}", + "authors": [ + "${mod_author}" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + "license": "${license}", + "icon": "${mod_id}.png", + "environment": "*", + "entrypoints": { + "main": [ + "${MAIN_CLASS}" + ] + }, + "mixins": [ + "${mod_id}.mixins.json", + "${mod_id}.fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabric_loader_version}", + "fabric-api": "*", + "minecraft": "${minecraft_version}", + "java": ">=${java_version}" + }, + "suggests": { + "another-mod": "*" + } +} Index: templates/multiloader/fabric/service.IPlatformHelper.ft =================================================================== --- templates/multiloader/fabric/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/fabric/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,1 @@ +${MAIN_CLASS.packageName}.platform.FabricPlatformHelper Index: templates/multiloader/forge/ExampleMod.java.ft =================================================================== --- templates/multiloader/forge/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,18 @@ +package ${MAIN_CLASS.packageName}; + +import net.minecraftforge.fml.common.Mod; + +@Mod(Constants.MOD_ID) +public class ${MAIN_CLASS.className} { + + public ${MAIN_CLASS.className}() { + // This method is invoked by the Forge mod loader when it is ready + // to load your mod. You can access Forge and Common code in this + // project. + + // Use Forge to bootstrap the Common mod. + Constants.LOG.info("Hello Forge world!"); + CommonClass.init(); + + } +} Index: templates/multiloader/forge/ForgePlatformHelper.java.ft =================================================================== --- templates/multiloader/forge/ForgePlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/ForgePlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,23 @@ +package ${MAIN_CLASS.packageName}.platform; + +import ${MAIN_CLASS.packageName}.platform.services.IPlatformHelper; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.loading.FMLLoader; + +public class ForgePlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + return "Forge"; + } + + @Override + public boolean isModLoaded(String modId) { + return ModList.get().isLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + return !FMLLoader.isProduction(); + } +} Index: templates/multiloader/forge/MixinTitleScreen.java.ft =================================================================== --- templates/multiloader/forge/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,19 @@ +package ${MAIN_CLASS.packageName}.mixin; + +import ${MAIN_CLASS.packageName}.Constants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TitleScreen.class) +public class MixinTitleScreen { + + @Inject(at = @At("HEAD"), method = "init()V") + private void init(CallbackInfo info) { + Constants.LOG.info("This line is printed by the ${MOD_NAME} mixin from Forge!"); + Constants.LOG.info("MC Version: {}", Minecraft.getInstance().getVersionType()); + } +} Index: templates/multiloader/forge/build.gradle.ft =================================================================== --- templates/multiloader/forge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,89 @@ +plugins { + id 'multiloader-loader' + id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' + id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' +} +base { + archivesName = "${mod_name}-forge-${minecraft_version}" +} +mixin { + config("${mod_id}.mixins.json") + config("${mod_id}.forge.mixins.json") +} + +minecraft { + mappings channel: 'official', version: minecraft_version + + copyIdeResources = true //Calls processResources when in dev + + reobf = false // Forge 1.20.6+ uses official mappings at runtime, so we shouldn't reobf from official to SRG + + // Automatically enable forge AccessTransformers if the file exists + // This location is hardcoded in Forge and can not be changed. + // https://github.com/MinecraftForge/MinecraftForge/blob/be1698bb1554f9c8fa2f58e32b9ab70bc4385e60/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java#L123 + // Forge still uses SRG names during compile time, so we cannot use the common AT's + def at = file('src/main/resources/META-INF/accesstransformer.cfg') + if (at.exists()) { + accessTransformer = at + } + + runs { + client { + workingDirectory file('runs/client') + ideaModule "${rootProject.name}.${project.name}.main" + taskName 'Client' + mods { + modClientRun { + source sourceSets.main + } + } + } + + server { + workingDirectory file('runs/server') + ideaModule "${rootProject.name}.${project.name}.main" + taskName 'Server' + mods { + modServerRun { + source sourceSets.main + } + } + } + + data { + workingDirectory file('runs/data') + ideaModule "${rootProject.name}.${project.name}.main" + args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + taskName 'Data' + mods { + modDataRun { + source sourceSets.main + } + } + } + } +} + +sourceSets.main.resources.srcDir 'src/generated/resources' + +dependencies { + minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" + annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") + + // Forge's hack fix + implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } +} + +publishing { + publications { + mavenJava(MavenPublication) { + fg.component(it) + } + } +} + +sourceSets.each { + def dir = layout.buildDirectory.dir("sourcesSets/$it.name") + it.output.resourcesDir = dir + it.java.destinationDirectory = dir +} Index: templates/multiloader/forge/forge.mixins.json.ft =================================================================== --- templates/multiloader/forge/forge.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/forge.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "${MAIN_CLASS.packageName}.mixin", + "compatibilityLevel": "JAVA_18", + "mixins": [], + "client": [ + "MixinTitleScreen" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} Index: templates/multiloader/forge/mods.toml.ft =================================================================== --- templates/multiloader/forge/mods.toml.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/mods.toml.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,27 @@ +modLoader = "javafml" #mandatory +loaderVersion = "${forge_loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See https://files.minecraftforge.net/ for a list of versions. +license = "${license}" # Review your options at https://choosealicense.com/. +#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional +#clientSideOnly=true #optional +[[mods]] #mandatory +modId = "${mod_id}" #mandatory +version = "${version}" #mandatory +displayName = "${mod_name}" #mandatory +#updateJSONURL="https://change.me.example.invalid/updates.json" #optional, see https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ +#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional, displayed in the mod UI +logoFile = "${mod_id}.png" #optional +credits = "${credits}" #optional +authors = "${mod_author}" #optional +description = '''${description}''' #mandatory Supports multiline text +[[dependencies."${mod_id}"]] #optional +modId = "forge" #mandatory +mandatory = true #mandatory +versionRange = "[${forge_version},)" #mandatory +ordering = "NONE" # The order that this dependency should load in relation to your mod, required to be either 'BEFORE' or 'AFTER' if the dependency is not mandatory +side = "BOTH" # Side this dependency is applied on - 'BOTH', 'CLIENT' or 'SERVER' +[[dependencies."${mod_id}"]] +modId = "minecraft" +mandatory = true +versionRange = "${minecraft_version_range}" +ordering = "NONE" +side = "BOTH" Index: templates/multiloader/forge/service.IPlatformHelper.ft =================================================================== --- templates/multiloader/forge/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/forge/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,1 @@ +${MAIN_CLASS.packageName}.platform.ForgePlatformHelper Index: templates/multiloader/neoforge/ExampleMod.java.ft =================================================================== --- templates/multiloader/neoforge/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/ExampleMod.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,19 @@ +package ${MAIN_CLASS.packageName}; + + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; + +@Mod(Constants.MOD_ID) +public class ${MAIN_CLASS.className} { + + public ${MAIN_CLASS.className}(IEventBus eventBus) { + // This method is invoked by the NeoForge mod loader when it is ready + // to load your mod. You can access NeoForge and Common code in this + // project. + + // Use NeoForge to bootstrap the Common mod. + Constants.LOG.info("Hello NeoForge world!"); + CommonClass.init(); + } +} Index: templates/multiloader/neoforge/MixinTitleScreen.java.ft =================================================================== --- templates/multiloader/neoforge/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/MixinTitleScreen.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,19 @@ +package ${MAIN_CLASS.packageName}.mixin; + +import ${MAIN_CLASS.packageName}.Constants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.TitleScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TitleScreen.class) +public class MixinTitleScreen { + + @Inject(at = @At("HEAD"), method = "init()V") + private void init(CallbackInfo info) { + Constants.LOG.info("This line is printed by the ${MOD_NAME} mixin from NeoForge!"); + Constants.LOG.info("MC Version: {}", Minecraft.getInstance().getVersionType()); + } +} Index: templates/multiloader/neoforge/NeoForgePlatformHelper.java.ft =================================================================== --- templates/multiloader/neoforge/NeoForgePlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/NeoForgePlatformHelper.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,23 @@ +package ${MAIN_CLASS.packageName}.platform; + +import ${MAIN_CLASS.packageName}.platform.services.IPlatformHelper; +import net.neoforged.fml.ModList; +import net.neoforged.fml.loading.FMLLoader; + +public class NeoForgePlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + return "NeoForge"; + } + + @Override + public boolean isModLoaded(String modId) { + return ModList.get().isLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + return !FMLLoader.isProduction(); + } +} Index: templates/multiloader/neoforge/build.gradle.ft =================================================================== --- templates/multiloader/neoforge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,39 @@ +plugins { + id 'multiloader-loader' + id 'net.neoforged.moddev' +} + +neoForge { + version = neoforge_version + // Automatically enable neoforge AccessTransformers if the file exists + def at = project(':common').file('src/main/resources/META-INF/accesstransformer.cfg') + if (at.exists()) { + accessTransformers.add(at.absolutePath) + } + parchment { + minecraftVersion = parchment_minecraft + mappingsVersion = parchment_version + } + runs { + configureEach { + systemProperty('neoforge.enabledGameTestNamespaces', mod_id) + ideName = "NeoForge ${it.name.capitalize()} (${project.path})" // Unify the run config names with fabric + } + client { + client() + } + data { + data() + } + server { + server() + } + } + mods { + "${mod_id}" { + sourceSet sourceSets.main + } + } +} + +sourceSets.main.resources { srcDir 'src/generated/resources' } Index: templates/multiloader/neoforge/neoforge.mixins.json.ft =================================================================== --- templates/multiloader/neoforge/neoforge.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/neoforge.mixins.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "${MAIN_CLASS.packageName}.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [], + "client": [ + "MixinTitleScreen" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} Index: templates/multiloader/neoforge/neoforge.mods.toml.ft =================================================================== --- templates/multiloader/neoforge/neoforge.mods.toml.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/neoforge.mods.toml.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,36 @@ +modLoader = "javafml" #mandatory +loaderVersion = "${neoforge_loader_version_range}" #mandatory +license = "${license}" # Review your options at https://choosealicense.com/. +#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional +[[mods]] #mandatory +modId = "${mod_id}" #mandatory +version = "${version}" #mandatory +displayName = "${mod_name}" #mandatory +#updateJSONURL="https://change.me.example.invalid/updates.json" #optional, see https://docs.neoforged.net/docs/misc/updatechecker/ +#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional, displayed in the mod UI +logoFile="${mod_id}.png" #optional +credits="${credits}" #optional +authors = "${mod_author}" #optional +description = '''${description}''' #mandatory Supports multiline text +[[mixins]] +config = "${mod_id}.mixins.json" +[[mixins]] +config = "${mod_id}.neoforge.mixins.json" +[[dependencies."${mod_id}"]] #optional +modId = "neoforge" #mandatory +type="required" #mandatory Can be one of "required", "optional", "incompatible" or "discouraged" +versionRange = "[${neoforge_version},)" #mandatory +ordering = "NONE" # The order that this dependency should load in relation to your mod, required to be either 'BEFORE' or 'AFTER' if the dependency is not mandatory +side = "BOTH" # Side this dependency is applied on - 'BOTH', 'CLIENT' or 'SERVER' +[[dependencies."${mod_id}"]] +modId = "minecraft" +type="required" #mandatory Can be one of "required", "optional", "incompatible" or "discouraged" +versionRange = "${minecraft_version_range}" +ordering = "NONE" +side = "BOTH" + +# Features are specific properties of the game environment, that you may want to declare you require. This example declares +# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't +# stop your mod loading on the server for example. +#[features.${mod_id}] +#openGLVersion="[3.2,)" Index: templates/multiloader/neoforge/service.IPlatformHelper.ft =================================================================== --- templates/multiloader/neoforge/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/neoforge/service.IPlatformHelper.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,1 @@ +${MAIN_CLASS.packageName}.platform.NeoForgePlatformHelper Index: templates/multiloader/settings.gradle.ft =================================================================== --- templates/multiloader/settings.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/multiloader/settings.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,51 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + exclusiveContent { + forRepository { + maven { + name = 'Fabric' + url = uri('https://maven.fabricmc.net') + } + } + filter { + includeGroup('net.fabricmc') + includeGroup('fabric-loom') + } + } + exclusiveContent { + forRepository { + maven { + name = 'Sponge' + url = uri('https://repo.spongepowered.org/repository/maven-public') + } + } + filter { + includeGroupAndSubgroups("org.spongepowered") + } + } + exclusiveContent { + forRepository { + maven { + name = 'Forge' + url = uri('https://maven.minecraftforge.net') + } + } + filter { + includeGroupAndSubgroups('net.minecraftforge') + } + } + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +// This should match the folder name of the project, or else IDEA may complain (see https://youtrack.jetbrains.com/issue/IDEA-317606) +rootProject.name = '${PROJECT_NAME}' +include('common') +include('fabric') +include('neoforge') +include('forge') Index: templates/neoforge/.mcdev.template.json =================================================================== --- templates/neoforge/.mcdev.template.json (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/neoforge/.mcdev.template.json (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -181,7 +181,7 @@ }, { "template": "neoforge.mods.toml.ft", - "destination": "src/main/resources/META-INF/neoforge.mods.toml" + "destination": "src/main/templates/META-INF/neoforge.mods.toml" }, { "template": "MixinsConfig.json.ft", @@ -189,6 +189,10 @@ "condition": "$USE_MIXINS" }, { + "template": "en_us.json.ft", + "destination": "src/main/resources/assets/${MOD_ID}/lang/en_us.json" + }, + { "template": "MainClass.java.ft", "destination": "src/main/java/${MAIN_CLASS.path}.java", "condition": "$LANGUAGE=='Java'", Index: templates/neoforge/MainClass.java.ft =================================================================== --- templates/neoforge/MainClass.java.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/neoforge/MainClass.java.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -80,7 +80,7 @@ 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. + // Note that this is necessary if and only if we want *this* class (${MAIN_CLASS.className}) 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); Index: templates/neoforge/build.gradle.ft =================================================================== --- templates/neoforge/build.gradle.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/neoforge/build.gradle.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -1,7 +1,5 @@ plugins { id 'java-library' - id 'eclipse' - id 'idea' id 'maven-publish' #if (${VERSIONS.minecraft.compareTo($mcver.MC1_21)} >= 0) id 'net.neoforged.moddev' version '${VERSIONS.moddev}' @@ -195,9 +193,7 @@ // 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. -// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. -// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html -tasks.withType(ProcessResources).configureEach { +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, @@ -212,12 +208,17 @@ mod_description : mod_description ] inputs.properties replaceProperties - - filesMatching(['META-INF/neoforge.mods.toml']) { - expand replaceProperties + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" - } +} -} +// Include the output of "generateModMetadata" as an input directory for the build +// 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 + // Example configuration to allow publishing using the maven-publish plugin publishing { publications { Index: templates/neoforge/en_us.json.ft =================================================================== --- templates/neoforge/en_us.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) +++ templates/neoforge/en_us.json.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -0,0 +1,5 @@ +{ + "itemGroup.${MOD_ID}": "Example Mod Tab", + "block.${MOD_ID}.example_block": "Example Block", + "item.${MOD_ID}.example_item": "Example Item" +} Index: templates/neoforge/neoforge.mods.toml.ft =================================================================== --- templates/neoforge/neoforge.mods.toml.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/neoforge/neoforge.mods.toml.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -42,13 +42,6 @@ #credits="" #optional # A text field displayed in the mod UI authors="${mod_authors}" #optional -# Display Test controls the display for your mod in the server connection screen -# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. -# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. -# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. -# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. -# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. -#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) # The description text for the mod (multi line!) (#mandatory) description='''${mod_description}''' Index: templates/sponge/build.gradle.kts.ft =================================================================== --- templates/sponge/build.gradle.kts.ft (revision 9d40d071e4c4a2eabbc5047a262714e0e4c2d7d3) +++ templates/sponge/build.gradle.kts.ft (revision f510e314041f65bb940a2ef370af44e85b183b32) @@ -60,14 +60,8 @@ loadOrder(PluginDependency.LoadOrder.AFTER) optional(false) } - #foreach (${DEPENDENCY} in ${DEPENDENCIES}) - dependency("${DEPEDENCY}") { - loadOrder(PluginDependency.LoadOrder.AFTER) - optional(false) - } + } - #end - } +} -} val javaTarget = ${JAVA_VERSION} // Sponge targets a minimum of Java ${JAVA_VERSION} #if ($LANGUAGE == 'Kotlin')