Merge overhaul branch to be upstream (#24)

* Debug mode for publishing artifacts
* Jabel
* Generation of mod meta, pack meta and mixin jsons
* Fixed runObfServer using 1.7's main class rather than 1.12's
- Allows changing of source without it being regenerated in dev
* ExampleMod + fixing tag collection
* Template expanding for mcmod.info + pack.mcmeta + remove redundant tasks
- Now supports arbitrary script blocks to retrieve value `${{ }}` from directly in gradle.properties
* Deployment via tasks/actions + changelog support + script folder
* Fixed mixin json generating condition
* Fix ATs not being applied
* Allow mixinbooter & configanytime to be prioritized in obf runs
* Remove redundant coremod arg addition as manifest is read at runtime
* Allow processResources to work correctly
* refactor: make parser changelog as method instead of job
* fix: ensure correct header parser for changelog (2to2 and 3to3)
* fix: no env available due to Github don't automatic inject env value to GHA
* refactor: standardize mod version with SemVer, remove unnecessary changelog block in `build.gradle`
* refactor: mixin config template and generator, resource filter
* Updated Gradle to 8.7 + RetroFuturaGradle to 1.3.35
* Update MixinBooter to 9.1 + provide wiki link

Co-authored-by: Oganesson897 <101081378+Darknight123MC@users.noreply.github.com>
Co-authored-by: Li <nhatlinh.l195@gmail.com>
Co-authored-by: Li <li.hvktqs@gmail.com>
This commit is contained in:
Rongmario 2024-04-07 18:39:25 +01:00 committed by GitHub
parent 7db468db1e
commit c82fcee8aa
Signed by: GitHub
GPG key ID: B5690EEEBB952194
16 changed files with 730 additions and 133 deletions

61
.github/workflows/deploy.yml vendored Normal file
View file

@ -0,0 +1,61 @@
# A deployment template that works out of the box
# It supports these objectives:
# - Deploy to Maven (Build Job) [Secrets: MAVEN_USER, MAVEN_PASS]
# - Deploy to CurseForge (Upload Job) [Secrets: CURSEFORGE_TOKEN]
# - Deploy to Modrinth (Upload Job) [Secrets: MODRINTH_TOKEN]
name: Deploy
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Grant Execute Permission for gradlew
run: chmod +x gradlew
- name: Read gradle.properties
uses: BrycensRanch/read-properties-action@v1
id: properties
with:
file: gradle.properties
all: true
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Publish to Maven
if: steps.properties.outputs.publish_to_maven == 'true' && steps.properties.outputs.publish_to_local_maven == 'true'
uses: gradle/gradle-build-action@v2
with:
arguments: |
publish
-P${{ steps.properties.outputs.maven_name }}Username=${{ secrets.MAVEN_USER }}
-P${{ steps.properties.outputs.maven_name }}Password=${{ secrets.MAVEN_PASS }}
- name: Publish to CurseForge
if: steps.properties.outputs.publish_to_curseforge == 'true'
uses: gradle/gradle-build-action@v2
env:
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
with:
arguments: curseforge
- name: Publish to Modrinth
if: steps.properties.outputs.publish_to_modrinth == 'true'
uses: gradle/gradle-build-action@v2
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
with:
arguments: modrinth

6
CHANGELOG.md Normal file
View file

@ -0,0 +1,6 @@
# Changelog
## [1.0.0] - 2023-09-15
### Added
- This is a default template changelog that follows the [KeepAChangelog Convention](https://keepachangelog.com/en/1.1.0/)

View file

@ -2,7 +2,7 @@
Template workspace for modding Minecraft 1.12.2. Licensed under MIT, it is made for public use. Template workspace for modding Minecraft 1.12.2. Licensed under MIT, it is made for public use.
This template currently utilizies **Gradle 8.1.1** + **[RetroFuturaGradle](https://github.com/GTNewHorizons/RetroFuturaGradle) 1.3.27** + **Forge 14.23.5.2847**. This template currently utilizies **Gradle 8.7** + **[RetroFuturaGradle](https://github.com/GTNewHorizons/RetroFuturaGradle) 1.3.35** + **Forge 14.23.5.2847**.
With **coremod and mixin support** that is easy to configure. With **coremod and mixin support** that is easy to configure.

View file

@ -1,3 +1,8 @@
/**
* It is advised that you do not edit anything in the build.gradle; unless you are sure of what you are doing
*/
import com.gtnewhorizons.retrofuturagradle.mcp.InjectTagsTask
import org.jetbrains.changelog.Changelog
import org.jetbrains.gradle.ext.Gradle import org.jetbrains.gradle.ext.Gradle
plugins { plugins {
@ -5,29 +10,58 @@ plugins {
id 'java-library' id 'java-library'
id 'maven-publish' id 'maven-publish'
id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7'
id 'eclipse' id 'com.gtnewhorizons.retrofuturagradle' version '1.3.35'
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.27' id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
id 'com.matthewprenger.cursegradle' version '1.4.0' id 'com.modrinth.minotaur' version '2.+' apply false
id 'org.jetbrains.changelog' version '2.2.0'
} }
version = project.mod_version apply from: 'gradle/scripts/helpers.gradle'
group = project.maven_group
archivesBaseName = project.archives_base_name // Early Assertions
assertProperty 'mod_version'
assertProperty 'root_package'
assertProperty 'mod_id'
assertProperty 'mod_name'
assertSubProperties 'use_tags', 'tag_class_name'
assertSubProperties 'use_access_transformer', 'access_transformer_locations'
assertSubProperties 'use_mixins', 'mixin_booter_version', 'mixin_refmap'
assertSubProperties 'is_coremod', 'coremod_includes_mod', 'coremod_plugin_class_name'
assertSubProperties 'use_asset_mover', 'asset_mover_version'
setDefaultProperty 'use_modern_java_syntax', false, false
setDefaultProperty 'generate_sources_jar', true, false
setDefaultProperty 'generate_javadocs_jar', true, false
setDefaultProperty 'mapping_channel', true, 'stable'
setDefaultProperty 'mapping_version', true, '39'
setDefaultProperty 'use_dependency_at_files', true, true
setDefaultProperty 'minecraft_username', true, 'Developer'
setDefaultProperty 'extra_jvm_args', false, ''
setDefaultProperty 'extra_tweak_classes', false, ''
setDefaultProperty 'change_minecraft_sources', false, false
version = propertyString('mod_version')
group = propertyString('root_package')
base {
archivesName.set(propertyString('mod_id'))
}
tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources')
// Set the toolchain version to decouple the Java we run Gradle with from the Java used to compile and run the mod
java { java {
toolchain { toolchain {
languageVersion.set(JavaLanguageVersion.of(8)) languageVersion.set(JavaLanguageVersion.of(propertyBool('use_modern_java_syntax') ? 16 : 8))
// Azul covers the most platforms for Java 8 toolchains, crucially including MacOS arm64 // Azul covers the most platforms for Java 8 toolchains, crucially including MacOS arm64
vendor.set(org.gradle.jvm.toolchain.JvmVendorSpec.AZUL) vendor.set(JvmVendorSpec.AZUL)
}
if (propertyBool('generate_sources_jar')) {
withSourcesJar()
}
if (propertyBool('generate_javadocs_jar')) {
withJavadocJar()
} }
// Generate sources and javadocs jars when building and publishing
withSourcesJar()
// withJavadocJar()
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
} }
configurations { configurations {
@ -36,44 +70,36 @@ configurations {
} }
minecraft { minecraft {
mcVersion = '1.12.2' mcVersion.set('1.12.2')
// MCP Mappings mcpMappingChannel.set(propertyString('mapping_channel'))
mcpMappingChannel = 'stable' mcpMappingVersion.set(propertyString('mapping_version'))
mcpMappingVersion = '39'
// Set username here, the UUID will be looked up automatically useDependencyAccessTransformers.set(propertyBool('use_dependency_at_files'))
username = 'Developer'
username.set(propertyString('minecraft_username'))
// Add any additional tweaker classes here // Add any additional tweaker classes here
// extraTweakClasses.add('org.spongepowered.asm.launch.MixinTweaker') extraTweakClasses.addAll(propertyStringList('extra_tweak_classes'))
// Add various JVM arguments here for runtime // Add various JVM arguments here for runtime
def args = ["-ea:${project.group}"] def args = ['-ea:' + group]
if (project.use_coremod.toBoolean()) { if (propertyBool('use_mixins')) {
args << '-Dfml.coreMods.load=' + coremod_plugin_class_name
}
if (project.use_mixins.toBoolean()) {
args << '-Dmixin.hotSwap=true' args << '-Dmixin.hotSwap=true'
args << '-Dmixin.checks.interfaces=true' args << '-Dmixin.checks.interfaces=true'
args << '-Dmixin.debug.export=true' args << '-Dmixin.debug.export=true'
} }
extraRunJvmArguments.addAll(args) extraRunJvmArguments.addAll(args)
extraRunJvmArguments.addAll(propertyStringList('extra_jvm_args'))
// Include and use dependencies' Access Transformer files if (propertyBool('use_tags')) {
useDependencyAccessTransformers = true if (file('tags.properties').exists()) {
Properties props = new Properties().tap { it.load(file('tags.properties').newInputStream()); it }
// Add any properties you want to swap out for a dynamic value at build time here if (!props.isEmpty()) {
// Any properties here will be added to a class at build time, the name can be configured below injectedTags.set(props.collectEntries { k, v -> [(k): interpolate(v)] })
// Example: }
// injectedTags.put('VERSION', project.version) }
// injectedTags.put('MOD_ID', project.archives_base_name) }
}
// Generate a group.archives_base_name.Tags class
tasks.injectTags.configure {
// Change Tags class' name here:
outputClassName.set("${project.group}.${project.archives_base_name}.Tags")
} }
repositories { repositories {
@ -81,34 +107,29 @@ repositories {
name 'CleanroomMC Maven' name 'CleanroomMC Maven'
url 'https://maven.cleanroommc.com' url 'https://maven.cleanroommc.com'
} }
maven {
name 'SpongePowered Maven'
url 'https://repo.spongepowered.org/maven'
}
maven {
name 'CurseMaven'
url 'https://cursemaven.com'
content {
includeGroup 'curse.maven'
}
}
mavenLocal() // Must be last for caching to work
} }
dependencies { dependencies {
if (project.use_assetmover.toBoolean()) { if (propertyBool('use_modern_java_syntax')) {
implementation 'com.cleanroommc:assetmover:2.5' annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
// Workaround for https://github.com/bsideup/jabel/issues/174
annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0'
compileOnly ('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
transitive = false
}
// Allow jdk.unsupported classes like sun.misc.Unsafe, workaround for JDK-8206937 and fixes crashes in tests
patchedMinecraft 'me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0'
// Include for tests
testAnnotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
testCompileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
transitive = false // We only care about the 1 annotation class
}
} }
if (project.use_mixins.toBoolean()) { if (propertyBool('use_asset_mover')) {
implementation 'zone.rong:mixinbooter:7.1' implementation "com.cleanroommc:assetmover:${propertyString('asset_mover_version')}"
} }
if (propertyBool('use_mixins')) {
// Example of deobfuscating a dependency String mixin = modUtils.enableMixins("zone.rong:mixinbooter:${propertyString('mixin_booter_version')}", propertyString('mixin_refmap'))
// implementation rfg.deobf('curse.maven:had-enough-items-557549:4543375')
if (project.use_mixins.toBoolean()) {
// Change your mixin refmap name here:
String mixin = modUtils.enableMixins('org.spongepowered:mixin:0.8.3', "mixins.${project.archives_base_name}.refmap.json")
api (mixin) { api (mixin) {
transitive = false transitive = false
} }
@ -119,50 +140,65 @@ dependencies {
transitive = false transitive = false
} }
} }
} }
apply from: 'gradle/scripts/dependencies.gradle'
// Adds Access Transformer files to tasks // Adds Access Transformer files to tasks
if (project.use_access_transformer.toBoolean()) { if (propertyBool('use_access_transformer')) {
for (File at : sourceSets.getByName("main").resources.files) { for (def location : propertyStringList('access_transformer_locations')) {
if (at.name.toLowerCase().endsWith("_at.cfg")) { def fileLocation = file("${projectDir}/src/main/resources/${location}")
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at) if (fileLocation.exists()) {
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at) tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(fileLocation)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(fileLocation)
} else {
throw new GradleException("Access Transformer file [$fileLocation] does not exist!")
} }
} }
} }
processResources { processResources {
// This will ensure that this task is redone when the versions change
inputs.property 'version', project.version
inputs.property 'mcversion', project.minecraft.version
// Replace various properties in mcmod.info and pack.mcmeta if applicable def filterList = ['mcmod.info', 'pack.mcmeta']
filesMatching(['mcmod.info', 'pack.mcmeta']) { fcd -> filterList.addAll(propertyStringList('mixin_configs').collect(config -> "mixins.${config}.json" as String))
// Replace version and mcversion
fcd.expand ( filesMatching(filterList) { fcd ->
'version': project.version, fcd.expand(
'mcversion': project.minecraft.version 'mod_id': propertyString('mod_id'),
'mod_name': propertyString('mod_name'),
'mod_version': propertyString('mod_version'),
'mod_description': propertyString('mod_description'),
'mod_authors': "[${propertyStringList('mod_authors', ',').join(', ')}]",
'mod_credits': propertyString('mod_credits'),
'mod_url': propertyString('mod_url'),
'mod_update_json': propertyString('mod_update_json'),
'mod_logo_path': propertyString('mod_logo_path'),
'mixin_refmap': propertyString('mixin_refmap'),
'mixin_package': propertyString('mixin_package')
) )
} }
if (project.use_access_transformer.toBoolean()) { if (propertyBool('use_access_transformer')) {
rename '(.+_at.cfg)', 'META-INF/$1' // Make sure Access Transformer files are in META-INF folder rename '(.+_at.cfg)', 'META-INF/$1'
} }
} }
jar { jar {
manifest { manifest {
def attribute_map = [:] def attribute_map = [:]
if (project.use_coremod.toBoolean()) { if (propertyBool('is_coremod')) {
attribute_map['FMLCorePlugin'] = project.coremod_plugin_class_name attribute_map['FMLCorePlugin'] = propertyString('coremod_plugin_class_name')
if (project.include_mod.toBoolean()) { if (propertyBool('coremod_includes_mod')) {
attribute_map['FMLCorePluginContainsFMLMod'] = true attribute_map['FMLCorePluginContainsFMLMod'] = true
attribute_map['ForceLoadAsMod'] = project.gradle.startParameter.taskNames[0] == "build" def currentTasks = gradle.startParameter.taskNames
if (currentTasks[0] == 'build' || currentTasks[0] == 'prepareObfModsFolder' || currentTasks[0] == 'runObfClient') {
attribute_map['ForceLoadAsMod'] = true
}
} }
} }
if (project.use_access_transformer.toBoolean()) { if (propertyBool('use_access_transformer')) {
attribute_map['FMLAT'] = project.archives_base_name + '_at.cfg' attribute_map['FMLAT'] = propertyString('access_transformer_locations')
} }
attributes(attribute_map) attributes(attribute_map)
} }
@ -202,6 +238,99 @@ idea {
} }
} }
tasks.named("processIdeaSettings").configure { compileTestJava {
dependsOn("injectTags") sourceCompatibility = targetCompatibility = 8
} }
test {
javaLauncher.set(javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(8)
})
}
String parserChangelog() {
if (!file('CHANGELOG.md').exists()) {
throw new GradleException('publish_with_changelog is true, but CHANGELOG.md does not exist in the workspace!')
}
String parsedChangelog = changelog.renderItem(
changelog.get(propertyString('mod_version')).withHeader(false).withEmptySections(false),
Changelog.OutputType.MARKDOWN)
if (parsedChangelog.isEmpty()) {
throw new GradleException('publish_with_changelog is true, but the changelog for the latest version is empty!')
}
return parsedChangelog
}
tasks.register('generateMixinJson') {
group 'cleanroom helpers'
def missingConfig = propertyStringList('mixin_configs').findAll(config -> !file("src/main/resources/mixins.${config}.json").exists())
onlyIf {
if (propertyBool('use_mixins') && propertyBool('generate_mixins_json')) {
return !missingConfig.empty
}
return false
}
doLast {
for (String mixinConfig : missingConfig) {
def file = file("src/main/resources/mixins.${mixinConfig}.json")
file << """{\n\t"package": "",\n\t"required": true,\n\t"refmap": "${mixin_refmap}",\n\t"target": "@env(DEFAULT)",\n\t"minVersion": "0.8.5",\n\t"compatibilityLevel": "JAVA_8",\n\t"mixins": [],\n\t"server": [],\n\t"client": []\n}"""
}
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
if (propertyBool('use_modern_java_syntax')) {
if (it.name in ['compileMcLauncherJava', 'compilePatchedMcJava']) {
return
}
sourceCompatibility = 17
options.release.set(8)
javaCompiler.set(javaToolchains.compilerFor {
languageVersion.set(JavaLanguageVersion.of(16))
vendor.set(JvmVendorSpec.AZUL)
})
}
}
tasks.register('cleanroomAfterSync') {
group 'cleanroom helpers'
dependsOn 'injectTags', 'generateMixinJson'
}
if (propertyBool('use_modern_java_syntax')) {
tasks.withType(Javadoc).configureEach {
sourceCompatibility = 17
}
}
tasks.named('injectTags', InjectTagsTask).configure {
onlyIf {
return propertyBool('use_tags') && !it.getTags().get().isEmpty()
}
it.outputClassName.set(propertyString('tag_class_name'))
}
tasks.named('prepareObfModsFolder').configure {
finalizedBy 'prioritizeCoremods'
}
tasks.register('prioritizeCoremods') {
dependsOn 'prepareObfModsFolder'
doLast {
fileTree('run/obfuscated').forEach {
if (it.isFile() && it.name =~ '(mixinbooter|configanytime)(-)([0-9])+\\.+([0-9])+(.jar)') {
it.renameTo(new File(it.parentFile, "!${it.name}"))
}
}
}
}
idea.project.settings {
taskTriggers {
afterSync 'cleanroomAfterSync'
}
}
apply from: 'gradle/scripts/publishing.gradle'
apply from: 'gradle/scripts/extra.gradle'

View file

@ -1,22 +1,122 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties. # Gradle Properties
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs = -Xmx3G org.gradle.jvmargs = -Xmx3G
# Source Options
# Use Modern Java(9+) Syntax (Courtesy of Jabel)
use_modern_java_syntax = false
# Compilation Options
generate_sources_jar = true
generate_javadocs_jar = false
# Mod Information # Mod Information
mod_version = 1.0 # HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/
maven_group = com.cleanroommc mod_version = 1.0.0
archives_base_name = modid root_package = com.example
mod_id = modid
mod_name = Mod Name
# If any properties changes below this line, run `gradlew setupDecompWorkspace` and refresh gradle again to ensure everything is working correctly. # Mod Metadata (Optional)
mod_description =
mod_url =
mod_update_json =
# Delimit authors with commas
mod_authors =
mod_credits =
mod_logo_path =
# Boilerplate Options # Mapping Properties
use_mixins = false mapping_channel = stable
use_coremod = false mapping_version = 39
use_assetmover = false use_dependency_at_files = true
# Access Transformer files should be in the root of `resources` folder and with the filename formatted as: `{archives_base_name}_at.cfg` # Run Configurations
# If multiple arguments/tweak classes are stated, use spaces as the delimiter
minecraft_username = Developer
extra_jvm_args =
extra_tweak_classes =
# Maven Publishing (Provide secret: MAVEN_USER, MAVEN_PASS)
publish_to_maven = false
# Good for debugging artifacts before uploading to remote maven
# GitHub actions won't run if this is true, test this by running the task `publishToMavenLocal`
publish_to_local_maven = false
maven_name = ${mod_name}
maven_url =
# Publishing
# release_type can only be: release, beta or alpha (applies to CurseForge / Modrinth)
release_type = release
publish_with_changelog = ${{ it.file('CHANGELOG.md').exists() }}
# Publishing to CurseForge (Provide secret: CURSEFORGE_TOKEN)
# To configure dependencies, head to publishing.gradle's curseforge block
publish_to_curseforge = false
# CurseForge project ID must be the numerical ID and not the slug
curseforge_project_id =
curseforge_debug = false
# Publishing to Modrinth (Provide secret: MODRINTH_TOKEN), the token must have the `CREATE_VERSION` and `PROJECT_WRITE` permissions
# To configure dependencies, head to publishing.gradle's modrinth block
publish_to_modrinth = false
modrinth_project_id =
# Allows gradle to publish updated READMEs to the project body (via the modrinthSyncBody task)
modrinth_sync_readme = false
modrinth_debug = false
# If any properties changes below this line, refresh gradle again to ensure everything is working correctly.
# Modify Minecraft Sources
# RetroFuturaGradle allows Minecraft sources to be edited, and have the changes reflected upon running it
# Good for previews when coremodding, or generally seeing how behaviours can change with certain code applied/unapplied
# Turning this on allows Minecraft sources to persist and not regenerate
change_minecraft_sources = false
# Tags
# A RetroFuturaGradle concept akin to Ant ReplaceTokens
# A class is generated at build-time for compilation, to describe properties that have values that could change at build time such as versioning
# Class name is configurable with the `tag_class_name` property
# Tag properties can be stated in the `tags.properties` file, references are allowed
use_tags = true
tag_class_name = ${root_package}.${mod_id}.Tags
# Access Transformers
# A way to change visibility of Minecraft's classes, methods and fields
# An example access transformer file is given in the path: `src/main/resources/example_at.cfg`
# AT files should be in the root of src/main/resources with the filename formatted as: `mod_id_at.cfg`
# Use the property `access_transformer_locations` to state custom AT files if you aren't using the default `mod_id_at.cfg` location
# If multiple locations are stated, use spaces as the delimiter
use_access_transformer = false use_access_transformer = false
access_transformer_locations = ${mod_id}_at.cfg
# Coremod Arguments # Mixins
include_mod = true # Powerful tool to do runtime description changes of classes
# Wiki: https://github.com/SpongePowered/Mixin/wiki + https://github.com/CleanroomMC/MixinBooter/ + https://cleanroommc.com/wiki/forge-mod-development/mixin/preface
# Only use mixins once you understand the underlying structure
use_mixins = false
mixin_booter_version = 9.1
# A configuration defines a mixin set, and you may have as many mixin sets as you require for your application.
# Each config can only have one and only one package root.
# Generate missing configs, obtain from mixin_configs and generate file base on name convention: "mixins.config_name.json"
# You should change package root once they are generated
generate_mixins_json = true
# Delimit configs with spaces. Should only put configs name instead of full file name
mixin_configs = ${mod_id}
# A refmap is a json that denotes mapping conversions, this json is generated automatically, with the name `mixins.mod_id.refmap.json`
# Use the property `mixin_refmap` if you want it to use a different name, only one name is accepted
mixin_refmap = mixins.${mod_id}.refmap.json
# Coremods
# The most powerful way to change java classes at runtime, it is however very primitive with little documentation.
# Only make a coremod if you are absolutely sure of what you are doing
# Change the property `coremod_includes_mod` to false if your coremod doesn't have a @Mod annotation
# You MUST state a class name for `coremod_plugin_class_name` if you are making a coremod, the class should implement `IFMLLoadingPlugin`
is_coremod = false
coremod_includes_mod = true
coremod_plugin_class_name = coremod_plugin_class_name =
# AssetMover
# Convenient way to allow downloading of assets from official vanilla Minecraft servers, CurseForge, or any direct links
# Documentation: https://github.com/CleanroomMC/AssetMover
use_asset_mover = false
asset_mover_version = 2.5

View file

@ -0,0 +1,62 @@
apply from: 'gradle/scripts/helpers.gradle'
repositories {
// Other repositories described by default:
// CleanroomMC: https://maven.cleanroommc.com
exclusiveContent {
forRepository {
maven {
name 'CurseMaven'
url 'https://cursemaven.com'
}
}
filter {
includeGroup 'curse.maven'
}
}
exclusiveContent {
forRepository {
maven {
name 'Modrinth'
url 'https://api.modrinth.com/maven'
}
}
filter {
includeGroup 'maven.modrinth'
}
}
mavenLocal() // Must be last for caching to work
}
dependencies {
// Example - Dependency descriptor:
// 'com.google.code.gson:gson:2.8.6' << group: com.google.code.gson, name:gson, version:2.8.6
// 'group:name:version:classifier' where classifier is optional
// Example - Deobfuscating dependencies:
// rfg.deobf('curse.maven:had-enough-items-557549:4543375')
// By wrapping a dependency descriptor in rfg.deobf() method call, the dependency is queued for deobfuscation
// When deobfuscating, RFG respects the mapping_channel + mapping_version stated in gradle.properties
// Example - CurseMaven dependencies:
// 'curse.maven:had-enough-items-557549:4543375' << had-enough-items = project slug, 557549 = project id, 4543375 = file id
// Full documentation: https://cursemaven.com/
// Example - Modrinth dependencies:
// 'maven.modrinth:jei:4.16.1.1000' << jei = project name, 4.16.1.1000 = file version
// Full documentation: https://docs.modrinth.com/docs/tutorials/maven/
// Common dependency types (configuration):
// implementation = dependency available at both compile time and runtime
// runtimeOnly = runtime dependency
// compileOnly = compile time dependency
// annotationProcessor = annotation processing dependencies
// Transitive dependencies:
// (Dependencies that your dependency depends on)
// If you wish to exclude transitive dependencies in the described dependencies
// Use a closure as such:
// implementation ('com.google.code.gson:gson:2.8.6') {
// transitive = false
// }
}

View file

@ -0,0 +1,5 @@
// You may write any gradle buildscript component in this file
// This file is automatically applied after build.gradle + dependencies.gradle is ran
// If you wish to use the default helper methods, uncomment the line below
// apply from: 'gradle/scripts/helpers.gradle'

View file

@ -0,0 +1,96 @@
import groovy.text.SimpleTemplateEngine
import org.codehaus.groovy.runtime.MethodClosure
ext.propertyString = this.&propertyString as MethodClosure
ext.propertyBool = this.&propertyBool as MethodClosure
ext.propertyStringList = this.&propertyStringList as MethodClosure
ext.interpolate = this.&interpolate as MethodClosure
ext.assertProperty = this.&assertProperty as MethodClosure
ext.assertSubProperties = this.&assertSubProperties as MethodClosure
ext.setDefaultProperty = this.&setDefaultProperty as MethodClosure
ext.assertEnvironmentVariable = this.&assertEnvironmentVariable as MethodClosure
String propertyString(String key) {
return $property(key).toString()
}
boolean propertyBool(String key) {
return propertyString(key).toBoolean()
}
Collection<String> propertyStringList(String key) {
return propertyStringList(key, ' ')
}
Collection<String> propertyStringList(String key, String delimit) {
return propertyString(key).split(delimit).findAll { !it.isEmpty() }
}
private Object $property(String key) {
def value = project.findProperty(key)
if (value instanceof String) {
return interpolate(value)
}
return value
}
String interpolate(String value) {
if (value.startsWith('${{') && value.endsWith('}}')) {
value = value.substring(3, value.length() - 2)
Binding newBinding = new Binding(this.binding.getVariables())
newBinding.setProperty('it', this)
return new GroovyShell(this.getClass().getClassLoader(), newBinding).evaluate(value)
}
if (value.contains('${')) {
return new SimpleTemplateEngine().createTemplate(value).make(project.properties).toString()
}
return value
}
void assertProperty(String propertyName) {
def property = property(propertyName)
if (property == null) {
throw new GradleException("Property ${propertyName} is not defined!")
}
if (property.isEmpty()) {
throw new GradleException("Property ${propertyName} is empty!")
}
}
void assertSubProperties(String propertyName, String... subPropertyNames) {
assertProperty(propertyName)
if (propertyBool(propertyName)) {
for (String subPropertyName : subPropertyNames) {
assertProperty(subPropertyName)
}
}
}
void setDefaultProperty(String propertyName, boolean warn, defaultValue) {
def property = property(propertyName)
def exists = true
if (property == null) {
exists = false
if (warn) {
project.logger.log(LogLevel.WARN, "Property ${propertyName} is not defined!")
}
} else if (property.isEmpty()) {
exists = false
if (warn) {
project.logger.log(LogLevel.WARN, "Property ${propertyName} is empty!")
}
}
if (!exists) {
project.setProperty(propertyName, defaultValue.toString())
}
}
void assertEnvironmentVariable(String propertyName) {
def property = System.getenv(propertyName)
if (property == null) {
throw new GradleException("System Environment Variable $propertyName is not defined!")
}
if (property.isEmpty()) {
throw new GradleException("Property $propertyName is empty!")
}
}

View file

@ -0,0 +1,107 @@
apply from: 'gradle/scripts/helpers.gradle'
setDefaultProperty('publish_to_maven', true, false)
setDefaultProperty('publish_to_curseforge', true, false)
setDefaultProperty('publish_to_modrinth', true, false)
if (propertyBool('publish_to_maven')) {
assertProperty('maven_name')
assertProperty('maven_url')
publishing {
repositories {
maven {
name propertyString('maven_name').replaceAll("\\s", "")
url propertyString('maven_url')
credentials(PasswordCredentials)
}
}
publications {
mavenJava(MavenPublication) {
from components.java // Publish with standard artifacts
setGroupId(propertyString('root_package'))// Publish with root package as maven group
setArtifactId(propertyString('mod_id')) // Publish artifacts with mod id as the artifact id
// Custom artifact:
// If you want to publish a different artifact to the one outputted when building normally
// Create a different gradle task (Jar task), in extra.gradle
// Remove the 'from components.java' line above
// Add this line (change the task name):
// artifacts task_name
}
}
}
}
// Documentation here: https://github.com/matthewprenger/CurseGradle/wiki/
if (propertyBool('publish_to_curseforge')) {
apply plugin: 'com.matthewprenger.cursegradle'
assertProperty('curseforge_project_id')
assertProperty('release_type')
setDefaultProperty('curseforge_debug', false, false)
curseforge {
apiKey = System.getenv('CURSEFORGE_TOKEN') == null ? "" : System.getenv('CURSEFORGE_TOKEN')
// noinspection GroovyAssignabilityCheck
project {
id = propertyString('curseforge_project_id')
addGameVersion 'Java 8'
addGameVersion 'Forge'
addGameVersion '1.12.2'
releaseType = propertyString('release_type')
if (!propertyBool('publish_with_changelog')) {
changelog = parserChangelog()
changelogType = 'markdown'
}
mainArtifact tasks.reobfJar, {
displayName = "${propertyString('mod_name')} ${propertyString('mod_version')}"
if (propertyBool('use_mixins')) {
relations {
requiredDependency 'mixin-booter'
}
}
if (propertyBool('use_asset_mover')) {
relations {
requiredDependency 'assetmover'
}
}
}
options {
debug = propertyBool('curseforge_debug')
}
}
}
}
// Documentation here: https://github.com/modrinth/minotaur
if (propertyBool('publish_to_modrinth')) {
apply plugin: 'com.modrinth.minotaur'
assertProperty('modrinth_project_id')
assertProperty('release_type')
setDefaultProperty('modrinth_debug', false, false)
modrinth {
token = System.getenv('MODRINTH_TOKEN') ? "" : System.getenv('MODRINTH_TOKEN')
projectId = propertyString('modrinth_project_id')
versionNumber = propertyString('mod_version')
versionType = propertyString('release_type')
uploadFile = tasks.reobfJar
gameVersions = ['1.12.2']
loaders = ['forge']
debugMode = propertyBool('modrinth_debug')
if (propertyBool('use_mixins') || propertyBool('use_asset_mover')) {
dependencies {
if (propertyBool('use_mixins')) {
required.project 'mixinbooter'
}
if (propertyBool('use_asset_mover')) {
required.project 'assetmover'
}
}
}
if (!propertyBool('publish_with_changelog')) {
changelog = parserChangelog()
}
if (propertyBool('modrinth_sync_readme')) {
syncBodyFrom = file('README.md').text
tasks.modrinth.dependsOn(tasks.modrinthSyncBody)
}
}
}

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000 networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -1,2 +0,0 @@
- Here lies the root of the `io.github.cleanroommc` package, add another level with your mod id and use that as the root for your mod classes.

View file

@ -0,0 +1,24 @@
package com.example.modid;
import com.example.modid.Tags;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@Mod(modid = Tags.MOD_ID, name = Tags.MOD_NAME, version = Tags.VERSION)
public class ExampleMod {
public static final Logger LOGGER = LogManager.getLogger(Tags.MOD_NAME);
/**
* <a href="https://wiki.cleanroommc.com/mod-development/event/overview/">
* Take a look at how many FMLStateEvents you can listen to via the @Mod.EventHandler annotation here
* </a>
*/
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER.info("Hello From {}!", Tags.MOD_NAME);
}
}

