diff --git a/adapters/fabric/build.gradle b/adapters/fabric/build.gradle index 8127265c4..f5aefa5e2 100644 --- a/adapters/fabric/build.gradle +++ b/adapters/fabric/build.gradle @@ -181,6 +181,8 @@ dependencies { fabricApi = ((Map) irisModTarget.fabricModules).collect { String module, String moduleVersion -> "net.fabricmc.fabric-api:${module}:${moduleVersion}".toString() } + } + if (irisModTarget.fabricPermissions != null) { fabricApi.add("me.lucko:fabric-permissions-api:${irisModTarget.fabricPermissions}".toString()) } fabricApi.each { Object notation -> @@ -296,6 +298,8 @@ if (irisModTarget.fabricModules != null) { nestedFabricApiJars = ((Map) irisModTarget.fabricModules).collectEntries { String module, String ignored -> [(module): "${module}.jar".toString()] } +} +if (irisModTarget.fabricPermissions != null) { nestedFabricApiJars.put('fabric-permissions-api', 'fabric-permissions-api.jar') } diff --git a/adapters/forge/build.gradle b/adapters/forge/build.gradle index cae2321dd..8aa91b5a8 100644 --- a/adapters/forge/build.gradle +++ b/adapters/forge/build.gradle @@ -263,8 +263,9 @@ tasks.named('test').configure { processResources { inputs.property('version', irisVersion) inputs.property('minecraftVersion', minecraftVersion) + inputs.property('loaderRange', irisModTarget.forgeRange.toString()) filesMatching('META-INF/mods.toml') { - expand('version': irisVersion, 'minecraftVersion': minecraftVersion) + expand('version': irisVersion, 'minecraftVersion': minecraftVersion, 'loaderRange': irisModTarget.forgeRange.toString()) } } diff --git a/adapters/forge/src/main/resources/META-INF/mods.toml b/adapters/forge/src/main/resources/META-INF/mods.toml index 0c267e564..a3977a361 100644 --- a/adapters/forge/src/main/resources/META-INF/mods.toml +++ b/adapters/forge/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader = "javafml" -loaderVersion = "[66,67)" +loaderVersion = "${loaderRange}" license = "GPL-3.0" issueTrackerURL = "https://github.com/VolmitSoftware/Iris/issues" @@ -16,7 +16,7 @@ logoFile = "assets/irisworldgen/icon.png" [[dependencies.irisworldgen]] modId = "forge" mandatory = true -versionRange = "[66,67)" +versionRange = "${loaderRange}" ordering = "NONE" side = "BOTH" diff --git a/adapters/neoforge/build.gradle b/adapters/neoforge/build.gradle index cd92352f8..7343c7031 100644 --- a/adapters/neoforge/build.gradle +++ b/adapters/neoforge/build.gradle @@ -264,8 +264,9 @@ tasks.named('test').configure { processResources { inputs.property('version', irisVersion) inputs.property('minecraftVersion', minecraftVersion) + inputs.property('loaderRange', irisModTarget.neoForgeRange.toString()) filesMatching('META-INF/neoforge.mods.toml') { - expand('version': irisVersion, 'minecraftVersion': minecraftVersion) + expand('version': irisVersion, 'minecraftVersion': minecraftVersion, 'loaderRange': irisModTarget.neoForgeRange.toString()) } } diff --git a/adapters/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/adapters/neoforge/src/main/resources/META-INF/neoforge.mods.toml index a65393071..fbf789f52 100644 --- a/adapters/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/adapters/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -25,7 +25,7 @@ logoFile = "assets/irisworldgen/icon.png" [[dependencies.irisworldgen]] modId = "neoforge" type = "required" -versionRange = "[26.3.0.65-beta,26.4)" +versionRange = "${loaderRange}" ordering = "NONE" side = "BOTH" diff --git a/gradle/mod-target.gradle b/gradle/mod-target.gradle index bc882bbe7..384fea748 100644 --- a/gradle/mod-target.gradle +++ b/gradle/mod-target.gradle @@ -8,6 +8,9 @@ Map target = targets.get(targetMinecraft) if (target == null) { throw new GradleException("Unsupported Iris mod target ${targetMinecraft}; choose ${targets.keySet().join(', ')}") } +targets.each { String minecraft, Map candidate -> + candidate.put('overlays', candidate.get('overlays') ?: [minecraft]) +} ext.irisModTarget = target ext.irisModTargets = targets if (project.name.startsWith('iris-')) { diff --git a/gradle/mod-targets.json b/gradle/mod-targets.json index 3769a2540..e1df32669 100644 --- a/gradle/mod-targets.json +++ b/gradle/mod-targets.json @@ -4,7 +4,9 @@ "fabricRemap": true, "fabricLoader": "0.19.5", "forge": "1.21.1-52.1.20", + "forgeRange": "[52,53)", "neoForge": "21.1.262", + "neoForgeRange": "[21.1,21.2)", "nativeAccess": "minecraft1_21_1", "fabricModules": { "fabric-api-base": "0.4.42+6573ed8c19", @@ -25,7 +27,9 @@ "fabricRemap": false, "fabricLoader": "0.19.5", "forge": "26.3-66.0.8", + "forgeRange": "[66,67)", "neoForge": "26.3.0.83", + "neoForgeRange": "[26.3.0.65-beta,26.4)", "nativeAccess": "minecraft26_2", "slf4j": "2.0.17" } diff --git a/gradle/modded-version-sources.gradle b/gradle/modded-version-sources.gradle index c0ad7dba9..b0556f577 100644 --- a/gradle/modded-version-sources.gradle +++ b/gradle/modded-version-sources.gradle @@ -1,6 +1,6 @@ import groovy.json.JsonSlurper -String sourceMinecraftVersion = providers.gradleProperty('minecraftVersion').getOrElse('26.3') +List sourceOverlays = (List) irisModTarget.overlays List adapterSourceRoots = [projectDir, file('../modded-common'), file('../client-common')] tasks.named('compileTestJava', JavaCompile).configure { @@ -12,20 +12,33 @@ tasks.withType(Test).configureEach { }) } -['java', 'resources'].each { String kind -> - List overlays = adapterSourceRoots.collect { File adapter -> - new File(adapter, "src/versions/${sourceMinecraftVersion}/${kind}") +Closure> overlayDirectories = { File adapter, String kind -> + sourceOverlays.collect { String overlay -> new File(adapter, "src/versions/${overlay}/${kind}") } +} +Closure overlayOrigin = { List overlays, String path -> + for (int index = overlays.size() - 1; index >= 0; index--) { + if (new File(overlays.get(index), path).isFile()) { + return index + } } - if (!overlays.any { File directory -> directory.isDirectory() }) { + return -1 +} + +['java', 'resources'].each { String kind -> + if (!adapterSourceRoots.any { File adapter -> overlayDirectories(adapter, kind).any { File directory -> directory.isDirectory() } }) { return } TaskProvider prepareSources = tasks.register("prepareVersion${kind.capitalize()}", Sync) { adapterSourceRoots.each { File adapter -> - File overlay = new File(adapter, "src/versions/${sourceMinecraftVersion}/${kind}") + List overlays = overlayDirectories(adapter, kind) from(new File(adapter, "src/main/${kind}")) { - exclude { FileTreeElement entry -> new File(overlay, entry.path).isFile() } + exclude { FileTreeElement entry -> overlayOrigin(overlays, entry.path) >= 0 } + } + overlays.eachWithIndex { File overlay, int index -> + from(overlay) { + exclude { FileTreeElement entry -> !entry.directory && overlayOrigin(overlays, entry.path) != index } + } } - from(overlay) } includeEmptyDirs = false into(layout.buildDirectory.dir("generated/sources/iris/${kind}")) @@ -41,37 +54,49 @@ tasks.withType(Test).configureEach { tasks.named('verifyNativeBoundary').configure { dependsOn(prepareSources) } } -File testRulesFile = file("../modded-common/src/versions/${sourceMinecraftVersion}/test/source-replacements.json") -if (testRulesFile.isFile()) { - Map testRules = (Map) new JsonSlurper().parse(testRulesFile) +List testRulesFiles = sourceOverlays.collect { String overlay -> + file("../modded-common/src/versions/${overlay}/test/source-replacements.json") +} +boolean testOverlays = testRulesFiles.any { File rules -> rules.isFile() } || adapterSourceRoots.any { File adapter -> + overlayDirectories(adapter, 'test/java').any { File directory -> directory.isDirectory() } +} +if (testOverlays) { + List> testRules = testRulesFiles.collect { File rules -> + rules.isFile() ? (Map) new JsonSlurper().parse(rules) : [:] + } TaskProvider prepareTests = tasks.register('prepareVersionTests', Sync) { - inputs.file(testRulesFile) + testRulesFiles.findAll { File rules -> rules.isFile() }.each { File rules -> inputs.file(rules) } adapterSourceRoots.each { File adapter -> - File overlay = new File(adapter, "src/versions/${sourceMinecraftVersion}/test/java") + List overlays = overlayDirectories(adapter, 'test/java') from(new File(adapter, 'src/test/java')) { - exclude { FileTreeElement entry -> new File(overlay, entry.path).isFile() } + exclude { FileTreeElement entry -> overlayOrigin(overlays, entry.path) >= 0 } + } + overlays.eachWithIndex { File overlay, int index -> + from(overlay) { + exclude { FileTreeElement entry -> !entry.directory && overlayOrigin(overlays, entry.path) != index } + } } - from(overlay) } includeEmptyDirs = false into(layout.buildDirectory.dir('generated/sources/iris/test')) doLast { - List> rules = (List>) (testRules.get('global') ?: []) - Map>> fileRules = (Map>>) (testRules.get('files') ?: [:]) project.fileTree(destinationDir).matching { include('**/*.java') }.each { File source -> String path = destinationDir.toPath().relativize(source.toPath()).toString().replace(File.separator, '/') - boolean overridden = adapterSourceRoots.any { File adapter -> - new File(adapter, "src/versions/${sourceMinecraftVersion}/test/java/${path}").isFile() - } - if (!overridden) { - String content = source.getText('UTF-8') - String rewritten = content + int origin = adapterSourceRoots.collect { File adapter -> + overlayOrigin(overlayDirectories(adapter, 'test/java'), path) + }.max() + String content = source.getText('UTF-8') + String rewritten = content + for (int index = origin + 1; index < testRules.size(); index++) { + Map replacements = testRules.get(index) + List> rules = (List>) (replacements.get('global') ?: []) + Map>> fileRules = (Map>>) (replacements.get('files') ?: [:]) for (Map rule : rules + (fileRules.get(path) ?: [])) { rewritten = rewritten.replaceAll(rule.pattern, rule.replacement) } - if (content != rewritten) { - source.setText(rewritten, 'UTF-8') - } + } + if (content != rewritten) { + source.setText(rewritten, 'UTF-8') } } } diff --git a/gradle/native-minecraft-sources.gradle b/gradle/native-minecraft-sources.gradle index ef0818a30..836bc3647 100644 --- a/gradle/native-minecraft-sources.gradle +++ b/gradle/native-minecraft-sources.gradle @@ -1,4 +1,5 @@ import groovy.json.JsonSlurper +import java.util.zip.ZipEntry import java.util.zip.ZipFile Configuration nativeMinecraftSources = configurations.create('nativeMinecraftSources') { @@ -8,31 +9,42 @@ Configuration nativeMinecraftSources = configurations.create('nativeMinecraftSou String nativeSourceLoader = extensions.extraProperties.get('nativeSourceLoader') String nativeSourceImplementation = 'minecraft26_2' -String nativeSourceMinecraftVersion = providers.gradleProperty('minecraftVersion').getOrElse('26.3') -String versionPrefix = "versions/${nativeSourceMinecraftVersion}/" +List nativeSourceOverlays = (List) irisModTarget.overlays +List versionPrefixes = nativeSourceOverlays.collect { String overlay -> "versions/${overlay}/".toString() } extensions.extraProperties.set('nativeSourceImplementation', nativeSourceImplementation) dependencies.add(nativeMinecraftSources.name, "com.github.VolmitSoftware.VolmLib:native-${nativeSourceImplementation}-sources:master-SNAPSHOT") -Set overrides = new HashSet<>() -Map replacements = [:] +List> overlayEntries = versionPrefixes.collect { String ignored -> new HashSet() } +List> overlayReplacements = versionPrefixes.collect { String ignored -> new HashMap() } +Closure overlayOrigin = { String path -> + for (int index = overlayEntries.size() - 1; index >= 0; index--) { + if (overlayEntries.get(index).contains(path)) { + return index + } + } + return -1 +} TaskProvider unpackNativeMinecraftSources = tasks.register('unpackNativeMinecraftSources', Sync) { dependsOn(nativeMinecraftSources) - inputs.property('minecraftVersion', nativeSourceMinecraftVersion) + inputs.property('overlays', nativeSourceOverlays) inputs.property('loader', nativeSourceLoader) doFirst { - overrides.clear() + overlayEntries.each { Set entries -> entries.clear() } + overlayReplacements.each { Map rules -> rules.clear() } for (File artifact : nativeMinecraftSources) { new ZipFile(artifact).withCloseable { ZipFile archive -> - archive.entries().each { entry -> - if (entry.name.startsWith(versionPrefix)) { - overrides.add(entry.name.substring(versionPrefix.length())) + versionPrefixes.eachWithIndex { String versionPrefix, int index -> + archive.entries().each { ZipEntry entry -> + if (entry.name.startsWith(versionPrefix)) { + overlayEntries.get(index).add(entry.name.substring(versionPrefix.length())) + } } - } - java.util.zip.ZipEntry rules = archive.getEntry(versionPrefix + 'source-replacements.json') - if (rules != null) { - archive.getInputStream(rules).withCloseable { InputStream stream -> - replacements = (Map) new JsonSlurper().parse(stream) + ZipEntry rules = archive.getEntry(versionPrefix + 'source-replacements.json') + if (rules != null) { + archive.getInputStream(rules).withCloseable { InputStream stream -> + overlayReplacements.get(index).putAll((Map) new JsonSlurper().parse(stream)) + } } } } @@ -42,32 +54,40 @@ TaskProvider unpackNativeMinecraftSources = tasks.register('unpackNativeMi include('art/**', 'modded/**', "${nativeSourceLoader}/**", 'resources/modded/**', "resources/${nativeSourceLoader}/**") eachFile { FileCopyDetails source -> - if (overrides.contains(source.path)) { + if (overlayOrigin(source.path) >= 0) { source.exclude() } } } - from(provider { nativeMinecraftSources.collect { File artifact -> zipTree(artifact) } }) { - include("${versionPrefix}art/**", "${versionPrefix}modded/**", "${versionPrefix}${nativeSourceLoader}/**", - "${versionPrefix}resources/modded/**", "${versionPrefix}resources/${nativeSourceLoader}/**") - eachFile { FileCopyDetails source -> source.path = source.path.substring(versionPrefix.length()) } + versionPrefixes.eachWithIndex { String versionPrefix, int index -> + from(provider { nativeMinecraftSources.collect { File artifact -> zipTree(artifact) } }) { + include("${versionPrefix}art/**", "${versionPrefix}modded/**", "${versionPrefix}${nativeSourceLoader}/**", + "${versionPrefix}resources/modded/**", "${versionPrefix}resources/${nativeSourceLoader}/**") + eachFile { FileCopyDetails source -> + source.path = source.path.substring(versionPrefix.length()) + if (overlayOrigin(source.path) != index) { + source.exclude() + } + } + } } includeEmptyDirs = false into(layout.buildDirectory.dir('generated/sources/native-minecraft')) doLast { - List> rules = (List>) (replacements.get('global') ?: []) - Map>> fileRules = (Map>>) (replacements.get('files') ?: [:]) project.fileTree(destinationDir).matching { include('**/*.java') }.each { File source -> String path = destinationDir.toPath().relativize(source.toPath()).toString().replace(File.separator, '/') - if (!overrides.contains(path)) { - String content = source.getText('UTF-8') - String rewritten = content + String content = source.getText('UTF-8') + String rewritten = content + for (int index = overlayOrigin(path) + 1; index < overlayReplacements.size(); index++) { + Map replacements = overlayReplacements.get(index) + List> rules = (List>) (replacements.get('global') ?: []) + Map>> fileRules = (Map>>) (replacements.get('files') ?: [:]) for (Map rule : rules + (fileRules.get(path) ?: [])) { rewritten = rewritten.replaceAll(rule.pattern, rule.replacement) } - if (content != rewritten) { - source.setText(rewritten, 'UTF-8') - } + } + if (content != rewritten) { + source.setText(rewritten, 'UTF-8') } } }