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.
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.

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
plugins {
@ -5,29 +10,58 @@ plugins {
id 'java-library'
id 'maven-publish'
id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7'
id 'eclipse'
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.27'
id 'com.matthewprenger.cursegradle' version '1.4.0'
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.35'
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
id 'com.modrinth.minotaur' version '2.+' apply false
id 'org.jetbrains.changelog' version '2.2.0'
}
version = project.mod_version
group = project.maven_group
archivesBaseName = project.archives_base_name
apply from: 'gradle/scripts/helpers.gradle'
// 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 {
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
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 {
@ -36,44 +70,36 @@ configurations {
}
minecraft {
mcVersion = '1.12.2'
mcVersion.set('1.12.2')
// MCP Mappings
mcpMappingChannel = 'stable'
mcpMappingVersion = '39'
// Set username here, the UUID will be looked up automatically
username = 'Developer'
mcpMappingChannel.set(propertyString('mapping_channel'))
mcpMappingVersion.set(propertyString('mapping_version'))
useDependencyAccessTransformers.set(propertyBool('use_dependency_at_files'))
username.set(propertyString('minecraft_username'))
// 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
def args = ["-ea:${project.group}"]
if (project.use_coremod.toBoolean()) {
args << '-Dfml.coreMods.load=' + coremod_plugin_class_name
}
if (project.use_mixins.toBoolean()) {
def args = ['-ea:' + group]
if (propertyBool('use_mixins')) {
args << '-Dmixin.hotSwap=true'
args << '-Dmixin.checks.interfaces=true'
args << '-Dmixin.debug.export=true'
}
extraRunJvmArguments.addAll(args)
extraRunJvmArguments.addAll(propertyStringList('extra_jvm_args'))
// Include and use dependencies' Access Transformer files
useDependencyAccessTransformers = true
// Add any properties you want to swap out for a dynamic value at build time here
// Any properties here will be added to a class at build time, the name can be configured below
// 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")
if (propertyBool('use_tags')) {
if (file('tags.properties').exists()) {
Properties props = new Properties().tap { it.load(file('tags.properties').newInputStream()); it }
if (!props.isEmpty()) {
injectedTags.set(props.collectEntries { k, v -> [(k): interpolate(v)] })
}
}
}
}
repositories {
@ -81,34 +107,29 @@ repositories {
name 'CleanroomMC Maven'
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 {
if (project.use_assetmover.toBoolean()) {
implementation 'com.cleanroommc:assetmover:2.5'
if (propertyBool('use_modern_java_syntax')) {
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()) {
implementation 'zone.rong:mixinbooter:7.1'
if (propertyBool('use_asset_mover')) {
implementation "com.cleanroommc:assetmover:${propertyString('asset_mover_version')}"
}
// Example of deobfuscating a dependency
// 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")
if (propertyBool('use_mixins')) {
String mixin = modUtils.enableMixins("zone.rong:mixinbooter:${propertyString('mixin_booter_version')}", propertyString('mixin_refmap'))
api (mixin) {
transitive = false
}
@ -119,50 +140,65 @@ dependencies {
transitive = false
}
}
}
apply from: 'gradle/scripts/dependencies.gradle'
// Adds Access Transformer files to tasks
if (project.use_access_transformer.toBoolean()) {
for (File at : sourceSets.getByName("main").resources.files) {
if (at.name.toLowerCase().endsWith("_at.cfg")) {
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at)
if (propertyBool('use_access_transformer')) {
for (def location : propertyStringList('access_transformer_locations')) {
def fileLocation = file("${projectDir}/src/main/resources/${location}")
if (fileLocation.exists()) {
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(fileLocation)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(fileLocation)
} else {
throw new GradleException("Access Transformer file [$fileLocation] does not exist!")
}
}
}
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
filesMatching(['mcmod.info', 'pack.mcmeta']) { fcd ->
// Replace version and mcversion
fcd.expand (
'version': project.version,
'mcversion': project.minecraft.version
def filterList = ['mcmod.info', 'pack.mcmeta']
filterList.addAll(propertyStringList('mixin_configs').collect(config -> "mixins.${config}.json" as String))
filesMatching(filterList) { fcd ->
fcd.expand(
'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()) {
rename '(.+_at.cfg)', 'META-INF/$1' // Make sure Access Transformer files are in META-INF folder
if (propertyBool('use_access_transformer')) {
rename '(.+_at.cfg)', 'META-INF/$1'
}
}
jar {
manifest {
def attribute_map = [:]
if (project.use_coremod.toBoolean()) {
attribute_map['FMLCorePlugin'] = project.coremod_plugin_class_name
if (project.include_mod.toBoolean()) {
if (propertyBool('is_coremod')) {
attribute_map['FMLCorePlugin'] = propertyString('coremod_plugin_class_name')
if (propertyBool('coremod_includes_mod')) {
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()) {
attribute_map['FMLAT'] = project.archives_base_name + '_at.cfg'
if (propertyBool('use_access_transformer')) {
attribute_map['FMLAT'] = propertyString('access_transformer_locations')
}
attributes(attribute_map)
}
@ -202,6 +238,99 @@ idea {
}
}
tasks.named("processIdeaSettings").configure {
dependsOn("injectTags")
compileTestJava {
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.
# This is required to provide enough memory for the Minecraft decompilation process.
# Gradle Properties
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_version = 1.0
maven_group = com.cleanroommc
archives_base_name = modid
# HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/
mod_version = 1.0.0
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
use_mixins = false
use_coremod = false
use_assetmover = false
# Mapping Properties
mapping_channel = stable
mapping_version = 39
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
access_transformer_locations = ${mod_id}_at.cfg
# Coremod Arguments
include_mod = true
coremod_plugin_class_name =
# Mixins
# 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 =
# 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
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
zipStoreBase=GRADLE_USER_HOME
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": "examplemod",
"name": "Example Mod",
"description": "Example placeholder mod.",
"version": "${version}",
"mcversion": "${mcversion}",
"url": "",
"updateUrl": "",
"authorList": ["CleanroomMC"],
"credits": "Authors of this project",
"logoFile": "",
"screenshots": [],
"dependencies": []
}
]
[{
"modid": "${mod_id}",
"name": "${mod_name}",
"version": "${mod_version}",
"mcversion": "1.12.2",
"description": "${mod_description}",
"authorList": ${mod_authors},
"credits": "${mod_credits}",
"url": "${mod_url}",
"updateJSON": "${mod_update_json}",
"logoFile": "${mod_logo_path}"
}]

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": {
"description": "examplemod resources",
"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)."
}
}
"pack": {
"description": "${mod_name} Resources",
"pack_format": 3
}
}

3
tags.properties Normal file
View file

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