View file

@ -1,16 +1,12 @@
[ [{
{ "modid": "${mod_id}",
"modid": "examplemod", "name": "${mod_name}",
"name": "Example Mod", "version": "${mod_version}",
"description": "Example placeholder mod.", "mcversion": "1.12.2",
"version": "${version}", "description": "${mod_description}",
"mcversion": "${mcversion}", "authorList": ${mod_authors},
"url": "", "credits": "${mod_credits}",
"updateUrl": "", "url": "${mod_url}",
"authorList": ["CleanroomMC"], "updateJSON": "${mod_update_json}",
"credits": "Authors of this project", "logoFile": "${mod_logo_path}"
"logoFile": "", }]
"screenshots": [],
"dependencies": []
}
]

View file

@ -0,0 +1,11 @@
{
"package": "",
"required": true,
"refmap": "${mixin_refmap}",
"target": "@env(DEFAULT)",
"minVersion": "0.8.5",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"server": [],
"client": []
}

View file

@ -1,7 +1,6 @@
{ {
"pack": { "pack": {
"description": "examplemod resources", "description": "${mod_name} Resources",
"pack_format": 3, "pack_format": 3
"_comment": "A pack_format of 3 should be used starting with Minecraft 1.11. All resources, including language files, should be lowercase (eg: en_us.lang). A pack_format of 2 will load your mod resources with LegacyV2Adapter, which requires language files to have uppercase letters (eg: en_US.lang)." }
}
} }

3
tags.properties Normal file
View file

@ -0,0 +1,3 @@
VERSION = ${mod_version}
MOD_ID = ${mod_id}
MOD_NAME = ${mod_name}