mirror of
https://github.com/MinecraftForge/MinecraftForge
synced 2026-08-22 04:26:10 -04:00
Compare commits
35 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dae990880 | ||
|
|
f0f144156b | ||
|
|
d17cfd0b4b | ||
|
|
d697be351f | ||
|
|
703195cd36 | ||
|
|
3f1e9a90c9 | ||
|
|
da353a52fe | ||
|
|
3bac35089f | ||
|
|
cb2e205867 | ||
|
|
c5d015e60a | ||
|
|
72be0c9ccd | ||
|
|
dabe919492 | ||
|
|
3da1b644d0 | ||
|
|
d3476f3f80 | ||
|
|
6665cdcf4e | ||
|
|
d9665f6447 | ||
|
|
ec73fd5240 | ||
|
|
3bbdbacb81 | ||
|
|
478d8b3f18 | ||
|
|
03f928a3de | ||
|
|
4834f16aef | ||
|
|
7846d25606 | ||
|
|
77cb0c5c4e | ||
|
|
5e421e8b8b | ||
|
|
5f37e8af53 | ||
|
|
5ab792f1d7 | ||
|
|
38ebbf189c | ||
|
|
f247eebd55 | ||
|
|
555989cf10 | ||
|
|
49fe93b1b5 | ||
|
|
48167e93b4 | ||
|
|
2bd132a6f8 | ||
|
|
b8168a12df | ||
|
|
df271e0265 | ||
|
|
d7687a72d5 |
938 changed files with 11171 additions and 13750 deletions
2
.github/workflows/publish.yml
vendored
2
.github/workflows/publish.yml
vendored
|
|
@ -2,7 +2,7 @@ name: Publish
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ '26.1' ]
|
||||
branches: [ '26.2' ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
|
|||
17
.gitignore
vendored
17
.gitignore
vendored
|
|
@ -1,3 +1,6 @@
|
|||
#forgedev dev if the folder exists in here
|
||||
forgedev
|
||||
|
||||
#eclipse
|
||||
**/bin
|
||||
**/.settings
|
||||
|
|
@ -22,10 +25,12 @@
|
|||
/*/build
|
||||
/*/.gradle
|
||||
|
||||
# Minecraft
|
||||
/run
|
||||
/*.launch
|
||||
|
||||
# Projects repo, either ignore it, or ignore patches.
|
||||
/projects/mcp/
|
||||
/projects/clean/
|
||||
/projects/forge/
|
||||
src/minecraft
|
||||
|
||||
#occupational hazards
|
||||
/projects/**/build/
|
||||
|
|
@ -33,6 +38,7 @@
|
|||
/projects/**/run/
|
||||
/projects/**/*.launch
|
||||
/repo/
|
||||
/rejects-*/
|
||||
src/*/generated/**/.cache/
|
||||
|
||||
# Generated by gradle every import
|
||||
|
|
@ -47,3 +53,8 @@ src/*/generated/**/.cache/
|
|||
/*/.factorypath
|
||||
/*/.apt_generated/
|
||||
/fmlcore/logs/
|
||||
/lib/
|
||||
/_actual/
|
||||
/runs/
|
||||
/forge.ipr
|
||||
/forge.iws
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ parts herein are licensed under the terms of the LGPL 2.1 found
|
|||
here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and
|
||||
copied below.
|
||||
|
||||
Homepage: http://minecraftforge.net/
|
||||
Homepage: https://minecraftforge.net/
|
||||
https://github.com/MinecraftForge/MinecraftForge
|
||||
|
||||
|
||||
|
|
|
|||
812
build.gradle
812
build.gradle
|
|
@ -1,57 +1,795 @@
|
|||
import net.minecraftforge.forge.tasks.*
|
||||
import net.minecraftforge.gradleutils.PomUtils
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id 'net.minecraftforge.licenser' version '1.0.1'
|
||||
id 'com.github.ben-manes.versions' version '0.46.0'
|
||||
id 'net.minecraftforge.gradleutils' version '[2.6.4,2.7)'
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
id 'eclipse'
|
||||
id 'de.undercouch.download' version '5.4.0'
|
||||
id 'net.minecraftforge.gradle.patcher' version '[6.0.51,6.2)' apply false
|
||||
id 'net.minecraftforge.gradle.mcp' version '[6.0.51,6.2)' apply false
|
||||
id 'net.minecraftforge.gradlejarsigner' version '1.0.4'
|
||||
id 'org.barfuin.gradle.taskinfo' version '3.0.1'
|
||||
id 'maven-publish'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.versions
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
alias libs.plugins.jarsigner
|
||||
id 'net.minecraftforge.forgedev'
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
Util.init() //Init all our extension methods!
|
||||
gradleutils.displayName = 'Forge'
|
||||
group = 'net.minecraftforge'
|
||||
description = 'Modifications to Minecraft to enable mod developers.'
|
||||
|
||||
ext {
|
||||
VERSION = gitversion.getMCTagOffsetBranch(MC_VERSION)
|
||||
FORGE_VERSION = VERSION.substring(MC_VERSION.length() + 1)
|
||||
// NOTE: See settings.gradle for all the referenceable version variables.
|
||||
// All subprojects (that apply 'net.minecraftforge.forge.build.convention') will have these available.
|
||||
println "Version: $version"
|
||||
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
|
||||
jarSigner.autoDetect('forge')
|
||||
|
||||
// We have to tell ForgeDev to use the exact versions of tools we ship in the installer
|
||||
fdtools {
|
||||
configure('binpatcher') {
|
||||
version = buildLibs.binarypatcher.get().version
|
||||
}
|
||||
configure('installertools') {
|
||||
version = buildLibs.installertools.get().version
|
||||
}
|
||||
configure('jarcompatibilitychecker') {
|
||||
javaLauncher = javaToolchains.launcherFor(java.toolchain)
|
||||
}
|
||||
}
|
||||
|
||||
changelog {
|
||||
from '47.999'
|
||||
/* This is used for debugging, comparing all published artifacts against actual production
|
||||
forgedev.validatePublish {
|
||||
task {
|
||||
baseBranch = 'upstream/26.1.2'
|
||||
versionPrefix = minecraftVersion
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
final minecraftFiles = forgedev.minecraftFiles(minecraftVersion)
|
||||
|
||||
final mcpBase = forgedev.mcpBase {
|
||||
mcpVersion = "${minecraftVersion}-${project.ext.mcpVersion}"
|
||||
accessTransformers.from file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
sideAnnotationStrippers.from file('src/main/resources/forge.sas')
|
||||
}
|
||||
|
||||
forgedev.patches {
|
||||
base = mcpBase
|
||||
patches = file('patches/minecraft')
|
||||
patched = file('src/minecraft/java')
|
||||
sourceSets.main.java.srcDir patched
|
||||
}
|
||||
|
||||
tasks.register('setup') {
|
||||
dependsOn ':forge:extractMapped'
|
||||
if (findProject(':clean'))
|
||||
dependsOn ':clean:extractMapped'
|
||||
dependsOn forgedev.patches.apply
|
||||
}
|
||||
|
||||
tasks.register('doChecks') {
|
||||
dependsOn ':forge:checkJarCompatibility'
|
||||
dependsOn ':forge:publish'
|
||||
}
|
||||
|
||||
project(':mcp') {
|
||||
apply plugin: 'net.minecraftforge.gradle.mcp'
|
||||
mcp {
|
||||
config MC_VERSION + '-' + MCP_VERSION
|
||||
pipeline = 'joined'
|
||||
sourceSets {
|
||||
named('main') {
|
||||
resources.srcDir 'src/main/generated'
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
named('test') {
|
||||
resources.srcDir 'src/test/generated'
|
||||
}
|
||||
}
|
||||
|
||||
if (System.env.TEAMCITY_VERSION) {
|
||||
//Only setup the CI environment if and only if the environment variables are set.
|
||||
tasks.named('configureTeamCity').configure {
|
||||
doLast {
|
||||
println "##teamcity[buildNumber '${project(':forge').version}']"
|
||||
println "##teamcity[setParameter name='env.PUBLISHED_JAVA_ARTIFACT_VERSION' value='${project(':forge').version}']"
|
||||
license {
|
||||
header = file('LICENSE-header.txt')
|
||||
|
||||
include 'net/minecraftforge/'
|
||||
exclude 'net/minecraftforge/common/LenientUnboundedMapCodec.java'
|
||||
|
||||
tasks.tap {
|
||||
register('main') {
|
||||
files.from files('src/main/java')
|
||||
}
|
||||
|
||||
register('test') {
|
||||
files.from files('src/test/java')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changelog {
|
||||
from changelogBase
|
||||
publishAll = false
|
||||
}
|
||||
|
||||
// TODO [ForgeDev] Support compileOnlyApi, runtimeOnly, and a consumable annotation processor configuration
|
||||
configurations {
|
||||
// Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it.
|
||||
register('bootstrap') {
|
||||
transitive = false
|
||||
canBeDeclared = true
|
||||
canBeResolved = true
|
||||
}
|
||||
|
||||
register('installer') {
|
||||
transitive = false
|
||||
canBeDeclared = true
|
||||
canBeResolved = true
|
||||
extendsFrom(bootstrap)
|
||||
}
|
||||
|
||||
named('api') {
|
||||
extendsFrom(installer)
|
||||
}
|
||||
|
||||
named('implementation') {
|
||||
// Inherit vanilla Minecraft's dependencies
|
||||
extendsFrom(mcpBase.dependencyConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// These need to actually be on the classpath at the start. This is only used for the server shim jar.
|
||||
// And this is only needed because custom file systems are REQUIRED to be on the boot classloader.
|
||||
// This has ASM/BootStrap/Unsafe all because I haven't gotten around to moving UnionFileSystem out to its own project.
|
||||
bootstrap libs.jarjar.fs // JarInJar file system
|
||||
bootstrap libs.roimfs // JarInJar File System - FileSystems need to be on boot loader.
|
||||
bootstrap libs.bundles.jimfs // In memory file system used for ForgeDev launches
|
||||
bootstrap libs.securemodules // Has Union file system in it
|
||||
bootstrap libs.unsafe // Needed by securemodules
|
||||
bootstrap libs.bundles.asm // Needed by securemodules
|
||||
|
||||
implementation libs.jopt.simple
|
||||
|
||||
installer libs.bootstrap
|
||||
installer libs.bootstrap.api // Needed by securemodules
|
||||
installer libs.accesstransformers
|
||||
installer libs.eventbus
|
||||
installer libs.jspecify // Dep of EventBus
|
||||
installer libs.forgespi
|
||||
installer libs.coremods.api
|
||||
installer libs.modlauncher
|
||||
installer libs.mergetool.api
|
||||
installer libs.bundles.night.config
|
||||
installer libs.maven.artifact
|
||||
installer libs.bundles.terminalconsoleappender
|
||||
installer libs.mixin
|
||||
installer libs.mixinextras.forge
|
||||
installer libs.bundles.jarjar
|
||||
installer libs.roimfs
|
||||
|
||||
installer projects.fmlcore
|
||||
installer projects.fmlloader
|
||||
installer projects.fmlearlydisplay
|
||||
installer projects.javafmllanguage
|
||||
installer projects.lowcodelanguage
|
||||
installer projects.mclanguage
|
||||
installer projects.forgeTransformers
|
||||
|
||||
runtimeOnly files(mcpBase.extra)
|
||||
|
||||
runtimeOnly libs.bootstrap
|
||||
runtimeOnly libs.bootstrap.dev
|
||||
|
||||
annotationProcessor libs.eventbus.validator
|
||||
}
|
||||
|
||||
final EXTRA_TXTS = [
|
||||
file('LICENSE.txt'),
|
||||
changelog.task.flatMap(task -> task.outputFile)
|
||||
]
|
||||
forgedev.runs {
|
||||
configureEach {
|
||||
options {
|
||||
workingDir = layout.projectDirectory.dir("runs/$name")
|
||||
|
||||
mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap'
|
||||
args '--gameDir', '.'
|
||||
jvmArgs '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders'
|
||||
|
||||
systemProperty 'bsl.debug', 'true'
|
||||
systemProperty 'terminal.jline', 'true'
|
||||
with(sourceSets.test) {
|
||||
systemProperty 'forge.enableGameTest', 'true'
|
||||
systemProperty 'forgedev.enableTestMods', 'true'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create('client') {
|
||||
options {
|
||||
systemProperty 'eventbus.api.strictRuntimeChecks', 'true'
|
||||
systemProperty 'org.lwjgl.system.SharedLibraryExtractDirectory', 'lwjgl_dll'
|
||||
|
||||
args '--launchTarget', 'forge_dev_client',
|
||||
'--username', 'Dev',
|
||||
'--version', project.name,
|
||||
'--accessToken', '0',
|
||||
'--userType', 'mojang',
|
||||
'--versionType', 'release',
|
||||
'--assetsDir', '{assets_root}',
|
||||
'--assetIndex', '{asset_index}'
|
||||
}
|
||||
}
|
||||
|
||||
create('server') {
|
||||
options {
|
||||
args '--launchTarget', 'forge_dev_server'
|
||||
}
|
||||
}
|
||||
|
||||
create('gameTestServer') {
|
||||
options {
|
||||
args '--launchTarget', 'forge_dev_server_gametest'
|
||||
args '--uniqueWorld' // Unique world is used so that the world regenerates, as well as the world config isn't influenced by other runs
|
||||
}
|
||||
}
|
||||
|
||||
create('data') {
|
||||
options {
|
||||
args '--launchTarget', 'forge_dev_data',
|
||||
'--all',
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--assetsDir', '{assets_root}',
|
||||
'--assetIndex', '{asset_index}'
|
||||
|
||||
with(sourceSets.main) {
|
||||
args '--mod', 'forge',
|
||||
'--output', rootProject.file('src/main/generated/')
|
||||
}
|
||||
|
||||
with(sourceSets.test) {
|
||||
args '--mod', '.+',
|
||||
'--existing', sourceSets.test.resources.srcDirs[0],
|
||||
'--output', rootProject.file('src/test/generated/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create('clientData') {
|
||||
options {
|
||||
args '--all',
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--assetsDir', '{assets_root}',
|
||||
'--assetIndex', '{asset_index}'
|
||||
|
||||
with(sourceSets.main) {
|
||||
args '--launchTarget', 'forge_dev_client_data',
|
||||
'--mod', 'forge',
|
||||
'--output', rootProject.file('src/main/generated/'),
|
||||
'--mod', 'forge'
|
||||
}
|
||||
|
||||
with(sourceSets.test) {
|
||||
args '--launchTarget', 'forge_dev',
|
||||
'--launchEntry', 'minecraft/net.minecraft.client.data.Main',
|
||||
'--launchData',
|
||||
'--mod', '.+',
|
||||
'--existing', sourceSets.test.resources.srcDirs[0],
|
||||
'--output', rootProject.file('src/test/generated/')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.register('genAllData') {
|
||||
dependsOn forgedev.runs.data.run, forgedev.runs.data.runTest, forgedev.runs.clientData.run, forgedev.runs.clientData.runTest
|
||||
}
|
||||
|
||||
final serverShim = forgedev.shim {
|
||||
config {
|
||||
mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap'
|
||||
args = ['--launchTarget', 'forge_server']
|
||||
}
|
||||
classpath {
|
||||
libraries configurations.installer
|
||||
library tasks.named('universalJar', Jar)
|
||||
library forgedev.binaryPatches('server').apply, 'server'
|
||||
serverBundle.fileProvider(minecraftFiles.server)
|
||||
}
|
||||
bootstrapClasspath(configurations.bootstrap)
|
||||
jar {
|
||||
jarSigner.sign(it)
|
||||
}
|
||||
}
|
||||
|
||||
final finalizeSpawn = forgedev.methodCallFinder('findFinalizeSpawnTargets') {
|
||||
jar.fileProvider(mcpBase.classes)
|
||||
output = rootProject.file('forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json')
|
||||
blacklist 'net/minecraft/world/level/BaseSpawner' // Ignore this class as we special case it.
|
||||
invokeVirtual('finalizeSpawn', '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;')
|
||||
}
|
||||
|
||||
forgedev.validateDeprecations(tasks.named('jar', Jar)) {
|
||||
mcVersion = minecraftVersion
|
||||
}
|
||||
|
||||
forgedev.checks() {
|
||||
base = mcpBase
|
||||
ats {}
|
||||
sas {}
|
||||
execs {}
|
||||
|
||||
patches {
|
||||
dependsOn forgedev.patches.make
|
||||
patchDir = forgedev.patches.patches
|
||||
patchesWithS2SArtifact = [
|
||||
'minecraft/net/minecraft/client/renderer/ViewArea.java.patch',
|
||||
'minecraft/net/minecraft/data/models/blockstates/Variant.java.patch',
|
||||
]
|
||||
}
|
||||
|
||||
fix {
|
||||
dependsOn finalizeSpawn
|
||||
}
|
||||
|
||||
forgedev.patches.make.configure {
|
||||
finalizedBy forgedev.checks.patches.fix
|
||||
}
|
||||
}
|
||||
|
||||
final crowdin = forgedev.crowdin // Create the crowdin tasks
|
||||
tasks.named('jar', Jar) {
|
||||
from(EXTRA_TXTS)
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
exclude '.cache'
|
||||
|
||||
from(zipTree(crowdin.flatMap { it.output } )) {
|
||||
include 'assets/forge/lang/*.json'
|
||||
}
|
||||
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.forge'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : gradleutils.vendor.get(),
|
||||
'Specification-Version' : gitversion.info.tag,
|
||||
'Implementation-Title' : project.group,
|
||||
'Implementation-Vendor' : gradleutils.vendor.get(),
|
||||
'Implementation-Version': forgeVersion
|
||||
], 'net/minecraftforge/versions/forge/')
|
||||
attributes([
|
||||
'Specification-Title' : 'Minecraft',
|
||||
'Specification-Vendor' : gradleutils.vendor.get(),
|
||||
'Specification-Version' : minecraftVersion,
|
||||
'Implementation-Title' : 'MCP',
|
||||
'Implementation-Vendor' : gradleutils.vendor.get(),
|
||||
'Implementation-Version': mcpVersion
|
||||
], 'net/minecraftforge/versions/mcp/')
|
||||
}
|
||||
jarSigner.sign(it)
|
||||
}
|
||||
|
||||
final universalJar = tasks.register('universalJar', Jar) {
|
||||
from (zipTree(tasks.named('jar', Jar).flatMap { it.archiveFile } )) {
|
||||
exclude(forgedev.filterVanilla(mcpBase.classes))
|
||||
}
|
||||
manifest = tasks.named('jar', Jar).get().manifest
|
||||
archiveClassifier = 'universal'
|
||||
jarSigner.sign(it)
|
||||
}
|
||||
|
||||
final sourcesJarAll = tasks.register('sourcesJarAll', Jar) {
|
||||
archiveClassifier = 'sources-all'
|
||||
from(sourceSets.main.allJava.srcDirs)
|
||||
}
|
||||
|
||||
// Our sources, plus the patches we do to Vanilla Minecraft
|
||||
final sourcesJar = tasks.register('sourcesJar', Jar) {
|
||||
archiveClassifier = 'sources'
|
||||
from(sourceSets.main.allJava.srcDirs - forgedev.patches.patched.asFile.get())
|
||||
mustRunAfter(forgedev.patches.make)
|
||||
from(forgedev.patches.patches) {
|
||||
into 'patches/'
|
||||
}
|
||||
}
|
||||
|
||||
forgedev.userDev {
|
||||
base(mcpBase)
|
||||
|
||||
config {
|
||||
universal universalJar
|
||||
sources sourcesJar
|
||||
addLibraries(configurations.installer)
|
||||
// TODO [ForgeDev][UserDev] Split API/Runtime elements in userdev config
|
||||
// so we don't gotta keep making exceptions for MixinExtras
|
||||
addCompileDependency(libs.mixinextras.common)
|
||||
addAnnotationProcessorDependency(libs.mixinextras.common)
|
||||
|
||||
// TODO [ForgeDev] Consolidate Patcher + UserDev Config runs in a sane way
|
||||
runs {
|
||||
configureEach {
|
||||
parents = []
|
||||
main = 'net.minecraftforge.bootstrap.ForgeBootstrap'
|
||||
args '--gameDir', '.'
|
||||
jvmArgs '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders'
|
||||
client = it.name.containsIgnoreCase('client')
|
||||
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
||||
}
|
||||
|
||||
register('clientData') {
|
||||
args '--launchTarget', "forge_userdev_client_data"
|
||||
args '--assetIndex', '{asset_index}'
|
||||
args '--assetsDir', '{assets_root}'
|
||||
}
|
||||
|
||||
register('client') {
|
||||
property 'forge.enableGameTest', 'true'
|
||||
args '--launchTarget', "forge_userdev_client"
|
||||
args '--version', 'MOD_DEV'
|
||||
args '--assetIndex', '{asset_index}'
|
||||
args '--assetsDir', '{assets_root}'
|
||||
}
|
||||
|
||||
register('server') {
|
||||
property 'forge.enableGameTest', 'true'
|
||||
args '--launchTarget', "forge_userdev_server"
|
||||
}
|
||||
|
||||
register('gameTestServer') {
|
||||
args '--launchTarget', "forge_userdev_server_gametest"
|
||||
}
|
||||
|
||||
register('data') {
|
||||
args '--launchTarget', "forge_userdev_data"
|
||||
args '--assetIndex', '{asset_index}'
|
||||
args '--assetsDir', '{assets_root}'
|
||||
}
|
||||
}
|
||||
}
|
||||
patches {
|
||||
modified.setFrom(sourcesJarAll.flatMap { it.archiveFile })
|
||||
}
|
||||
binaryPatches {
|
||||
mustRunAfter(forgedev.patches.make)
|
||||
patches.setFrom(forgedev.patches.patches)
|
||||
dirty.setFrom(tasks.named('jar', Jar).flatMap { it.archiveFile })
|
||||
}
|
||||
}
|
||||
|
||||
forgedev.userdevCompatibility(minecraftVersion) {
|
||||
clean = mcpBase.classes
|
||||
dirty = tasks.named('jar', Jar)
|
||||
}
|
||||
|
||||
// region Installer tasks, Not needed when we simplify the installer/remove obf
|
||||
final clientBinPatches = forgedev.binaryPatches('client') {
|
||||
clean = minecraftFiles.client
|
||||
// Workaround for 3rd party launcher issues, marker needed to locate MC, store needed to fix zlib-ng issues
|
||||
apply {
|
||||
store = true
|
||||
marker = '.forge_patched_minecraft'
|
||||
}
|
||||
}
|
||||
final serverBinPatches = forgedev.binaryPatches('server') {
|
||||
clean = minecraftFiles.serverExtracted
|
||||
apply { store = true }
|
||||
}
|
||||
// endregion
|
||||
|
||||
forgedev.installer {
|
||||
dev = !forgedev.ci
|
||||
offline = false
|
||||
baseVersion = buildLibs.installer.get().version.toString()
|
||||
|
||||
// Add extra libraries
|
||||
pack serverShim.jar // The Server executable jar IS needed to be packed, as the installer would need a spec bump in order to download it
|
||||
pack universalJar // I don't think this is strictly needed to be packed anymore, will need to double check later
|
||||
|
||||
launcherLibrary universalJar
|
||||
// We configure the launcher here to keep the order for easier diff, after publishing, move this to the LauncherJson configuration below
|
||||
launcherJson {
|
||||
// We create this during install, so it's not downloadable
|
||||
generated(clientBinPatches.apply, 'client')
|
||||
}
|
||||
|
||||
launcherLibraries configurations.installer
|
||||
|
||||
final launcherId = "${minecraftVersion}-${project.name}-${forgeVersion}"
|
||||
final installertools = tool(buildLibs.installertools)
|
||||
final binarypatcher = tool(buildLibs.binarypatcher)
|
||||
|
||||
jar {
|
||||
from(EXTRA_TXTS)
|
||||
from(rootProject.file('/forge_installer_logo.png')) {
|
||||
rename { 'big_logo.png' }
|
||||
}
|
||||
from(clientBinPatches.create.flatMap { t -> t.output }) {
|
||||
rename { 'data/client.lzma' }
|
||||
}
|
||||
from(serverBinPatches.create.flatMap { t -> t.output }) {
|
||||
rename { 'data/server.lzma' }
|
||||
}
|
||||
|
||||
final argsFile = rootProject.file('server_files/args.txt')
|
||||
final tokens = [tokens: [
|
||||
SHIM_JAR_FILE: serverShim.jar.get().archiveFileName.get(),
|
||||
MAVEN_PATH: forgedev.mavenArtifact.directory
|
||||
]]
|
||||
from(argsFile) {
|
||||
filter(tokens, ReplaceTokens)
|
||||
into 'data'
|
||||
rename { 'unix_args.txt' }
|
||||
}
|
||||
from(argsFile) {
|
||||
filter(tokens, ReplaceTokens)
|
||||
into 'data'
|
||||
rename { 'win_args.txt' }
|
||||
}
|
||||
|
||||
from(rootProject.file('server_files')) {
|
||||
filter(tokens, ReplaceTokens)
|
||||
into 'data'
|
||||
exclude 'args.txt'
|
||||
}
|
||||
|
||||
jarSigner.sign(it)
|
||||
}
|
||||
json {
|
||||
icon = rootProject.file('icon.ico')
|
||||
executable serverShim.jar
|
||||
minecraft = minecraftVersion
|
||||
profileVersion = launcherId
|
||||
|
||||
final projectArtifact = "${project.group}:${project.name}:${project.version}"
|
||||
|
||||
data 'MC_UNPACKED', "[net.minecraft:client:${minecraftVersion}]", "[net.minecraft:server:${minecraftVersion}:unpacked]"
|
||||
data 'MC_UNPACKED_SHA', minecraftFiles.client, minecraftFiles.serverExtracted
|
||||
|
||||
data 'BINPATCH', '/data/client.lzma', '/data/server.lzma'
|
||||
data 'PATCHED', "[$projectArtifact:client]", "[$projectArtifact:server]"
|
||||
data 'PATCHED_SHA', clientBinPatches.apply.flatMap { it.output }, serverBinPatches.apply.flatMap { it.output }
|
||||
|
||||
steps = [
|
||||
extract(installertools) {
|
||||
side = 'server'
|
||||
archive '{INSTALLER}'
|
||||
extract 'data/README.txt', '{ROOT}/README.txt'
|
||||
extract 'data/run.sh', '{ROOT}/run.sh'
|
||||
executable '{ROOT}/run.sh'
|
||||
extract 'data/run.bat', '{ROOT}/run.bat'
|
||||
optional 'data/user_jvm_args.txt', '{ROOT}/user_jvm_args.txt'
|
||||
extract 'data/unix_args.txt', "{ROOT}/libraries/${forgedev.mavenArtifact.directory}/unix_args.txt"
|
||||
extract 'data/win_args.txt', "{ROOT}/libraries/${forgedev.mavenArtifact.directory}/win_args.txt"
|
||||
},
|
||||
extractBundle(installertools) {
|
||||
side = 'server'
|
||||
libraries()
|
||||
},
|
||||
extractBundle(installertools) {
|
||||
side = 'server'
|
||||
jar '{MINECRAFT_JAR}', '{MC_UNPACKED}'
|
||||
cache '{MC_UNPACKED}', '{MC_UNPACKED_SHA}'
|
||||
},
|
||||
step(binarypatcher) {
|
||||
side = 'server'
|
||||
args = [
|
||||
'--clean', '{MC_UNPACKED}',
|
||||
'--output', '{PATCHED}',
|
||||
'--apply', '{BINPATCH}',
|
||||
'--data', '--unpatched',
|
||||
'--store'
|
||||
]
|
||||
cache '{PATCHED}', '{PATCHED_SHA}'
|
||||
},
|
||||
step(binarypatcher) {
|
||||
side = 'client'
|
||||
args = [
|
||||
'--clean', '{MINECRAFT_JAR}',
|
||||
'--output', '{PATCHED}',
|
||||
'--apply', '{BINPATCH}',
|
||||
'--data', '--unpatched',
|
||||
'--store',
|
||||
'--marker', '.forge_patched_minecraft'
|
||||
]
|
||||
cache '{PATCHED}', '{PATCHED_SHA}'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
launcherJson {
|
||||
// These are flags to preserve glitchy old behavior to make diffing easier, removing when migrating to production is recommended
|
||||
sortLibraries = false // Don't sort, makes things non-deterministic, but easier to diff old versions
|
||||
duplicateLibraries = true // Our 'bootstrap' layer go added twice
|
||||
librariesLast = false // Makes libraries be added before args
|
||||
|
||||
id = launcherId
|
||||
inheritsFrom = minecraftVersion
|
||||
mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap'
|
||||
gameArgs = [ '--launchTarget', 'forge_client' ]
|
||||
jvmArgs = [ '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders' ]
|
||||
}
|
||||
}
|
||||
|
||||
final mdkGradleWrapper = tasks.register('mdkGradleWrapper', Wrapper) {
|
||||
gradleVersion = '9.5.0'
|
||||
scriptFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradlew")
|
||||
jarFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradle/wrapper/gradle-wrapper.jar")
|
||||
}
|
||||
|
||||
final mdkZip = tasks.register('mdkZip', Zip) {
|
||||
dependsOn mdkGradleWrapper
|
||||
|
||||
archiveBaseName = project.name
|
||||
archiveClassifier = 'mdk'
|
||||
archiveVersion = project.version
|
||||
destinationDirectory = file('build/libs')
|
||||
from(EXTRA_TXTS)
|
||||
|
||||
from mdkGradleWrapper.map(Wrapper.&getScriptFile)
|
||||
from mdkGradleWrapper.map(Wrapper.&getBatchScript)
|
||||
into('gradle/wrapper/') {
|
||||
from mdkGradleWrapper.map(Wrapper.&getJarFile)
|
||||
from mdkGradleWrapper.map(Wrapper.&getPropertiesFile)
|
||||
}
|
||||
from(rootProject.file('mdk/')){
|
||||
rootProject.file('mdk/gitignore.txt').eachLine {
|
||||
if (!it.trim().isEmpty() && !it.trim().startsWith('#'))
|
||||
exclude it
|
||||
}
|
||||
filter(ReplaceTokens, tokens: [
|
||||
FORGE_VERSION: forgeVersion,
|
||||
FORGE_GROUP: project.group,
|
||||
FORGE_NAME: project.name,
|
||||
MC_VERSION: minecraftVersion,
|
||||
FORGE_SPEC_VERSION: gitversion.info.tag.split("\\.")[0],
|
||||
MC_NEXT_VERSION: minecraftNextVersion,
|
||||
EVENTBUS_VERSION: libs.versions.eventbus.get()
|
||||
])
|
||||
rename 'gitignore\\.txt', '.gitignore'
|
||||
rename 'gitattributes\\.txt', '.gitattributes'
|
||||
}
|
||||
from(rootProject.file('src/test/java/com/example/examplemod/')) {
|
||||
into('src/main/java/com/example/examplemod/')
|
||||
}
|
||||
from(rootProject.file('src/test/generated/mdk_datagen/')) {
|
||||
into('src/main/resources/')
|
||||
exclude '**/.cache/'
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
tasks.named('javadoc', Javadoc) {
|
||||
description = 'Generates the combined javadocs for the FML projects and the main Forge project'
|
||||
var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage', ':forge-transformers' ]
|
||||
source includedProjects.collect { project(it).sourceSets.main.allJava }
|
||||
classpath = classpath + files(includedProjects.collect { project(it).sourceSets.main.compileClasspath })
|
||||
|
||||
var docsDir = rootProject.file('src/docs/')
|
||||
inputs.dir(docsDir)
|
||||
.withPropertyName('docs resources directory')
|
||||
.withPathSensitivity(PathSensitivity.RELATIVE)
|
||||
.optional()
|
||||
|
||||
failOnError = false
|
||||
|
||||
// Exclude the Minecraft classes if not enabled
|
||||
if (!project.hasProperty('generateAllDocumentation')) {
|
||||
exclude 'net/minecraft/**'
|
||||
exclude 'com/mojang/**'
|
||||
}
|
||||
exclude 'mcp/**'
|
||||
|
||||
options {
|
||||
stylesheetFile = new File(docsDir, 'stylesheet.css')
|
||||
|
||||
tags = [
|
||||
'apiNote:a:<em>API Note:</em>',
|
||||
'implSpec:a:<em>Implementation Requirements:</em>',
|
||||
'implNote:a:<em>Implementation Note:</em>'
|
||||
]
|
||||
|
||||
groups = [
|
||||
'Forge Mod Loader': [
|
||||
'net.minecraftforge.fml.common.asm*',
|
||||
'net.minecraftforge.fml.loading*',
|
||||
'net.minecraftforge.fml.server*'
|
||||
],
|
||||
'FML Core': [
|
||||
'net.minecraftforge.fml',
|
||||
'net.minecraftforge.fml.config*',
|
||||
'net.minecraftforge.fml.event*',
|
||||
'net.minecraftforge.fml.util*'
|
||||
],
|
||||
'FML Common': [
|
||||
'net.minecraftforge.fml.core',
|
||||
'net.minecraftforge.fml.event.config',
|
||||
'net.minecraftforge.fml.event.lifecycle'
|
||||
],
|
||||
'FML Java/MC Language Providers': [
|
||||
'net.minecraftforge.fml.common',
|
||||
'net.minecraftforge.fml.javafmlmod',
|
||||
'net.minecraftforge.fml.mclanguageprovider'
|
||||
],
|
||||
'Minecraft Forge API': [
|
||||
'net.minecraftforge*'
|
||||
]
|
||||
]
|
||||
|
||||
author = false
|
||||
noSince = true
|
||||
noHelp = true
|
||||
|
||||
bottom = "Minecraft Forge is an open source modding API for Minecraft: Java Edition, licensed under the Lesser GNU General Public License, version 2.1."
|
||||
windowTitle = "Minecraft Forge API ${version}"
|
||||
docTitle = "Minecraft Forge API - ${forgeVersion} for Minecraft ${minecraftVersion}"
|
||||
header = "<div style=\"margin-top: 9px;padding: 5px 6px;\"><strong>${forgeVersion} for Minecraft ${minecraftVersion}</strong></div>"
|
||||
}
|
||||
|
||||
doLast {
|
||||
project.copy {
|
||||
from docsDir
|
||||
exclude '/stylesheet.css'
|
||||
into destinationDir
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
artifact universalJar
|
||||
artifact forgedev.installer.jar
|
||||
artifact mdkZip
|
||||
artifact forgedev.userDev.jar
|
||||
artifact sourcesJar
|
||||
artifact serverShim.jar
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// These are debugging tasks that are only used when developing ForgeDevPlugin, to bulk test task's config/caching
|
||||
// region ForgeDev Tests
|
||||
def all = tasks.register('all') {}
|
||||
afterEvaluate {
|
||||
if (gradle.startParameter.taskNames.contains('all')) {
|
||||
tasks.forEach { task -> // This forces everything to be realized, which is why we have the startParameter check
|
||||
if (!gradle.startParameter.isTaskGraph() && task.name.startsWith('run')) return
|
||||
if (task.name in [all.name, 'dependencyInsight', 'dependencies', 'dependencyUpdates', 'init', 'buildEnvironment', 'idea',
|
||||
'eclipse', 'javaToolchains', 'outgoingVariants', 'projects', 'properties', 'resolvableConfigurations', 'tasks', 'updateDaemonJvm',
|
||||
'generateActionsWorkflow'
|
||||
]) return
|
||||
if (task.name.startsWith('clean')) return
|
||||
if (task.name == 'checkJarCompatibility') return // This doesn't work in FG6 dev, I think it's cuz we check vs srg names. Will need to look at later
|
||||
all.configure { dependsOn(task) }
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// endregion
|
||||
// We dont have any unit tests, so disable this error
|
||||
tasks.withType(AbstractTestTask).configureEach {
|
||||
failOnNoDiscoveredTests = false
|
||||
}
|
||||
// This shouldn't be needed according to the Gradle devs, as we never run these commands together.
|
||||
// But in another case of Gradle being gradle, here we are
|
||||
[ 'makePatches', 'compileJava', 'checkLicenseMain', 'updateLicenseMain', 'sourcesJar', 'sourcesJarAll' ]
|
||||
.each{ tasks.named(it).configure{ mustRunAfter forgedev.patches.apply }}
|
||||
forgedev.runs.configureEach {
|
||||
run.configure { dependsOn finalizeSpawn}
|
||||
runTest.configure { dependsOn finalizeSpawn}
|
||||
}
|
||||
// run gradlew dependencyUpdates --no-parallel
|
||||
//noinspection UnnecessaryQualifiedReference
|
||||
tasks.named('dependencyUpdates', com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask) {
|
||||
resolutionStrategy {
|
||||
mcpBase.dependencies.get().forEach {dep -> force(dep) } // Force all vanilla dependencies to their correct versions
|
||||
force(earlyDisplayLibs.slf4j.jdk14) // Force slf4j implementation, its tied to the api from the manifest
|
||||
}
|
||||
}
|
||||
3
buildSrc/.gitignore
vendored
3
buildSrc/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
/.gradle/
|
||||
/build/
|
||||
/out/
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
repositories {
|
||||
maven { url = 'https://maven.minecraftforge.net/' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.ow2.asm:asm:9.9.1'
|
||||
implementation 'org.ow2.asm:asm-tree:9.9.1'
|
||||
implementation 'net.minecraftforge:srgutils:0.6.2'
|
||||
implementation 'net.minecraftforge:JarJarMetadata:0.3.27'
|
||||
implementation 'commons-io:commons-io:2.13.0'
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r'
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
abstract class BundleList extends DefaultTask {
|
||||
@InputFiles abstract ConfigurableFileCollection getConfig()
|
||||
@InputFile abstract RegularFileProperty getServerBundle()
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
|
||||
BundleList() {
|
||||
config.setFrom(project.configurations.installer)
|
||||
output.convention(project.layout.buildDirectory.file("$name/output.list"))
|
||||
configure {
|
||||
dependsOn(project.tasks.universalJar)
|
||||
inputs.file(project.tasks.universalJar.archiveFile)
|
||||
dependsOn(project.tasks.applyServerBinPatches)
|
||||
inputs.file(project.tasks.applyServerBinPatches.output)
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def entries = [:] as TreeMap
|
||||
def resolved = project.configurations.installer.resolvedConfiguration.resolvedArtifacts
|
||||
for (def dep : resolved) {
|
||||
def info = Util.getMavenInfoFromDep(dep)
|
||||
//println("$dep.file.sha1\t$info.name\t$info.path")
|
||||
entries.put("$info.art.group:$info.art.name", "$dep.file.sha256\t$info.name\t$info.path")
|
||||
}
|
||||
|
||||
var packed = (AbstractArchiveTask) project.tasks.universalJar
|
||||
var info = Util.getMavenInfoFromTask(packed)
|
||||
def file = packed.archiveFile.get().asFile
|
||||
entries.put("$info.art.group:$info.art.name:$info.art.classifier", "$file.sha256\t$info.name\t$info.path")
|
||||
|
||||
var classifier = 'server'
|
||||
var genned = project.tasks.applyServerBinPatches
|
||||
info = Util.getMavenInfoFromTask(genned, classifier)
|
||||
file = genned.output.get().asFile
|
||||
entries.put("$info.art.group:$info.art.name:$info.art.classifier", "$file.sha256\t$info.name\t$info.path")
|
||||
|
||||
try (def zip = new ZipFile(serverBundle.get().asFile)) {
|
||||
def entry = zip.getEntry('META-INF/libraries.list')
|
||||
def data = zip.getInputStream(entry).text.split('\n')
|
||||
for (def line : data) {
|
||||
def (sha, artifact, path) = line.split('\t')
|
||||
def (group, name, other) = artifact.split(':', 3)
|
||||
//println("Group: $group Name: $name")
|
||||
def key = "$group:$name"
|
||||
if (other.indexOf(':') != -1){
|
||||
key += ':' + other.split(':', 2)[1]
|
||||
//println("\tKey: $key")
|
||||
}
|
||||
if (!entries.containsKey(key))
|
||||
entries.put(key, line)
|
||||
}
|
||||
}
|
||||
|
||||
output.get().asFile.text = entries.values().join('\n')
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.FieldNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
@CompileStatic
|
||||
abstract class BytecodeFinder extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getJar()
|
||||
// It should be fine to mark the output as internal as we want to control when we run it anyways.
|
||||
// This also shuts Gradle 8 up about implicit task dependencies.
|
||||
@Internal abstract RegularFileProperty getOutput()
|
||||
|
||||
BytecodeFinder() {
|
||||
output.convention(project.layout.buildDirectory.dir(name).map { it.file("output.json") })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
Util.init()
|
||||
|
||||
var outputFile = output.get().asFile
|
||||
if (outputFile.exists())
|
||||
outputFile.delete()
|
||||
|
||||
pre()
|
||||
|
||||
Util.processClassNodes(jar.get().asFile, this.&process)
|
||||
|
||||
post()
|
||||
outputFile.text = new JsonBuilder(getData()).toPrettyString()
|
||||
}
|
||||
|
||||
|
||||
protected process(ClassNode node) {
|
||||
if (node.fields !== null) node.fields.each { process(node, it) }
|
||||
if (node.methods !== null) node.methods.each { process(node, it) }
|
||||
}
|
||||
|
||||
protected pre() {}
|
||||
protected process(ClassNode parent, FieldNode node) {}
|
||||
protected process(ClassNode parent, MethodNode node) {}
|
||||
protected post() {}
|
||||
protected abstract Object getData()
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
@CompileStatic
|
||||
abstract class BytecodePredicateFinder extends BytecodeFinder {
|
||||
|
||||
@Internal
|
||||
abstract Property<Closure<Boolean>> getPredicate()
|
||||
|
||||
private final Map<String, List<String>> matches = new TreeMap<>(Comparator.naturalOrder())
|
||||
|
||||
@Override
|
||||
protected process(ClassNode parent, MethodNode node) {
|
||||
for (final current : node.instructions) {
|
||||
if (predicate.get().call(parent, node, current)) {
|
||||
var methods = matches.compute(parent.name, { k, v -> v ?: new ArrayList<>() })
|
||||
|
||||
// only add non-synthetic methods
|
||||
if ((node.access & Opcodes.ACC_SYNTHETIC) == 0) {
|
||||
methods.add(node.name + node.desc)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
protected Object getData() {
|
||||
var array = new ArrayList<Object>()
|
||||
matches.forEach { c, m ->
|
||||
{
|
||||
array.add(
|
||||
'class': c,
|
||||
'methods': m
|
||||
)
|
||||
}
|
||||
}
|
||||
return array ?: { throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.') }()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks;
|
||||
|
||||
import groovy.transform.CompileDynamic;
|
||||
import groovy.transform.CompileStatic;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Eclipse config files are literally just java properties, with the header cleaned up.
|
||||
* https://github.com/eclipse/buildship/blob/5b2c7fca7fa86cd74d71b3c099c7b1559eba038e/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/PreferenceStore.java#L238
|
||||
*
|
||||
* This does the same thing, as well as sorting alphabetically.
|
||||
* It also ignores all comments. We can add them latter if someone cares.
|
||||
*/
|
||||
@CompileStatic
|
||||
public class CleanProperties extends Properties {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String LINE_SEP = System.getProperty("line.separator");
|
||||
private static final String UNIX_LINE_SEP = "\n";
|
||||
private static final Charset ENCODING = StandardCharsets.UTF_8;
|
||||
|
||||
public CleanProperties load(File input) throws IOException {
|
||||
if (input.exists()) {
|
||||
try (Reader is = new InputStreamReader(new FileInputStream(input), ENCODING)) {
|
||||
super.load(is);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void store(File out) throws IOException {
|
||||
if (!out.getParentFile().exists())
|
||||
out.getParentFile().mkdirs();
|
||||
|
||||
try (OutputStream os = new FileOutputStream(out)) {
|
||||
store(os, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Enumeration<Object> keys() {
|
||||
Set<Object> ret = new TreeSet<>();
|
||||
for (Enumeration<?> e = super.keys(); e.hasMoreElements();)
|
||||
ret.add(e.nextElement());
|
||||
return Collections.enumeration(ret);
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
@Override
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
||||
Set<Map.Entry<Object, Object>> ret = new TreeSet<>((l, r) -> ((String)l.getKey()).compareTo((String)r.getKey()));
|
||||
ret.addAll(super.entrySet());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(OutputStream out, String comments) throws IOException {
|
||||
out.write(clean().getBytes(ENCODING));
|
||||
out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(Writer out, String comments) throws IOException {
|
||||
out.write(clean());
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private String clean() throws IOException {
|
||||
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
|
||||
try {
|
||||
super.store(tmp, null);
|
||||
} finally {
|
||||
tmp.close();
|
||||
}
|
||||
|
||||
String ret = tmp.toString(ENCODING).replace(LINE_SEP, UNIX_LINE_SEP);
|
||||
ret = ret.substring(ret.indexOf(UNIX_LINE_SEP) + 1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.stc.FirstParam
|
||||
|
||||
import java.util.function.BiConsumer
|
||||
|
||||
public class ClosureHelper {
|
||||
BiConsumer<String, Closure> callback
|
||||
|
||||
public ClosureHelper(Closure cl, BiConsumer<String, Closure> callback) {
|
||||
this.callback = callback
|
||||
apply(this, cl)
|
||||
}
|
||||
|
||||
|
||||
def methodMissing(String name, Object args) {
|
||||
if (!args.class.isArray()) return
|
||||
Object[] aargs = (Object[])args
|
||||
|
||||
if (aargs.length == 1 && aargs[0] instanceof Closure) {
|
||||
this.callback.accept(name, (Closure)aargs[0])
|
||||
} else {
|
||||
throw new IllegalArgumentException('Unknown method: "' + name + '" with arguments ' + args + ' for ' + this)
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T apply(T obj, @DelegatesTo(value = FirstParam, strategy = Closure.DELEGATE_FIRST) Closure cl) {
|
||||
cl.delegate = obj
|
||||
cl.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
cl()
|
||||
return obj
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.OutputFiles
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
abstract class DownloadLibraries extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getInput()
|
||||
@OutputDirectory abstract DirectoryProperty getOutput()
|
||||
@OutputFile abstract RegularFileProperty getLibrariesOutput()
|
||||
|
||||
DownloadLibraries() {
|
||||
output.convention(project.layout.buildDirectory.dir(name))
|
||||
librariesOutput.convention(project.layout.buildDirectory.dir(name).map(d -> d.file('libraries.txt')))
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
def run() {
|
||||
Util.init()
|
||||
File outputDir = output.get().asFile
|
||||
var libraries = new ArrayList<String>()
|
||||
|
||||
def json = input.get().asFile.json().libraries.each { lib ->
|
||||
//TODO: Thread?
|
||||
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
|
||||
artifacts.each{ art ->
|
||||
def target = new File(outputDir, art.path)
|
||||
libraries.add(target.absolutePath)
|
||||
if (!target.exists() || art.sha1 != target.sha1()) {
|
||||
project.logger.lifecycle("Downloading ${art.url}")
|
||||
if (!target.parentFile.exists()) {
|
||||
target.parentFile.mkdirs()
|
||||
}
|
||||
new URL(art.url).withInputStream { i ->
|
||||
target.withOutputStream { it << i }
|
||||
}
|
||||
if (art.sha1 != target.sha1()) {
|
||||
throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Files.write(librariesOutput.get().asFile.toPath(), libraries)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
@CompileStatic
|
||||
abstract class ExtractFile extends DefaultTask {
|
||||
@InputFile abstract RegularFileProperty getInput()
|
||||
@Input abstract Property<String> getTarget()
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
var zip = new ZipFile(input.get().asFile);
|
||||
var entry = zip.getEntry(target.get())
|
||||
if (entry == null)
|
||||
throw new IllegalStateException(input.get().asFile.absolutePath + " does not contain " + target.get())
|
||||
var stream = zip.getInputStream(entry)
|
||||
output.get().asFile.withOutputStream { out ->
|
||||
stream.transferTo(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
import org.gradle.api.tasks.*
|
||||
import org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*
|
||||
|
||||
abstract class FieldCompareFinder extends BytecodeFinder {
|
||||
@Nested
|
||||
Map<String, Search> fields = [:] as HashMap
|
||||
@Internal
|
||||
Map<Search, String> fieldsReverse = [:] as HashMap
|
||||
@Internal
|
||||
Map<String, Set<ObjectTarget>> targets = [:] as TreeMap
|
||||
|
||||
@Override
|
||||
protected pre() {
|
||||
//fields.each{ k,v -> logger.lifecycle("Fields: " + k + ' ' + v) }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected process(ClassNode parent, MethodNode node) {
|
||||
AbstractInsnNode last = null
|
||||
def parentInstance = new ObjectTarget(owner: parent.name, name: '', desc: '')
|
||||
for (int x = 0; x < node.instructions.size(); x++) {
|
||||
def current = node.instructions.get(x)
|
||||
if (current.opcode === IF_ACMPEQ || current.opcode === IF_ACMPNE) {
|
||||
if (last !== null && (last.opcode === GETSTATIC || last.opcode === GETFIELD)) {
|
||||
def target = new Search(cls: last.owner, name: last.name)
|
||||
def wanted = fieldsReverse.get(target)
|
||||
def original = fields.get(wanted)
|
||||
def instance = new ObjectTarget(owner: parent.name, name: node.name, desc: node.desc)
|
||||
if (wanted !== null && (original.blacklist === null || (!original.blacklist.contains(instance) && !original.blacklist.contains(parentInstance)))) {
|
||||
targets.computeIfAbsent(wanted, { k -> new TreeSet() }).add(instance)
|
||||
}
|
||||
}
|
||||
}
|
||||
last = current
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
protected Object getData() {
|
||||
def ret = [:] as HashMap
|
||||
targets.forEach{ k, v ->
|
||||
def e = fields.get(k)
|
||||
ret[k] = [
|
||||
cls: e.cls,
|
||||
name: e.name,
|
||||
replacement: e.replacement,
|
||||
targets: v
|
||||
]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
@EqualsAndHashCode(excludes = ['replacement', 'blacklist'])
|
||||
static class Search {
|
||||
@Input
|
||||
String cls
|
||||
|
||||
@Input
|
||||
String name
|
||||
|
||||
@Input
|
||||
String replacement
|
||||
|
||||
@Nested
|
||||
@Optional
|
||||
Set<ObjectTarget> blacklist
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
return cls + '.' + name
|
||||
}
|
||||
|
||||
def blacklist(String owner, String name, String desc) {
|
||||
if (blacklist === null)
|
||||
blacklist = new HashSet<>()
|
||||
blacklist.add(new ObjectTarget(owner: owner, name: name, desc: desc))
|
||||
}
|
||||
def blacklist(String owner) {
|
||||
blacklist(owner, '', '')
|
||||
}
|
||||
}
|
||||
|
||||
void fields(Closure cl) {
|
||||
new ClosureHelper(cl, {name, ccl ->
|
||||
def search = ClosureHelper.apply(new Search(), ccl)
|
||||
this.fields.put(name, search)
|
||||
this.fieldsReverse.put(search, name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TupleConstructor
|
||||
|
||||
@CompileStatic
|
||||
@TupleConstructor
|
||||
final class InheritanceData implements Annotatable {
|
||||
String name
|
||||
int access
|
||||
String superName
|
||||
List<String> interfaces = []
|
||||
Map<String, Method> methods = [:]
|
||||
Map<String, Field> fields = [:]
|
||||
List<Annotation> annotations = []
|
||||
|
||||
@TupleConstructor
|
||||
static final class Method implements Annotatable {
|
||||
int access
|
||||
String override
|
||||
List<Annotation> annotations = []
|
||||
}
|
||||
|
||||
@TupleConstructor
|
||||
static final class Field implements Annotatable {
|
||||
int access
|
||||
String desc
|
||||
List<Annotation> annotations = []
|
||||
}
|
||||
|
||||
@TupleConstructor
|
||||
static final class Annotation {
|
||||
String desc
|
||||
}
|
||||
|
||||
private static final Gson GSON = new Gson()
|
||||
static Map<String, InheritanceData> parse(File file) {
|
||||
try (final reader = file.newReader()) {
|
||||
return GSON.fromJson(reader, new TypeToken<Map<String, InheritanceData>>() {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
interface Annotatable {
|
||||
List<InheritanceData.Annotation> getAnnotations()
|
||||
}
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.file.DuplicatesStrategy
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
import org.gradle.api.tasks.bundling.Zip
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.Property
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
abstract class InstallerJar extends Zip {
|
||||
@Input @Optional abstract Property<Boolean> getFat()
|
||||
@Input @Optional abstract Property<Boolean> getOffline()
|
||||
|
||||
InstallerJar() {
|
||||
archiveClassifier.set('installer')
|
||||
archiveExtension.set('jar') // Needs to be Zip task to not override Manifest, so set extension
|
||||
destinationDirectory.set(project.layout.buildDirectory.dir('libs'))
|
||||
fat.convention(false)
|
||||
offline.convention(false)
|
||||
|
||||
def installerJson = project.tasks.installerJson
|
||||
def launcherJson = project.tasks.launcherJson
|
||||
def downloadInstaller = project.tasks.downloadInstaller
|
||||
|
||||
dependsOn(installerJson, launcherJson, downloadInstaller, project.configurations.installer)
|
||||
from(installerJson, launcherJson)
|
||||
|
||||
from(project.rootProject.file('/src/main/resources/url.png'))
|
||||
project.afterEvaluate {
|
||||
from(project.zipTree(downloadInstaller.output)) {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
if (fat.get() || offline.get()) {
|
||||
def cfg = project.tasks.register(name + "Config", Configure)
|
||||
cfg.get().configure {
|
||||
parent = this
|
||||
dependsOn(project.tasks.installerJson, project.tasks.launcherJson)
|
||||
}
|
||||
dependsOn(cfg)
|
||||
} else {
|
||||
// Things we ALWAYS bundle, this just the server shim jar, because the installer spec only says to extract the file.
|
||||
// I should make it allow downloads but thats a spec break, and this is just a ~14KB jar
|
||||
[
|
||||
project.tasks.serverShimJar // Server bootstrap executable jar
|
||||
].forEach { AbstractArchiveTask packed ->
|
||||
def path = Util.getMavenInfoFromTask(packed).path
|
||||
from(packed) {
|
||||
rename { "maven/$path" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class Configure extends DefaultTask {
|
||||
public Zip parent
|
||||
private int count = 0;
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
def deps = [:] as java.util.TreeMap
|
||||
|
||||
// Gather all things that need downloading
|
||||
[
|
||||
project.tasks.installerJson,
|
||||
project.tasks.launcherJson
|
||||
].each { task ->
|
||||
def json = task.output.get().asFile.json
|
||||
json.libraries.each { lib ->
|
||||
if (lib.downloads?.artifact?.url !== null && !lib.downloads.artifact.url.isEmpty())
|
||||
deps.put(lib.name, lib.downloads.artifact)
|
||||
}
|
||||
}
|
||||
|
||||
// First find things we build in this project.
|
||||
[
|
||||
project.tasks.universalJar, // Forge runtime code
|
||||
project.tasks.serverShimJar // Shim jar for dedicated server
|
||||
].forEach { AbstractArchiveTask packed ->
|
||||
def name = Util.getMavenInfoFromTask(packed).name
|
||||
def info = deps.remove(name)
|
||||
if (info !== null) {
|
||||
println("Adding: $packed.path $name")
|
||||
parent.from(packed) {
|
||||
rename { "maven/$info.path" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find any artifacts from the 'installer' config
|
||||
// This config specifies the runtime files we intend for the interaller to have.
|
||||
// And are typically what we would be developing and testing alongside Forge.
|
||||
// So we may have local modified versions
|
||||
def cfg = project.configurations.installer
|
||||
while (cfg != null) {
|
||||
//println('')
|
||||
def resolved = cfg.resolvedConfiguration.resolvedArtifacts
|
||||
int found = 0
|
||||
for (def dep : resolved) {
|
||||
def name = Util.getMavenInfoFromDep(dep).name
|
||||
def info = deps.remove(name)
|
||||
if (info == null) {
|
||||
//println("Skipping: $name")
|
||||
continue
|
||||
}
|
||||
//println("-$name")
|
||||
found++
|
||||
addFile(dep.file, info)
|
||||
}
|
||||
|
||||
if (deps.isEmpty()) {
|
||||
cfg = null
|
||||
continue
|
||||
}
|
||||
|
||||
// Prevent infinite loops if something fucky happens
|
||||
if (found == 0)
|
||||
throw new IllegalStateException("Failed to find any installer dependencies")
|
||||
|
||||
def seen = [] as Set
|
||||
cfg = project.configurations.detachedConfiguration()
|
||||
cfg.transitive = false
|
||||
for (def key : deps.keySet()) {
|
||||
def (group, artifact, other) = key.split(':', 3)
|
||||
// Only resolve unique group:artifact so we don't get version overrides
|
||||
if (seen.add(group + ':' + artifact)) {
|
||||
//println("+$key")
|
||||
cfg.dependencies.add(project.dependencies.create(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addFile(file, info) {
|
||||
boolean pack = parent.offline.get() || info.url.isEmpty()
|
||||
|
||||
// If it's a offline jar just always pack
|
||||
if (!pack) {
|
||||
try {
|
||||
var remote = new URL("${info.url}.sha1").getText('UTF-8')
|
||||
pack = info.sha1 != remote
|
||||
} catch (FileNotFoundException e) {
|
||||
pack = !info.url.startsWith('https://libraries.minecraft.net/')
|
||||
// Oh noes its not there!
|
||||
}
|
||||
}
|
||||
|
||||
if (pack) {
|
||||
println("Adding: $file.absolutePath")
|
||||
parent.from(file) {
|
||||
rename { "maven/$info.path" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
abstract class InstallerJson extends DefaultTask {
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
@InputFiles abstract ConfigurableFileCollection getInput()
|
||||
@Input @Optional final Map<String, Object> libraries = new LinkedHashMap<>()
|
||||
@Input Map<String, Object> json = new LinkedHashMap<>()
|
||||
@InputFile abstract RegularFileProperty getIcon()
|
||||
@Input abstract Property<String> getLauncherJsonName()
|
||||
@Input abstract Property<String> getLogo()
|
||||
@Input abstract Property<String> getMirrors()
|
||||
@Input abstract Property<String> getWelcome()
|
||||
|
||||
InstallerJson() {
|
||||
launcherJsonName.convention('/version.json')
|
||||
logo.convention('/big_logo.png')
|
||||
mirrors.convention('https://files.minecraftforge.net/mirrors-2.0.json')
|
||||
welcome.convention("Welcome to the ${project.name.capitalize()} installer.")
|
||||
output.convention(project.layout.buildDirectory.file('libs/install_profile.json'))
|
||||
|
||||
project.afterEvaluate {
|
||||
[
|
||||
project.tasks.universalJar,
|
||||
project.tasks.serverShimJar
|
||||
].forEach { packed ->
|
||||
dependsOn(packed)
|
||||
input.from packed.archiveFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
def libs = libraries
|
||||
[
|
||||
project.tasks.universalJar,
|
||||
project.tasks.serverShimJar
|
||||
].forEach { AbstractArchiveTask packed ->
|
||||
def info = Util.getMavenInfoFromTask(packed)
|
||||
libs.put(info.name, [
|
||||
name: info.name,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: info.path,
|
||||
url: "https://maven.minecraftforge.net/$info.path",
|
||||
sha1: packed.archiveFile.get().asFile.sha1(),
|
||||
size: packed.archiveFile.get().asFile.length()
|
||||
]
|
||||
]
|
||||
])
|
||||
}
|
||||
json.libraries = libs.values().sort{a,b -> a.name.compareTo(b.name)}
|
||||
json.icon = "data:image/png;base64," + new String(Base64.getEncoder().encode(Files.readAllBytes(icon.get().asFile.toPath())))
|
||||
json.json = launcherJsonName.get()
|
||||
json.logo = logo.get()
|
||||
if (!mirrors.get().isEmpty())
|
||||
json.mirrorList = mirrors.get()
|
||||
json.welcome = welcome.get()
|
||||
|
||||
Files.writeString(output.get().getAsFile().toPath(), new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,415 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.forge.tasks;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import net.minecraftforge.jarjar.metadata.ContainedJarIdentifier;
|
||||
import net.minecraftforge.jarjar.metadata.ContainedJarMetadata;
|
||||
import net.minecraftforge.jarjar.metadata.ContainedVersion;
|
||||
import net.minecraftforge.jarjar.metadata.Metadata;
|
||||
import net.minecraftforge.jarjar.metadata.MetadataIOHandler;
|
||||
import net.minecraftforge.jarjar.metadata.json.ArtifactVersionSerializer;
|
||||
import net.minecraftforge.jarjar.metadata.json.ContainedJarIdentifierSerializer;
|
||||
import net.minecraftforge.jarjar.metadata.json.ContainedJarMetadataSerializer;
|
||||
import net.minecraftforge.jarjar.metadata.json.ContainedVersionSerializer;
|
||||
import net.minecraftforge.jarjar.metadata.json.MetadataSerializer;
|
||||
import net.minecraftforge.jarjar.metadata.json.VersionRangeSerializer;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
import org.codehaus.groovy.runtime.InvokerHelper;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.artifacts.ConfigurationContainer;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||
import org.gradle.api.artifacts.FileCollectionDependency;
|
||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency;
|
||||
import org.gradle.api.artifacts.ModuleDependency;
|
||||
import org.gradle.api.artifacts.ModuleIdentifier;
|
||||
import org.gradle.api.artifacts.ModuleVersionIdentifier;
|
||||
import org.gradle.api.artifacts.ResolvedArtifact;
|
||||
import org.gradle.api.file.ProjectLayout;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.provider.SetProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
// TODO SUPER SUPER SUPER UGLY, CLEAN UP IN FORGEDEV 7
|
||||
@Deprecated(forRemoval = true) // Will be moved to JarJar plugin in ForgeDev 7
|
||||
public abstract class JarJarMetadataOptions extends DefaultTask {
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(VersionRange.class, new VersionRangeSerializer())
|
||||
.registerTypeAdapter(ArtifactVersion.class, new ArtifactVersionSerializer())
|
||||
.registerTypeAdapter(DefaultArtifactVersion.class, new ArtifactVersionSerializer())
|
||||
.registerTypeAdapter(ContainedJarIdentifier.class, new ContainedJarIdentifierSerializer())
|
||||
.registerTypeAdapter(ContainedJarMetadata.class, new ContainedJarMetadataSerializer())
|
||||
.registerTypeAdapter(ContainedVersion.class, new ContainedVersionSerializer())
|
||||
.registerTypeAdapter(Metadata.class, new MetadataSerializer())
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
protected abstract @Input SetProperty<ResolvedDependencyInfoImpl> getResolvedDependencies();
|
||||
|
||||
protected abstract @OutputFile RegularFileProperty getMetadataFile();
|
||||
|
||||
protected abstract @Inject ProjectLayout getLayout();
|
||||
|
||||
// NOTE: I'm not adding a non-provider version. please just use the version catalog entries for now.
|
||||
public void add(Provider<MinimalExternalModuleDependency> dependency, Action<? super ResolvedDependencyInfo> action) {
|
||||
this.getResolvedDependencies().add(dependency.map(d -> {
|
||||
var ret = ResolvedDependencyInfoImpl.from(this.getProject().getConfigurations(), d);
|
||||
action.execute(ret);
|
||||
return ret;
|
||||
}));
|
||||
}
|
||||
|
||||
@Inject
|
||||
public JarJarMetadataOptions() {
|
||||
this.getMetadataFile().convention(this.getLayout().getBuildDirectory().file(this.getName() + "/options.json"));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
record ForgeLocaterOptions(String resource, String layer, String id, List<ContainedJarMetadata> deps, ContainedJarMetadata meta, boolean nested) { }
|
||||
|
||||
var resolved = this.getResolvedDependencies().get();
|
||||
var jars = new ArrayList<ForgeLocaterOptions>(resolved.size());
|
||||
for (var dependency : resolved) {
|
||||
var deps = new ArrayList<ContainedJarMetadata>();
|
||||
try (var zip = new ZipFile(dependency.artifact)) {
|
||||
var entry = zip.getEntry("META-INF/jarjar/metadata.json");
|
||||
if (entry != null) {
|
||||
try (var stream = zip.getInputStream(entry)) {
|
||||
var meta = MetadataIOHandler.fromStream(stream).orElse(null);
|
||||
if (meta == null)
|
||||
throw new IllegalStateException("Corrupt metadata.json in " + dependency.artifact.getAbsolutePath());
|
||||
for (var dep : meta.jars())
|
||||
deps.add(new ContainedJarMetadata(dep.identifier(), dep.version(), "", dep.isObfuscated()));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
jars.add(new ForgeLocaterOptions(
|
||||
dependency.resource,
|
||||
dependency.layer,
|
||||
dependency.identifier,
|
||||
deps,
|
||||
new ContainedJarMetadata(
|
||||
new ContainedJarIdentifier(validateGroup(dependency), dependency.module.getName()),
|
||||
new ContainedVersion(null, parseVersion(dependency)),
|
||||
Objects.requireNonNull(dependency.path, "Dependency path is unspecified: " + dependency.asString),
|
||||
false
|
||||
),
|
||||
dependency.nested
|
||||
));
|
||||
}
|
||||
|
||||
try {
|
||||
record Meta(List<ForgeLocaterOptions> options){}
|
||||
|
||||
Files.writeString(
|
||||
this.getMetadataFile().getAsFile().get().toPath(),
|
||||
GSON.toJson(new Meta(jars), Meta.class)
|
||||
);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String validateGroup(ResolvedDependencyInfoImpl dependency) {
|
||||
try {
|
||||
return Objects.requireNonNull(dependency.module.getGroup());
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException("Module dependency has no group: " + dependency.asString, e);
|
||||
}
|
||||
}
|
||||
|
||||
private ArtifactVersion parseVersion(ResolvedDependencyInfoImpl resolved) {
|
||||
try {
|
||||
return VersionRange.createFromVersionSpec(Objects.requireNonNull(resolved.version)).getRecommendedVersion();
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
throw new IllegalArgumentException("Version is invalid for: " + resolved.asString, e);
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException("Version is unspecified for: " + resolved.asString, e);
|
||||
}
|
||||
}
|
||||
|
||||
private VersionRange parseVersionRange(ResolvedDependencyInfoImpl dependency) {
|
||||
if (dependency.hasManuallySpecifiedRange) {
|
||||
try {
|
||||
return VersionRange.createFromVersionSpec(dependency.versionRange);
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
throw new IllegalArgumentException("Version is invalid for: " + dependency.asString, e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return VersionRange.createFromVersionSpec("[%s,)".formatted(Objects.requireNonNull(dependency.versionRange)));
|
||||
} catch (InvalidVersionSpecificationException e) {
|
||||
throw new IllegalArgumentException("Version range is invalid for: " + dependency.asString, e);
|
||||
} catch (NullPointerException e) {
|
||||
throw new IllegalArgumentException("Version is unspecified for: " + dependency.asString, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ResolvedDependencyInfo {
|
||||
void containedJarMetadata(Action<? super ContainedJarMetadataInfo> action);
|
||||
|
||||
void setResource(String resource);
|
||||
|
||||
void setLayer(String layer);
|
||||
|
||||
void setId(String identifier);
|
||||
|
||||
void setNested(boolean nested);
|
||||
|
||||
interface ContainedJarMetadataInfo {
|
||||
void setGroup(String group);
|
||||
|
||||
void setName(String name);
|
||||
|
||||
void setPath(String version);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ResolvedDependencyInfoImpl implements ResolvedDependencyInfo, ResolvedDependencyInfo.ContainedJarMetadataInfo, Serializable {
|
||||
private static final @Serial long serialVersionUID = -7577318115877822993L;
|
||||
|
||||
final MinimalModuleVersionIdentifier module;
|
||||
final String version;
|
||||
String versionRange;
|
||||
boolean hasManuallySpecifiedRange;
|
||||
boolean nested;
|
||||
final File artifact;
|
||||
String path;
|
||||
String resource;
|
||||
String layer;
|
||||
String identifier;
|
||||
final String asString;
|
||||
|
||||
public ResolvedDependencyInfoImpl(MinimalModuleVersionIdentifier module, String version, File artifact, String asString) {
|
||||
this.module = module;
|
||||
this.version = version;
|
||||
this.artifact = artifact;
|
||||
this.asString = asString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void containedJarMetadata(Action<? super ContainedJarMetadataInfo> action) {
|
||||
action.execute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(String group) {
|
||||
this.module.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.module.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayer(String layer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNested(boolean nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
static Set<File> getFiles(Set<ResolvedDependencyInfoImpl> resolvedDependencies) {
|
||||
var ret = new HashSet<File>(resolvedDependencies.size());
|
||||
for (var dependency : resolvedDependencies) {
|
||||
ret.add(dependency.artifact);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ResolvedDependencyInfoImpl from(ConfigurationContainer configurations, Dependency dependency) {
|
||||
var group = dependency.getGroup();
|
||||
var name = dependency.getName();
|
||||
var version = dependency.getVersion();
|
||||
|
||||
if (dependency instanceof FileCollectionDependency filesDependency) {
|
||||
File artifact;
|
||||
try {
|
||||
artifact = filesDependency.getFiles().getSingleFile();
|
||||
} catch (IllegalStateException e) {
|
||||
// TODO fileCollectionDependencyIsNotSingleFile
|
||||
throw e;
|
||||
}
|
||||
|
||||
return new ResolvedDependencyInfoImpl(
|
||||
new MinimalModuleVersionIdentifier(group, name, version),
|
||||
version,
|
||||
artifact,
|
||||
filesDependency.toString()
|
||||
);
|
||||
} else if (dependency instanceof ModuleDependency moduleDependency) {
|
||||
moduleDependency = moduleDependency.copy();
|
||||
if (moduleDependency instanceof ExternalModuleDependency externalModuleDependency) {
|
||||
externalModuleDependency.version(v -> v.strictly(version.toString()));
|
||||
}
|
||||
|
||||
var detachedConfiguration = configurations.detachedConfiguration(moduleDependency);
|
||||
detachedConfiguration.setTransitive(false);
|
||||
|
||||
ResolvedDependencyInfoImpl ret = null;
|
||||
for (var artifact : detachedConfiguration.getResolvedConfiguration().getFirstLevelModuleDependencies().iterator().next().getModuleArtifacts()) {
|
||||
var fileName = getFileName(artifact);
|
||||
if (!fileName.endsWith(".jar"))
|
||||
continue;
|
||||
|
||||
if (ret != null)
|
||||
throw new IllegalArgumentException("Module dependency has too many Jar artifacts: " + moduleDependency);
|
||||
|
||||
ret = new ResolvedDependencyInfoImpl(
|
||||
new MinimalModuleVersionIdentifier(group, name, artifact.getModuleVersion().getId().getVersion()),
|
||||
version,
|
||||
artifact.getFile(),
|
||||
moduleDependency.toString()
|
||||
);
|
||||
}
|
||||
if (ret == null)
|
||||
throw new IllegalArgumentException("Module dependency has no Jar artifacts: " + moduleDependency);
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported dependency type: " + dependency.getClass().getName() + " -- " + dependency);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFileName(ResolvedArtifact artifact) {
|
||||
try {
|
||||
return InvokerHelper.getProperty(artifact.getId(), "fileName").toString();
|
||||
} catch (Throwable e) {
|
||||
// NOTE: Why not just use this to begin with?
|
||||
// ComponentArtifactIdentifier can have a getFileName() method, which doesn't necessarily resolve the file itself.
|
||||
// This allows us to get the name of the file to be used without asking Gradle to download the file.
|
||||
// So, if a file is not a JAR file, we can check the name without actually downloading it.
|
||||
return artifact.getFile().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (ResolvedDependencyInfoImpl) obj;
|
||||
return Objects.equals(this.module, that.module) &&
|
||||
Objects.equals(this.version, that.version) &&
|
||||
Objects.equals(this.versionRange, that.versionRange) &&
|
||||
Objects.equals(this.artifact, that.artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(module, version, versionRange, artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResolvedDependencyInfo[" +
|
||||
"module=" + module + ", " +
|
||||
"fixedVersion=" + version + ", " +
|
||||
"versionRange=" + versionRange + ", " +
|
||||
"artifact=" + artifact + ']';
|
||||
}
|
||||
|
||||
static final class MinimalModuleVersionIdentifier implements ModuleIdentifier, ModuleVersionIdentifier {
|
||||
private static final @Serial long serialVersionUID = -955346236759069739L;
|
||||
|
||||
private String group;
|
||||
private String name;
|
||||
private final String version;
|
||||
|
||||
@Inject
|
||||
public MinimalModuleVersionIdentifier(String group, String name, String version) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleIdentifier getModule() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj || obj instanceof MinimalModuleVersionIdentifier o
|
||||
&& Objects.equals(this.group, o.group)
|
||||
&& Objects.equals(this.name, o.name)
|
||||
&& Objects.equals(this.version, o.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(group, name, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MinimalModuleVersionIdentifier[" +
|
||||
"group=" + group + ", " +
|
||||
"name=" + name + ", " +
|
||||
"version=" + version + ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
import static net.minecraftforge.forge.tasks.Util.getArtifacts
|
||||
import static net.minecraftforge.forge.tasks.Util.iso8601Now
|
||||
|
||||
abstract class LauncherJson extends DefaultTask {
|
||||
@OutputFile abstract RegularFileProperty getOutput()
|
||||
@InputFiles abstract ConfigurableFileCollection getInput()
|
||||
@Input Map<String, Object> json = new LinkedHashMap<>()
|
||||
|
||||
LauncherJson() {
|
||||
output.convention(project.layout.buildDirectory.file('libs/version.json'))
|
||||
|
||||
dependsOn(project.tasks.universalJar)
|
||||
input.from(project.tasks.universalJar.archiveFile)
|
||||
input.from(project.configurations.installer)
|
||||
configure {
|
||||
def mc = project.rootProject.ext.MC_VERSION
|
||||
def forge = project.rootProject.ext.FORGE_VERSION
|
||||
def timestamp = iso8601Now()
|
||||
json.putAll([
|
||||
_comment: [
|
||||
"Please do not automate the download and installation of Forge.",
|
||||
"Our efforts are supported by ads from the download page.",
|
||||
"If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/"
|
||||
],
|
||||
id: "$mc-$project.name-$forge",
|
||||
time: timestamp,
|
||||
releaseTime: timestamp,
|
||||
inheritsFrom: mc,
|
||||
type: 'release',
|
||||
logging: [:],
|
||||
mainClass: '',
|
||||
libraries: []
|
||||
] as LinkedHashMap)
|
||||
|
||||
[
|
||||
project.tasks.universalJar
|
||||
].forEach { packed ->
|
||||
dependsOn(packed)
|
||||
input.from packed.archiveFile
|
||||
}
|
||||
|
||||
def patched = project.tasks.applyClientBinPatches
|
||||
dependsOn(patched)
|
||||
input.from patched.output
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
var packed = (AbstractArchiveTask) project.tasks.universalJar
|
||||
def info = Util.getMavenInfoFromTask(packed)
|
||||
json.libraries.add([
|
||||
name: info.name,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: info.path,
|
||||
url: "https://maven.minecraftforge.net/$info.path",
|
||||
sha1: packed.archiveFile.get().asFile.sha1(),
|
||||
size: packed.archiveFile.get().asFile.length()
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
var classifier = 'client'
|
||||
var genned = project.tasks.applyClientBinPatches
|
||||
info = Util.getMavenInfoFromTask(genned, classifier)
|
||||
json.libraries.add([
|
||||
name: info.name,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: info.path,
|
||||
url: "",
|
||||
sha1: genned.output.get().asFile.sha1(),
|
||||
size: genned.output.get().asFile.length()
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
json.libraries.addAll(getArtifacts(project.configurations.installer).values())
|
||||
Files.writeString(output.get().asFile.toPath(), new JsonBuilder(json).toPrettyString())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
@CompileStatic
|
||||
abstract class MergeJars extends DefaultTask {
|
||||
MergeJars() {
|
||||
output.convention(project.layout.buildDirectory.dir(name).map { it.file('output.jar') })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def jars = inputJars.files
|
||||
|
||||
try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.get().asFile))) {
|
||||
for (def jar : jars) {
|
||||
try (ZipInputStream zin = new ZipInputStream(new FileInputStream(jar))) {
|
||||
ZipEntry entry
|
||||
while ((entry = zin.getNextEntry()) !== null) {
|
||||
ZipEntry _new = new ZipEntry(entry.getName())
|
||||
_new.setTime(0) //SHOULD be the same time as the main entry, but NOOOO _new.setTime(entry.getTime()) throws DateTimeException, so you get 0, screw you!
|
||||
zout.putNextEntry(_new)
|
||||
IOUtils.copy(zin, zout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
abstract ConfigurableFileCollection getInputJars()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getOutput()
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.Optional
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class ObjectTarget implements Comparable<ObjectTarget> {
|
||||
@Input
|
||||
String owner
|
||||
|
||||
@Input
|
||||
String name
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
String desc
|
||||
|
||||
@Override
|
||||
String toString() {
|
||||
if (desc == null)
|
||||
return owner + '.' + name
|
||||
return owner + '.' + name + desc
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(ObjectTarget o) {
|
||||
return toString() <=> o.toString()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
abstract class SetupCheckJarCompatibility extends DefaultTask {
|
||||
SetupCheckJarCompatibility() {
|
||||
group = 'jar compatibility'
|
||||
onlyIf {
|
||||
inputVersion.getOrNull() !== null
|
||||
}
|
||||
outputs.upToDateWhen { false } // Never up to date, because this setup task should always run
|
||||
|
||||
baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def inputVersion = inputVersion.get()
|
||||
|
||||
def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile
|
||||
project.rootProject.extensions.download.run {
|
||||
src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-userdev.jar"
|
||||
dest baseForgeUserdev
|
||||
}
|
||||
|
||||
def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile
|
||||
|
||||
Files.copy(joinedLzma.toPath(), baseBinPatchesOutput.get().asFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
abstract Property<String> getInputVersion()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getBaseBinPatchesOutput()
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import groovy.transform.CompileStatic
|
||||
import org.eclipse.jgit.api.Git
|
||||
|
||||
import javax.annotation.Nullable
|
||||
import java.util.stream.Collectors
|
||||
|
||||
@CompileStatic
|
||||
class TeamcityRequests {
|
||||
public static final Gson GSON = new Gson()
|
||||
|
||||
@Nullable
|
||||
static <T> T jsonRequest(TypeToken<T> clazz, String url) throws Exception {
|
||||
final HttpURLConnection conn = (HttpURLConnection) URI.create(url).toURL().openConnection()
|
||||
conn.setRequestProperty('Accept', 'application/json')
|
||||
conn.setReadTimeout(5 * 1000)
|
||||
conn.setConnectTimeout(5 * 1000)
|
||||
conn.connect()
|
||||
|
||||
if (conn.responseCode !== 200) {
|
||||
return null
|
||||
}
|
||||
|
||||
try (final InputStream is = conn.getInputStream()) {
|
||||
GSON.fromJson(new InputStreamReader(is), clazz.getType())
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Map<String, Build> buildsByCommit() throws IOException {
|
||||
final Map<String, Build> builds = [:]
|
||||
jsonRequest(new TypeToken<Builds>() {}, 'https://teamcity.minecraftforge.net/guestAuth/app/rest/builds?fields=build:(revisions,number)&locator=buildType:(id:MinecraftForge_MinecraftForge_MinecraftForge_MinecraftForge__Build),defaultFilter:false,count:300,status:SUCCESS')
|
||||
?.build?.forEach {
|
||||
it.revisions.revision.each { rev -> builds[rev.version] = it }
|
||||
}
|
||||
return builds
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static String attemptFindBase(File gitPath) {
|
||||
try (final git = Git.open(gitPath)) {
|
||||
final Map<String, Build> buildByCommit = buildsByCommit()
|
||||
for (final commit in git.log().setMaxCount(100).call()) {
|
||||
// Find the first commit which was built on CI
|
||||
final build = buildByCommit[commit.id.name]
|
||||
if (build) {
|
||||
return build.number
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return null
|
||||
}
|
||||
|
||||
static final class Builds {
|
||||
public List<Build> build
|
||||
}
|
||||
|
||||
static final class Build {
|
||||
public String number
|
||||
public Revisions revisions
|
||||
}
|
||||
|
||||
static final class Revisions {
|
||||
public int count
|
||||
public List<Revision> revision
|
||||
}
|
||||
|
||||
static final class Revision {
|
||||
public String version
|
||||
}
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.json.JsonBuilder
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.SimpleType
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvedArtifact
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
|
||||
import java.net.http.HttpClient
|
||||
import java.net.http.HttpRequest
|
||||
import java.net.http.HttpResponse
|
||||
import java.security.MessageDigest
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
final class Util {
|
||||
public static final int ASM_LEVEL = Opcodes.ASM9
|
||||
private static final HttpClient HTTP = HttpClient.newBuilder().build()
|
||||
|
||||
static void init() {
|
||||
File.metaClass.sha1 = { ->
|
||||
MessageDigest md = MessageDigest.getInstance('SHA-1')
|
||||
delegate.eachByte(4096) { byte[] bytes, int size ->
|
||||
md.update(bytes, 0, size)
|
||||
}
|
||||
return md.digest().collect(this.&toHex).join('')
|
||||
}
|
||||
File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() }
|
||||
File.metaClass.sha256 = { ->
|
||||
MessageDigest md = MessageDigest.getInstance('SHA-256')
|
||||
delegate.eachByte(4096) { byte[] bytes, int size ->
|
||||
md.update(bytes, 0, size)
|
||||
}
|
||||
return md.digest().collect(this.&toHex).join('')
|
||||
}
|
||||
File.metaClass.getSha256 = { !delegate.exists() ? null : delegate.sha256() }
|
||||
|
||||
File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) }
|
||||
File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] }
|
||||
File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() }
|
||||
|
||||
Date.metaClass.iso8601 = { ->
|
||||
var format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
var result = format.format(delegate)
|
||||
return result[0..21] + ':' + result[22..-1]
|
||||
}
|
||||
|
||||
String.metaClass.rsplit = { String del, int limit = -1 ->
|
||||
var lst = new ArrayList<String>()
|
||||
int x = 0
|
||||
int idx
|
||||
String tmp = delegate
|
||||
while ((idx = tmp.lastIndexOf(del)) != -1 && (limit === -1 || x++ < limit)) {
|
||||
lst.add(0, tmp.substring(idx + del.length(), tmp.length()))
|
||||
tmp = tmp.substring(0, idx)
|
||||
}
|
||||
lst.add(0, tmp)
|
||||
return lst
|
||||
}
|
||||
}
|
||||
|
||||
static String[] getClasspath(Project project, Map libs, String artifact) {
|
||||
def ret = []
|
||||
artifactTree(project, artifact).each { key, lib ->
|
||||
libs[lib.name] = lib
|
||||
if (lib.name != artifact)
|
||||
ret.add(lib.name)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static Map getArtifacts(Configuration config) {
|
||||
var ret = [:]
|
||||
var semaphore = new Semaphore(1, true)
|
||||
config.resolvedConfiguration.resolvedArtifacts.parallelStream().forEachOrdered(dep -> {
|
||||
var info = getMavenInfoFromDep(dep)
|
||||
var domain = 'libraries.minecraft.net'
|
||||
var url = "https://$domain/$info.path"
|
||||
if (!checkExists(url))
|
||||
url.values[0] = 'maven.minecraftforge.net'
|
||||
|
||||
var sha1 = sha1(dep.file)
|
||||
|
||||
semaphore.acquire()
|
||||
ret[info.key] = [
|
||||
name: info.name,
|
||||
downloads: [
|
||||
artifact: [
|
||||
path: info.path,
|
||||
url: url.toString(),
|
||||
sha1: sha1,
|
||||
size: dep.file.length()
|
||||
]
|
||||
]
|
||||
]
|
||||
semaphore.release()
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static Map getMavenInfoFromDep(ResolvedArtifact dep) {
|
||||
return getMavenInfoFromMap([
|
||||
group: dep.moduleVersion.id.group,
|
||||
name: dep.moduleVersion.id.name,
|
||||
version: dep.moduleVersion.id.version,
|
||||
classifier: dep.classifier,
|
||||
extension: dep.extension
|
||||
])
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static Map getMavenInfoFromTask(AbstractArchiveTask task) {
|
||||
return getMavenInfoFromMap([
|
||||
group: task.project.group.toString(),
|
||||
name: task.project.name,
|
||||
version: task.project.version.toString(),
|
||||
classifier: task.archiveClassifier.get(),
|
||||
extension: task.archiveExtension.get()
|
||||
])
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static Map getMavenInfoFromTask(Task task, String classifier) {
|
||||
return getMavenInfoFromMap([
|
||||
group: task.project.group.toString(),
|
||||
name: task.project.name,
|
||||
version: task.project.version.toString(),
|
||||
classifier: classifier,
|
||||
extension: 'jar'
|
||||
])
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
private static Map getMavenInfoFromMap(Map<String, String> art) {
|
||||
var key = "$art.group:$art.name"
|
||||
var name = "$art.group:$art.name:$art.version"
|
||||
var path = "${art.group.replace('.', '/')}/$art.name/$art.version/$art.name-$art.version"
|
||||
if (art.classifier !== null) {
|
||||
name += ":$art.classifier"
|
||||
path += "-$art.classifier"
|
||||
}
|
||||
if ('jar' != art.extension) {
|
||||
name += "@$art.extension"
|
||||
path += ".$art.extension"
|
||||
} else {
|
||||
path += ".jar"
|
||||
}
|
||||
return [
|
||||
key: key.toString(),
|
||||
name: name.toString(),
|
||||
path: path.toString(),
|
||||
art: art
|
||||
]
|
||||
}
|
||||
|
||||
static String iso8601Now() { new Date().iso8601() }
|
||||
|
||||
@CompileStatic
|
||||
static String sha1(File file) {
|
||||
MessageDigest md = MessageDigest.getInstance('SHA-1')
|
||||
file.eachByte(4096) { byte[] bytes, int size ->
|
||||
md.update(bytes, 0, size)
|
||||
}
|
||||
return md.digest().collect(this.&toHex).join('')
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
private static String toHex(byte bite) {
|
||||
return String.format('%02x', bite)
|
||||
}
|
||||
|
||||
private static Map artifactTree(Project project, String artifact, boolean transitive = true) {
|
||||
if (!project.ext.has('tree_resolver'))
|
||||
project.ext.tree_resolver = 1
|
||||
def cfg = project.configurations.create('tree_resolver_' + project.ext.tree_resolver++)
|
||||
cfg.transitive = transitive
|
||||
def dep = project.dependencies.create(artifact)
|
||||
cfg.dependencies.add(dep)
|
||||
def files = cfg.resolve()
|
||||
return getArtifacts(cfg)
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static boolean checkExists(String url) {
|
||||
try {
|
||||
return HTTP.send(HttpRequest.newBuilder(new URI(url))
|
||||
.method('HEAD', HttpRequest.BodyPublishers.noBody()).build(), HttpResponse.BodyHandlers.discarding()
|
||||
).statusCode() === 200
|
||||
} catch (Exception e) {
|
||||
if (e.toString().contains('unable to find valid certification path to requested target'))
|
||||
throw new RuntimeException("Failed to connect to $url: Missing certificate root authority, try updating Java")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
static String getLatestForgeVersion(String mcVersion) {
|
||||
final json = new JsonSlurper().parseText(new URL('https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json').getText('UTF-8'))
|
||||
final ver = json.promos["$mcVersion-latest"]
|
||||
ver === null ? null : (mcVersion + '-' + ver)
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static void processClassNodes(File file, @ClosureParams(value = SimpleType, options = 'org.objectweb.asm.tree.ClassNode') Closure process) {
|
||||
file.withInputStream { i ->
|
||||
new ZipInputStream(i).withCloseable { zin ->
|
||||
ZipEntry zein
|
||||
while ((zein = zin.nextEntry) !== null) {
|
||||
if (zein.name.endsWith('.class')) {
|
||||
var node = new ClassNode(ASM_LEVEL)
|
||||
new ClassReader(zin).accept(node, 0)
|
||||
process(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import net.minecraftforge.srgutils.MinecraftVersion
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.objectweb.asm.tree.AnnotationNode
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
|
||||
abstract class ValidateDeprecations extends DefaultTask {
|
||||
@InputFile
|
||||
abstract RegularFileProperty getInput()
|
||||
|
||||
@Input
|
||||
abstract Property<String> getMcVersion()
|
||||
|
||||
ValidateDeprecations() {
|
||||
this.onlyIf { !System.env.TEAMCITY_VERSION }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
protected void exec() {
|
||||
var mcVer = MinecraftVersion.from(mcVersion.get())
|
||||
List<String> errors = []
|
||||
|
||||
Util.processClassNodes(input.get().asFile) {
|
||||
processNode(mcVer, errors, it)
|
||||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
errors.forEach {
|
||||
this.logger.error("Deprecated ${it[0]} is marked for removal in ${it[1]} but is not yet removed")
|
||||
}
|
||||
throw new IllegalStateException("Found deprecated members marked for removal but not yet removed in ${mcVer}; see log for details")
|
||||
}
|
||||
}
|
||||
|
||||
protected processNode(MinecraftVersion mcVer, List<String> errors, ClassNode node) {
|
||||
node.visibleAnnotations?.each { annotation ->
|
||||
ValidateDeprecations.processAnnotations(annotation, mcVer, errors) {
|
||||
"class ${node.name}"
|
||||
}
|
||||
}
|
||||
node.fields?.each { field ->
|
||||
field.visibleAnnotations?.each { annotation ->
|
||||
ValidateDeprecations.processAnnotations(annotation, mcVer, errors) {
|
||||
"field ${node.name}#${field.name}"
|
||||
}
|
||||
}
|
||||
}
|
||||
node.methods?.each { method ->
|
||||
method.visibleAnnotations?.each { annotation ->
|
||||
ValidateDeprecations.processAnnotations(annotation, mcVer, errors) {
|
||||
"method ${node.name}#${method.name}${method.desc}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processAnnotations(AnnotationNode annotation, MinecraftVersion mcVer, List<String> errors, Closure<String> context) {
|
||||
def values = annotation.values
|
||||
if (values === null)
|
||||
return
|
||||
int forRemoval = values.indexOf('forRemoval')
|
||||
int since = values.indexOf('since')
|
||||
if (annotation.desc == 'Ljava/lang/Deprecated;' && forRemoval !== -1 && since !== -1 && values.size() >= 4 && values[forRemoval + 1] === true) {
|
||||
def oldVersion = MinecraftVersion.from(values[since + 1])
|
||||
int[] split = ValidateDeprecations.splitDots(oldVersion.toString())
|
||||
if (split.length < 2)
|
||||
return
|
||||
def removeVersion = MinecraftVersion.from("${split[0]}.${split[1] + 1}")
|
||||
if (removeVersion <= mcVer)
|
||||
errors.add([context(), removeVersion])
|
||||
}
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
private static int[] splitDots(String version) {
|
||||
String[] pts = version.split('\\.')
|
||||
int[] values = new int[pts.length]
|
||||
for (int x = 0; x < pts.length; x++)
|
||||
values[x] = Integer.parseInt(pts[x])
|
||||
return values
|
||||
}
|
||||
}
|
||||
|
|
@ -1,282 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.TupleConstructor
|
||||
import net.minecraftforge.forge.tasks.InheritanceData
|
||||
import net.minecraftforge.srgutils.IMappingFile
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.objectweb.asm.Opcodes
|
||||
|
||||
@CompileStatic
|
||||
abstract class CheckATs extends CheckTask {
|
||||
|
||||
@InputFile abstract RegularFileProperty getInheritance()
|
||||
@InputFiles abstract ConfigurableFileCollection getAts()
|
||||
|
||||
@Override
|
||||
void check(Reporter reporter, boolean fix) {
|
||||
final inheritance = InheritanceData.parse(this.inheritance.get().asFile)
|
||||
|
||||
ats.each {
|
||||
final lines = process(it, reporter, inheritance)
|
||||
if (fix) {
|
||||
it.text = joinBack(lines, inheritance).join('\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TreeMap<String, ATParser.Entry> process(File file, Reporter reporter, Map<String, InheritanceData> inheritance) {
|
||||
final TreeMap<String, ATParser.Entry> lines = ATParser.parse(file.readLines(), reporter)
|
||||
final Map<String, ATParser.Entry> constructorGroups = [:]
|
||||
|
||||
final itr = lines.entrySet().iterator()
|
||||
final toRemove = []
|
||||
while (itr.hasNext()) {
|
||||
final next = itr.next()
|
||||
String key = next.key
|
||||
final entry = next.value
|
||||
if (entry === null) continue
|
||||
|
||||
final binaryName = entry.cls.replaceAll('\\.', '/')
|
||||
|
||||
// Process Groups, this will remove any entries outside the group that is covered by the group
|
||||
if (entry.group) {
|
||||
final jcls = inheritance[binaryName]
|
||||
if (jcls === null) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid group: $key")
|
||||
} else if ('*' == entry.desc) {
|
||||
if (!jcls.fields) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid group, class has no fields: $key")
|
||||
} else {
|
||||
jcls.fields.each { field, value ->
|
||||
final fkey = entry.cls + ' ' + field
|
||||
if (accessLevel(value.access) < accessStr(entry.modifier)) {
|
||||
if (lines.containsKey(fkey)) {
|
||||
toRemove.add(fkey)
|
||||
} else if (!entry.existing.contains(fkey)) {
|
||||
reporter.report("Missing group entry: $fkey")
|
||||
}
|
||||
entry.children.add(fkey)
|
||||
} else if (lines.containsKey(fkey)) {
|
||||
toRemove.add(fkey)
|
||||
reporter.report("Found invalid group entry: $fkey")
|
||||
}
|
||||
}
|
||||
entry.existing.findAll { it !in entry.children }.each { println('Removed: ' + it) }
|
||||
}
|
||||
} else if ('*()' == entry.desc) {
|
||||
if (!jcls.methods) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid group, class has no methods: $key")
|
||||
} else {
|
||||
jcls.methods.each { mtd, value ->
|
||||
if (mtd.startsWith('<clinit>') || mtd.startsWith('lambda$')) return
|
||||
key = entry.cls + ' ' + mtd.replace(' ', '')
|
||||
if (accessLevel(value.access) < accessStr(entry.modifier)) {
|
||||
if (lines.containsKey(key)) {
|
||||
toRemove.add(key)
|
||||
} else if (!entry.existing.contains(key)) {
|
||||
reporter.report("Missing group entry: $key")
|
||||
}
|
||||
entry.children.add(key)
|
||||
} else if (lines.containsKey(key)) {
|
||||
toRemove.add(key)
|
||||
reporter.report("Found invalid group entry: $key")
|
||||
}
|
||||
}
|
||||
entry.existing.findAll { it !in entry.children }.each { println('Removed: ' + it) }
|
||||
}
|
||||
} else if ('<init>' == entry.desc) { //Make all public non-abstract subclasses
|
||||
constructorGroups.put(binaryName, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Process normal lines, remove invalid and remove narrowing
|
||||
else {
|
||||
def jcls = inheritance.get(binaryName)
|
||||
if (jcls === null) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid: $key")
|
||||
} else if (entry.desc == '') {
|
||||
if (accessLevel(jcls.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid Narrowing: $key")
|
||||
}
|
||||
} else if (!entry.desc.contains('(')) {
|
||||
if (!jcls.fields || !jcls.fields.containsKey(entry.desc)) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid: $key")
|
||||
} else {
|
||||
final value = jcls.fields[entry.desc]
|
||||
if (accessLevel(value.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid Narrowing: $key - ${entry.comment}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final jdesc = entry.desc.replace('(', ' (')
|
||||
if (!jcls.methods || !jcls.methods.containsKey(jdesc)) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid: $key")
|
||||
} else {
|
||||
final value = jcls.methods[jdesc]
|
||||
if (accessLevel(value.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) {
|
||||
itr.remove()
|
||||
reporter.report("Invalid Narrowing: $key")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inheritance.each { tcls, value ->
|
||||
if (!value.methods || ((value.access & Opcodes.ACC_ABSTRACT) !== 0)) return
|
||||
String parent = tcls
|
||||
while (parent !== null) {
|
||||
constructorGroups[parent]?.tap { entry ->
|
||||
value.methods.each { mtd, v ->
|
||||
if (mtd.startsWith('<init>')) {
|
||||
final child = tcls.replaceAll('/', '\\.') + ' ' + mtd.replace(' ', '')
|
||||
if (accessLevel(v.access) < 3) {
|
||||
if (lines.containsKey(child)) {
|
||||
toRemove.add(child)
|
||||
} else if (child !in entry.existing) {
|
||||
reporter.report("Missing group entry: $child")
|
||||
}
|
||||
entry.children.add(child)
|
||||
} else if (lines.containsKey(child)) {
|
||||
toRemove.add(child)
|
||||
reporter.report("Found invalid group entry: $child")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parent = inheritance[parent]?.superName
|
||||
}
|
||||
}
|
||||
constructorGroups.values().each { entry -> entry.existing.findAll { it !in entry.children }.each{ reporter.report("Found invalid group entry: $it") } }
|
||||
|
||||
toRemove.each(lines.&remove)
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
private static List<String> joinBack(TreeMap<String, ATParser.Entry> lines, Map<String, InheritanceData> inheritance) {
|
||||
final data = [] as List<String>
|
||||
lines.each { key, value ->
|
||||
if (!value.group) {
|
||||
def comment = null //value.comment
|
||||
data.add(value.modifier + ' ' + key + (comment ? ' ' + comment : ''))
|
||||
} else {
|
||||
data.add(('#group ' + value.modifier + ' ' + key + ' ' + (value.comment ?: '')).trim())
|
||||
value.children.each {
|
||||
final line = value.modifier + ' ' + it
|
||||
final entry = ATParser.parseEntry(line)
|
||||
final comment = null //entry.comment
|
||||
data.add(line + (comment ? ' ' + comment : ''))
|
||||
}
|
||||
data.add('#endgroup')
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
static int accessStr(String access) {
|
||||
if (access.endsWith('-f') || access.endsWith('+f')) return 4
|
||||
switch (access.toLowerCase()) {
|
||||
case 'public': return 3
|
||||
case 'protected': return 2
|
||||
case 'default': return 1
|
||||
case 'private': return 0
|
||||
default: return -1
|
||||
}
|
||||
}
|
||||
|
||||
static int accessLevel(int access) {
|
||||
if ((access & Opcodes.ACC_PUBLIC) !== 0) return 3
|
||||
if ((access & Opcodes.ACC_PROTECTED) !== 0) return 2
|
||||
if ((access & Opcodes.ACC_PRIVATE) !== 0) return 0
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
class ATParser {
|
||||
static TreeMap<String, Entry> parse(List<String> lines, CheckTask.Reporter reporter) {
|
||||
TreeMap<String, Entry> outLines = new TreeMap<>()
|
||||
Entry group = null
|
||||
for (final line : lines) {
|
||||
if (line.isEmpty()) continue
|
||||
if (line.startsWith('#group ')) {
|
||||
final entry = parseEntry(line.substring(7))
|
||||
|
||||
if (entry.desc != '*' && entry.desc != '*()' && entry.desc != '<init>') {
|
||||
reporter.report("Invalid group: $line", false)
|
||||
}
|
||||
|
||||
entry.group = true
|
||||
entry.children = []
|
||||
entry.existing = []
|
||||
|
||||
group = entry
|
||||
|
||||
if (outLines.containsKey(entry.key)) {
|
||||
reporter.report("Duplicate group: $line", false)
|
||||
}
|
||||
|
||||
outLines[entry.key] = group
|
||||
} else if (group !== null) {
|
||||
if (line.startsWith('#endgroup')) {
|
||||
group = null
|
||||
} else {
|
||||
final key = parseEntry(line).key
|
||||
group.existing.add(key)
|
||||
}
|
||||
} else if (line.startsWith('#endgroup')) {
|
||||
reporter.report("Invalid group ending: $line", false)
|
||||
} else if (line.startsWith('#')) {
|
||||
//Nom
|
||||
} else {
|
||||
final entry = parseEntry(line)
|
||||
if (outLines.containsKey(entry.key)) {
|
||||
reporter.report("Found duplicate: $line")
|
||||
continue
|
||||
}
|
||||
outLines[entry.key] = entry
|
||||
}
|
||||
}
|
||||
return outLines
|
||||
}
|
||||
|
||||
static Entry parseEntry(String line) {
|
||||
final idx = line.indexOf('#')
|
||||
final String comment = idx === -1 ? null : line.substring(idx)
|
||||
if (idx !== -1) line = line.substring(0, idx - 1)
|
||||
final data = (line.trim() + ' ').split(' ', -1)
|
||||
data[1] = data[1].replaceAll('/', '.') // Convert to Source names, internal names are fine by spec, but not supported by old AST based AT implementations.
|
||||
new Entry(data[0], data[1], data[2], comment)
|
||||
}
|
||||
|
||||
@TupleConstructor
|
||||
static final class Entry {
|
||||
String modifier, cls, desc, comment
|
||||
|
||||
Set<String> existing
|
||||
TreeSet<String> children
|
||||
boolean group = false
|
||||
|
||||
@Lazy
|
||||
String key = {cls + (desc.isEmpty() ? '' : ' ' + desc)}()
|
||||
|
||||
Object getAt(String key) {
|
||||
return getProperty(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import net.minecraftforge.forge.tasks.Util
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassVisitor
|
||||
import org.objectweb.asm.MethodVisitor
|
||||
import org.objectweb.asm.Type
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
abstract class CheckExcs extends CheckTask {
|
||||
|
||||
@InputFile abstract RegularFileProperty getBinary()
|
||||
@InputFiles abstract ConfigurableFileCollection getExcs()
|
||||
|
||||
@Override
|
||||
void check(Reporter reporter, boolean fix) {
|
||||
final Set<String> known = []
|
||||
collectKnown(known)
|
||||
|
||||
excs.each { f ->
|
||||
final lines = []
|
||||
f.eachLine { line ->
|
||||
int idx = line.indexOf('#')
|
||||
if (idx === 0 || line.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (idx !== -1) line = line.substring(0, idx - 1)
|
||||
|
||||
if (!line.contains('=')) {
|
||||
reporter.report("Invalid: $line")
|
||||
return
|
||||
}
|
||||
|
||||
def (String key, String value) = line.split('=', 2)
|
||||
if (!known.contains(key)) {
|
||||
reporter.report("Unknown: $line")
|
||||
return
|
||||
}
|
||||
|
||||
String desc = key.split('\\.', 2)[1]
|
||||
if (!desc.contains('(')) {
|
||||
reporter.report("Invalid: $line")
|
||||
return
|
||||
}
|
||||
desc = '(' + desc.split('\\(', 2)[1]
|
||||
|
||||
def (exceptions, String args) = value.contains('|') ? value.split('|', 2) : [value, '']
|
||||
|
||||
if (args.split(',').length !== Type.getArgumentTypes(desc).length) {
|
||||
reporter.report("Invalid: $line")
|
||||
return
|
||||
}
|
||||
lines.add(line)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (fix) f.text = lines.sort().join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
private void collectKnown(Collection<String> known) {
|
||||
binary.get().asFile.withInputStream { i ->
|
||||
new ZipInputStream(i).withCloseable { zin ->
|
||||
final visitor = new ClassVisitor(Util.ASM_LEVEL) {
|
||||
private String cls
|
||||
@Override
|
||||
void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
this.cls = name
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
known.add(this.cls + '.' + name + descriptor)
|
||||
super.visitMethod(access, name, descriptor, signature, exceptions)
|
||||
}
|
||||
}
|
||||
ZipEntry zein
|
||||
while ((zein = zin.nextEntry) !== null) {
|
||||
if (zein.name.endsWith('.class')) {
|
||||
ClassReader reader = new ClassReader(zin)
|
||||
reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
|
||||
@CompileStatic
|
||||
enum CheckMode {
|
||||
CHECK,
|
||||
FIX
|
||||
|
||||
CheckMode() {}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Optional
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@CompileStatic
|
||||
abstract class CheckPatches extends CheckTask {
|
||||
|
||||
private static final Pattern HUNK_START_PATTERN = Pattern.compile('^@@ -[0-9,]* \\+[0-9,_]* @@$')
|
||||
private static final Pattern WHITESPACE_PATTERN = Pattern.compile('^[+\\-]\\s*$')
|
||||
private static final Pattern IMPORT_PATTERN = Pattern.compile('^[+\\-]\\s*import.*')
|
||||
private static final Pattern FIELD_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^=;]*)(=.*)?;\\s*$')
|
||||
private static final Pattern METHOD_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^(]*)[(]([^)]*)?[)]\\s*[{]\\s*$')
|
||||
private static final Pattern CLASS_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final[\\s]*)?(class|interface)([^{]*)[{]\\s*$')
|
||||
private static final Map<String, Integer> ACCESS_MAP = [private: 0, protected: 2, public: 3].tap { it.put(null, 1) }
|
||||
|
||||
@InputDirectory abstract DirectoryProperty getPatchDir()
|
||||
@Input @Optional abstract ListProperty<String> getPatchesWithS2SArtifact()
|
||||
|
||||
@Override
|
||||
void check(Reporter reporter, boolean fix) {
|
||||
final patchDir = getPatchDir().get().asFile.toPath()
|
||||
Files.walk(patchDir).withCloseable {
|
||||
it.filter(Files.&isRegularFile).forEach { path ->
|
||||
final String relativeName = patchDir.relativize(path).toString()
|
||||
verifyPatch(path, reporter, fix, relativeName, patchesWithS2SArtifact.get().contains(relativeName.replace('\\', '/')))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean accessChange(String previous, String current) {
|
||||
//return ACCESS_MAP[previous] < ACCESS_MAP[current]
|
||||
return previous != current
|
||||
}
|
||||
|
||||
void verifyPatch(Path patch, Reporter reporter, boolean fix, String patchPath, boolean hasS2SArtifact) {
|
||||
int oldFixedErrors = reporter.fixed.size()
|
||||
|
||||
final lines = Files.readAllLines(patch)
|
||||
|
||||
int hunksStart = 0
|
||||
boolean onlyWhiteSpace = false
|
||||
|
||||
final List<String> newLines = []
|
||||
|
||||
// First two lines are file name ++/-- and we do not care
|
||||
newLines.add(lines[0] + '\n')
|
||||
newLines.add(lines[1] + '\n')
|
||||
|
||||
int i
|
||||
for (i = 2; i < lines.size(); ++i) {
|
||||
def line = lines[i]
|
||||
newLines.add(line + '\n')
|
||||
|
||||
if (HUNK_START_PATTERN.matcher(line).find()) {
|
||||
if (onlyWhiteSpace) {
|
||||
if (!hasS2SArtifact)
|
||||
reporter.report("Patch contains only white space hunk starting at line ${hunksStart + 1}, file: $patchPath")
|
||||
int toRemove = i - hunksStart
|
||||
while (toRemove-- > 0)
|
||||
newLines.remove(newLines.size() - 1)
|
||||
}
|
||||
hunksStart = i
|
||||
onlyWhiteSpace = true
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.startsWithAny('+','-')) {
|
||||
def prefixChange = false
|
||||
def prevLine = lines[i - 1]
|
||||
|
||||
if (line.charAt(0) == (char)'+' && prevLine.charAt(0) == (char)'-') {
|
||||
def prevTrim = prevLine.substring(1).replaceAll("\\s", "")
|
||||
def currTrim = line.substring(1).replaceAll("\\s", "")
|
||||
|
||||
if (prevTrim == currTrim) {
|
||||
prefixChange = true
|
||||
}
|
||||
|
||||
def pMatcher = FIELD_PATTERN.matcher(prevLine)
|
||||
def cMatcher = FIELD_PATTERN.matcher(line)
|
||||
|
||||
if (pMatcher.find() && cMatcher.find() &&
|
||||
pMatcher.group(6) == cMatcher.group(6) && // = ...
|
||||
pMatcher.group(5) == cMatcher.group(5) && // field name
|
||||
pMatcher.group(3) == cMatcher.group(3) && // static
|
||||
(accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) {
|
||||
reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false)
|
||||
}
|
||||
|
||||
pMatcher = METHOD_PATTERN.matcher(prevLine)
|
||||
cMatcher = METHOD_PATTERN.matcher(line)
|
||||
|
||||
if (pMatcher.find() && cMatcher.find() &&
|
||||
pMatcher.group(6) == cMatcher.group(6) && // params
|
||||
pMatcher.group(5) == cMatcher.group(5) && // <T> void name
|
||||
pMatcher.group(3) == cMatcher.group(3) && // static
|
||||
(accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) {
|
||||
reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false)
|
||||
}
|
||||
|
||||
pMatcher = CLASS_PATTERN.matcher(prevLine)
|
||||
cMatcher = CLASS_PATTERN.matcher(line)
|
||||
|
||||
if (pMatcher.find() && cMatcher.find() &&
|
||||
pMatcher.group(6) == cMatcher.group(6) && // ClassName<> extends ...
|
||||
pMatcher.group(5) == cMatcher.group(5) && // class | interface
|
||||
pMatcher.group(3) == cMatcher.group(3) && // static
|
||||
(accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) {
|
||||
reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false)
|
||||
}
|
||||
}
|
||||
|
||||
if (line.charAt(0) == (char)'-' && i + 1 < lines.size()) {
|
||||
final nextLine = lines[i + 1]
|
||||
if (nextLine.charAt(0) == (char)'+') {
|
||||
final nextTrim = nextLine.substring(1).replaceAll("\\s", "")
|
||||
final currTrim = line.substring(1).replaceAll("\\s", "")
|
||||
|
||||
if (nextTrim == currTrim) {
|
||||
prefixChange = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final isWhiteSpaceChange = WHITESPACE_PATTERN.matcher(line).find()
|
||||
|
||||
if (!prefixChange && !isWhiteSpaceChange) {
|
||||
onlyWhiteSpace = hasS2SArtifact && IMPORT_PATTERN.matcher(line).find()
|
||||
} else if (isWhiteSpaceChange) {
|
||||
final prevLineChange = prevLine.startsWithAny('+','-')
|
||||
final nextLineChange = i + 1 < lines.size() && lines[i + 1].startsWithAny('+','-')
|
||||
|
||||
if (!prevLineChange && !nextLineChange) {
|
||||
reporter.report("Patch contains white space change in valid hunk at line ${i + 1}, file: $patchPath \n$prevLine\n$line\n${lines[i+1]}", false)
|
||||
}
|
||||
}
|
||||
|
||||
if (line.contains('\t')) {
|
||||
reporter.report("Patch contains tabs on line ${i + 1}, file: $patchPath")
|
||||
line = line.replaceAll('\t', ' ')
|
||||
newLines.remove(newLines.size() - 1)
|
||||
newLines.add(line + '\n')
|
||||
}
|
||||
|
||||
if (IMPORT_PATTERN.matcher(line).find() && !hasS2SArtifact) {
|
||||
reporter.report("Patch contains import change on line ${i + 1}, file: $patchPath", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyWhiteSpace) {
|
||||
if (!hasS2SArtifact)
|
||||
reporter.report("Patch contains only white space hunk starting at line ${hunksStart + 1}, file: $patchPath")
|
||||
def toRemove = i - hunksStart;
|
||||
while (toRemove-- > 0)
|
||||
newLines.remove(newLines.size() - 1)
|
||||
}
|
||||
|
||||
if ((reporter.fixed.size() > oldFixedErrors && fix) || hasS2SArtifact) {
|
||||
if (newLines.size() <= 2) {
|
||||
logger.lifecycle("Patch is now empty removing, file: {}", patchPath)
|
||||
Files.delete(patch)
|
||||
}
|
||||
else {
|
||||
if (!hasS2SArtifact)
|
||||
logger.lifecycle("*** Updating patch file. Please run setup then genPatches again. ***")
|
||||
Files.newBufferedWriter(patch).withCloseable {
|
||||
newLines.each { l -> it.write(l) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import net.minecraftforge.forge.tasks.Annotatable
|
||||
import net.minecraftforge.forge.tasks.InheritanceData
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
|
||||
@CompileStatic
|
||||
abstract class CheckSAS extends CheckTask {
|
||||
|
||||
@InputFile abstract RegularFileProperty getInheritance()
|
||||
@InputFiles abstract ConfigurableFileCollection getSass()
|
||||
|
||||
@Override
|
||||
void check(Reporter reporter, boolean fix) {
|
||||
final inheritance = InheritanceData.parse(this.inheritance.get().asFile)
|
||||
|
||||
sass.each { f ->
|
||||
final lines = []
|
||||
f.eachLine { line ->
|
||||
if (line[0] == '\t') return // Skip any tabbed lines, those are ones we add
|
||||
final idx = line.indexOf('#')
|
||||
if (idx == 0 || line.isEmpty()) {
|
||||
lines.add(line)
|
||||
return
|
||||
}
|
||||
def comment = idx == -1 ? null : line.substring(idx)
|
||||
if (idx != -1) line = line.substring(0, idx - 1)
|
||||
final spl = (line.trim().replace('(', ' (') + ' ').split(' ', -1)
|
||||
def (String cls, String name, String desc) = [spl[0], spl[1], spl[2]]
|
||||
cls = cls.replaceAll('\\.', '/')
|
||||
|
||||
if (inheritance[cls] === null) {
|
||||
reporter.report("Invalid: $line")
|
||||
} else if (name.isEmpty()) { //Class SAS
|
||||
final toAdd = []
|
||||
final clsSided = isSided(inheritance[cls])
|
||||
boolean sided = clsSided
|
||||
|
||||
/* TODO: MergeTool doesn't do fields
|
||||
if (json[cls]['fields'] != null) {
|
||||
for (entry in json[cls]['fields']) {
|
||||
if (isSided(entry.value)) {
|
||||
sided = true
|
||||
toAdd.add('\t' + cls + ' ' + entry.key)
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
final clsInh = inheritance[cls]
|
||||
if (clsInh.methods) {
|
||||
for (entry in clsInh.methods) {
|
||||
if (isSided(entry.value)) {
|
||||
sided = true
|
||||
toAdd.add('\t' + cls + ' ' + entry.key.replaceAll(' ', ''))
|
||||
findChildMethods(inheritance, cls, entry.key).each { lines.add('\t' + it) }
|
||||
findChildMethods(inheritance, cls, entry.key).each { println(line + ' -- ' + it) }
|
||||
} else if (clsSided) {
|
||||
findChildMethods(inheritance, cls, entry.key).each { lines.add('\t' + it) }
|
||||
findChildMethods(inheritance, cls, entry.key).each { println(line + ' -- ' + it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sided) {
|
||||
lines.add(cls + (comment == null ? '' : ' ' + comment))
|
||||
lines.addAll(toAdd.sort())
|
||||
} else {
|
||||
reporter.report("Invalid: $line")
|
||||
}
|
||||
|
||||
} else if (desc.isEmpty()) { // Fields
|
||||
/* TODO: MergeTool doesn't do fields
|
||||
if (json[cls]['fields'] != null && isSided(json[cls]['fields'][name]))
|
||||
lines.add(cls + ' ' + name + (comment == null ? '' : ' ' + comment))
|
||||
else */
|
||||
reporter.report("Invalid: $line")
|
||||
} else { // Methods
|
||||
final clsInh = inheritance[cls]
|
||||
if (clsInh.methods === null || !isSided(clsInh.methods[name + ' ' + desc]))
|
||||
reporter.report("Invalid: $line")
|
||||
else {
|
||||
lines.add(cls + ' ' + name + desc + (comment == null ? '' : ' ' + comment))
|
||||
findChildMethods(inheritance, cls, name + ' ' + desc).each { println(line + ' -- ' + it) }
|
||||
findChildMethods(inheritance, cls, name + ' ' + desc).each { lines.add('\t' + it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fix) f.text = lines.join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isSided(Annotatable annotatable) {
|
||||
if (annotatable === null) return false
|
||||
for (ann in annotatable.annotations) {
|
||||
if ('Lnet/minecraftforge/api/distmarker/OnlyIn;' == ann.desc)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
protected static findChildMethods(Map<String, InheritanceData> json, String cls, String desc) {
|
||||
return json.values().findAll{ it.methods !== null && it.methods[desc] !== null && it.methods[desc].override == cls && isSided(it.methods[desc]) }
|
||||
.collect { it.name + ' ' + desc.replace(' ', '') } as TreeSet
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
package net.minecraftforge.forge.tasks.checks
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.stc.ClosureParams
|
||||
import groovy.transform.stc.ThirdParam
|
||||
import net.minecraftforge.forge.tasks.Util
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.TaskContainer
|
||||
import org.gradle.api.tasks.VerificationTask
|
||||
|
||||
@CompileStatic
|
||||
abstract class CheckTask extends DefaultTask implements VerificationTask {
|
||||
@Input
|
||||
abstract Property<CheckMode> getMode()
|
||||
|
||||
private boolean ignoreFailures = false
|
||||
|
||||
@Input
|
||||
@Override
|
||||
boolean getIgnoreFailures() {
|
||||
return ignoreFailures
|
||||
}
|
||||
|
||||
@Override
|
||||
void setIgnoreFailures(boolean ignoreFailures) {
|
||||
this.ignoreFailures = ignoreFailures
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
Util.init()
|
||||
|
||||
boolean doFix = getMode().get() === CheckMode.FIX
|
||||
final Reporter reporter = new Reporter(doFix)
|
||||
check(reporter, doFix)
|
||||
|
||||
if (reporter.messages) {
|
||||
if (getMode().get() === CheckMode.CHECK) {
|
||||
logger.error("Check task '{}' found errors:\n{}", name, reporter.messages.join('\n'))
|
||||
if (!ignoreFailures) {
|
||||
throw new IllegalArgumentException("${reporter.messages.size()} errors were found!")
|
||||
}
|
||||
} else {
|
||||
if (logger.isEnabled(LogLevel.DEBUG)) {
|
||||
logger.warn("Check task '{}' found {} errors and fixed {}:\n{}", name, reporter.messages.size(), reporter.fixed.size(), reporter.fixed.join('\n'))
|
||||
} else {
|
||||
logger.warn("Check task '{}' found {} errors and fixed {}.", name, reporter.messages.size(), reporter.fixed.size())
|
||||
}
|
||||
|
||||
if (reporter.notFixed) {
|
||||
logger.error('{} errors could not be fixed:\n{}', reporter.notFixed.size(), reporter.notFixed.join('\n'))
|
||||
if (!ignoreFailures) {
|
||||
throw new IllegalArgumentException("${reporter.notFixed.size()} errors which cannot be fixed were found!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract void check(Reporter reporter, boolean fix)
|
||||
|
||||
@CompileStatic
|
||||
static final class Reporter {
|
||||
final boolean trackFixed
|
||||
Reporter(boolean trackFixed) {
|
||||
this.trackFixed = trackFixed
|
||||
}
|
||||
|
||||
public final List<String> messages = []
|
||||
|
||||
public final List<String> fixed = []
|
||||
public final List<String> notFixed = []
|
||||
|
||||
void report(String message, boolean canBeFixed = true) {
|
||||
messages.add(message)
|
||||
|
||||
if (trackFixed) {
|
||||
if (canBeFixed) {
|
||||
fixed.add(message)
|
||||
} else {
|
||||
notFixed.add(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static <T extends CheckTask> void registerTask(TaskContainer tasks, String taskName, @DelegatesTo.Target('type') Class<T> clazz,
|
||||
@DelegatesTo(genericTypeIndex = 0, target = 'type')
|
||||
@ClosureParams(ThirdParam.FirstGenericType) Closure configuration) {
|
||||
taskName = taskName.capitalize()
|
||||
tasks.register("check$taskName", clazz) { CheckTask task ->
|
||||
def castedTask = task as T
|
||||
configuration.setDelegate(castedTask)
|
||||
configuration.call(castedTask)
|
||||
castedTask.mode.set(CheckMode.CHECK)
|
||||
castedTask.group = 'checks'
|
||||
}
|
||||
tasks.named('checkAll').configure { it.dependsOn("check$taskName") }
|
||||
|
||||
tasks.register("checkAndFix$taskName", clazz) { CheckTask task ->
|
||||
def castedTask = task as T
|
||||
configuration.setDelegate(castedTask)
|
||||
configuration.call(castedTask)
|
||||
castedTask.mode.set(CheckMode.FIX)
|
||||
castedTask.group = 'checks'
|
||||
}
|
||||
tasks.named('checkAllAndFix').configure { it.dependsOn("checkAndFix$taskName") }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
id 'net.minecraftforge.gradle.patcher'
|
||||
}
|
||||
|
||||
evaluationDependsOn(':mcp')
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven gradleutils.forgeMaven
|
||||
maven gradleutils.minecraftLibsMaven
|
||||
}
|
||||
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
|
||||
dependencies {
|
||||
implementation(libs.forgespi)
|
||||
}
|
||||
|
||||
patcher {
|
||||
parent = project(':mcp')
|
||||
mcVersion = MC_VERSION
|
||||
patchedSrc = file('src/main/java')
|
||||
|
||||
mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION
|
||||
|
||||
runs {
|
||||
clean_client {
|
||||
client true
|
||||
taskName 'clean_client'
|
||||
ideaModule "${rootProject.name}.${project.name}.main"
|
||||
|
||||
main 'net.minecraft.client.main.Main'
|
||||
workingDirectory project.file('run/client')
|
||||
|
||||
args '--gameDir', '.'
|
||||
args '--version', MC_VERSION
|
||||
args '--assetsDir', downloadAssets.output
|
||||
args '--assetIndex', '{asset_index}'
|
||||
args '--accessToken', '0'
|
||||
}
|
||||
|
||||
clean_server {
|
||||
client false
|
||||
taskName 'clean_server'
|
||||
ideaModule "${rootProject.name}.${project.name}.main"
|
||||
|
||||
main 'net.minecraft.server.Main'
|
||||
workingDirectory project.file('run/server')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||
options.warnings = false // Shutup deprecated for removal warnings
|
||||
}
|
||||
|
||||
eclipse.classpath.file.whenMerged {
|
||||
// Disable optional warnings on the minecraft decompiled source code. It just muddies the warning window and hides warnings in our own codebase
|
||||
def src = entries.find { it.path == 'src/main/java' }
|
||||
if (src == null) throw new IllegalStateException("You must run `setup` task before importing")
|
||||
src.entryAttributes['ignore_optional_problems'] = 'true'
|
||||
}
|
||||
|
||||
tasks.named('genPatches').configure {
|
||||
onlyIf { false }
|
||||
}
|
||||
|
||||
tasks.named('extractRangeMap').configure {
|
||||
onlyIf { false }
|
||||
tool = 'net.minecraftforge:Srg2Source:8.1.0:fatjar'
|
||||
}
|
||||
1021
build_forge.gradle
1021
build_forge.gradle
File diff suppressed because it is too large
Load diff
|
|
@ -1,89 +0,0 @@
|
|||
import net.minecraftforge.forge.tasks.CleanProperties
|
||||
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'net.minecraftforge.gradleutils'
|
||||
|
||||
group = 'net.minecraftforge'
|
||||
version = VERSION
|
||||
println("Version: $version")
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven gradleutils.forgeMaven
|
||||
maven gradleutils.minecraftLibsMaven
|
||||
//mavenLocal()
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc).configureEach {
|
||||
options.tags = [
|
||||
'apiNote:a:<em>API Note:</em>',
|
||||
'implSpec:a:<em>Implementation Requirements:</em>',
|
||||
'implNote:a:<em>Implementation Note:</em>'
|
||||
]
|
||||
options.addStringOption('Xdoclint:all,-missing', '-public')
|
||||
}
|
||||
|
||||
// We need to write the manifest to the binary file so we have properly versioned packaged at dev time.
|
||||
tasks.register('writeManifest') {
|
||||
doLast {
|
||||
if (plugins.findPlugin('net.minecraftforge.gradle.patcher')) // Forge project
|
||||
universalJar.manifest.writeTo(rootProject.file('src/main/resources/META-INF/MANIFEST.MF'))
|
||||
else
|
||||
jar.manifest.writeTo(project.file('src/main/resources/META-INF/MANIFEST.MF'))
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('generateResources') {
|
||||
dependsOn('writeManifest')
|
||||
}
|
||||
|
||||
tasks.named('processResources') {
|
||||
dependsOn(generateResources)
|
||||
}
|
||||
|
||||
// Make sure out manifests get written before compiling the code, IDEA calls this task if you tell it to use the gradle build.
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
dependsOn 'generateResources'
|
||||
dependsOn 'processResources' // Needed because we merge the output of this with the output of the compile task. And gradle detects downstream tasks using the output without a hard dep
|
||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||
options.warnings = false // Shutup deprecated for removal warnings
|
||||
options.forkOptions.jvmArgs += '-Xmx6G' // Needed to make compiling faster, and not run out of heap space in some cases.
|
||||
}
|
||||
|
||||
// Merge the resources and classes into the same directory. We'll need to split them at runtime because
|
||||
// Minecraft and Forge are in the same sourceSet as they are inter dependent.. for now..
|
||||
sourceSets.each {
|
||||
def dir = layout.buildDirectory.dir("classes/java/$it.name")
|
||||
it.output.resourcesDir = dir
|
||||
it.java.destinationDirectory = dir
|
||||
}
|
||||
|
||||
tasks.register('copyEclipseSettings') {
|
||||
doLast {
|
||||
rootProject.fileTree('ide/eclipse/template/.settings/').matching { include '**/*.prefs' }.each { file ->
|
||||
def target = project.file('.settings/' + file.name)
|
||||
def temp = new CleanProperties().load(file)
|
||||
def exst = new CleanProperties().load(target)
|
||||
exst.put('eclipse.preferences.version', '1')
|
||||
exst.putAll(temp)
|
||||
exst.store(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [Gradle][IntelliJ] Auto trigger these tasks on import.
|
||||
eclipse {
|
||||
// Run everytime eclipse builds the code
|
||||
//autoBuildTasks writeManifest
|
||||
// Run when importing the project
|
||||
synchronizationTasks generateResources, copyEclipseSettings, eclipseClasspath, eclipseProject
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
// IntelliJ IDEA does not do this by itself anymore...
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
MinecraftForge
|
||||
=============
|
||||
[][Download]
|
||||
[][Download]
|
||||
[][Download] [][Discord] [][Patreon]
|
||||
|
||||
Forge is a free, open-source modding API all of your favourite mods use!
|
||||
|
|
|
|||
|
|
@ -1,68 +1,78 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
gradleutils.displayName = 'FML'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Modifications to Minecraft to enable mod developers.'
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
api(libs.eventbus)
|
||||
annotationProcessor(libs.eventbus.validator)
|
||||
api libs.eventbus
|
||||
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(libs.commons.io)
|
||||
implementation projects.fmlloader
|
||||
implementation libs.commons.io
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.fmlcore',
|
||||
'FMLModType': 'LIBRARY'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'FML',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FML',
|
||||
'Implementation-Version': '1.0',
|
||||
'Implementation-Vendor': 'Forge Development LLC'
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/')
|
||||
}
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:-unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.fmlcore',
|
||||
'FMLModType' : 'LIBRARY'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Version': '1.0',
|
||||
'Implementation-Vendor' : vendor
|
||||
], 'net/minecraftforge/fml/')
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'fmlcore'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Modifactions to Minecraft to enable mod developers.'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,14 @@ import java.util.List;
|
|||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CrashReportCallables
|
||||
{
|
||||
public class CrashReportCallables {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final List<ISystemReportExtender> crashCallables = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
/**
|
||||
* Register a custom {@link ISystemReportExtender}
|
||||
*/
|
||||
public static void registerCrashCallable(ISystemReportExtender callable)
|
||||
{
|
||||
public static void registerCrashCallable(ISystemReportExtender callable) {
|
||||
crashCallables.add(callable);
|
||||
}
|
||||
|
||||
|
|
@ -33,19 +31,15 @@ public class CrashReportCallables
|
|||
* @param headerName The name of the system report entry
|
||||
* @param reportGenerator The report generator to be called when a crash report is built
|
||||
*/
|
||||
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator)
|
||||
{
|
||||
registerCrashCallable(new ISystemReportExtender()
|
||||
{
|
||||
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator) {
|
||||
registerCrashCallable(new ISystemReportExtender() {
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
public String getLabel() {
|
||||
return headerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get()
|
||||
{
|
||||
public String get() {
|
||||
return reportGenerator.get();
|
||||
}
|
||||
});
|
||||
|
|
@ -58,31 +52,23 @@ public class CrashReportCallables
|
|||
* @param reportGenerator The report generator to be called when a crash report is built
|
||||
* @param active The supplier of the flag to be checked when a crash report is built
|
||||
*/
|
||||
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator, BooleanSupplier active)
|
||||
{
|
||||
registerCrashCallable(new ISystemReportExtender()
|
||||
{
|
||||
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator, BooleanSupplier active) {
|
||||
registerCrashCallable(new ISystemReportExtender() {
|
||||
@Override
|
||||
public String getLabel()
|
||||
{
|
||||
public String getLabel() {
|
||||
return headerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get()
|
||||
{
|
||||
public String get() {
|
||||
return reportGenerator.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
try
|
||||
{
|
||||
public boolean isActive() {
|
||||
try {
|
||||
return active.getAsBoolean();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
} catch (Throwable t) {
|
||||
LOGGER.warn("CrashCallable '{}' threw an exception while checking the active flag, disabling", headerName, t);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -90,8 +76,7 @@ public class CrashReportCallables
|
|||
});
|
||||
}
|
||||
|
||||
public static List<ISystemReportExtender> allCrashCallables()
|
||||
{
|
||||
public static List<ISystemReportExtender> allCrashCallables() {
|
||||
return List.copyOf(crashCallables);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ package net.minecraftforge.fml;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface ISystemReportExtender extends Supplier<String>
|
||||
{
|
||||
public interface ISystemReportExtender extends Supplier<String> {
|
||||
String getLabel();
|
||||
|
||||
default boolean isActive()
|
||||
{
|
||||
default boolean isActive() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public abstract class ModContainer {
|
|||
Supplier<IExtensionPoint.DisplayTest> displayTestSupplier = switch (displayTestString) {
|
||||
case "MATCH_VERSION" -> // default displaytest checks for version string match
|
||||
() -> new IExtensionPoint.DisplayTest(() -> this.modInfo.getVersion().toString(),
|
||||
(incoming, isNetwork) -> Objects.equals(incoming, this.modInfo.getVersion().toString()));
|
||||
(incoming, _) -> Objects.equals(incoming, this.modInfo.getVersion().toString()));
|
||||
case "IGNORE_SERVER_VERSION" -> // Ignores any version information coming from the server - use for server only mods
|
||||
IExtensionPoint.DisplayTest.IGNORE_SERVER_VERSION;
|
||||
case "IGNORE_ALL_VERSION" -> // Ignores all information and provides no information
|
||||
|
|
|
|||
|
|
@ -379,8 +379,8 @@ public final class ModLoader {
|
|||
@SuppressWarnings("removal")
|
||||
public static <T extends IModBusEvent> void postEventWrapContainerInModOrder(T event) {
|
||||
postEventWithWrapInModOrder(event,
|
||||
(mc, e) -> ModLoadingContext.get().setActiveContainer(mc),
|
||||
(mc, e) -> ModLoadingContext.get().setActiveContainer(null)
|
||||
(mc, _) -> ModLoadingContext.get().setActiveContainer(mc),
|
||||
(_, _) -> ModLoadingContext.get().setActiveContainer(null)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import net.minecraftforge.fml.loading.progress.ProgressMeter;
|
|||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Function;
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ final class ModStateTransitionHelper {
|
|||
results[i] = raw.whenComplete((result, exception) -> list.set(i, new FutureResult<>(result, exception)));
|
||||
}
|
||||
|
||||
return CompletableFuture.allOf(results).handle((r, th)->null).thenApply(res -> list);
|
||||
return CompletableFuture.allOf(results).handle((_, _)->null).thenApply(_ -> list);
|
||||
}
|
||||
|
||||
private static <T extends IModBusEvent> CompletableFuture<Void> addCompletableFutureTaskForModDispatch(
|
||||
|
|
@ -135,7 +135,7 @@ final class ModStateTransitionHelper {
|
|||
handler.run();
|
||||
mod.acceptEvent(eventGenerator.apply(mod));
|
||||
}, executor)
|
||||
.whenComplete((mc, exception) -> {
|
||||
.whenComplete((_, exception) -> {
|
||||
mod.modLoadingStage = nextState.apply(mod.modLoadingStage, exception);
|
||||
progressBar.increment();
|
||||
ModLoadingContext.get().setActiveContainer(null);
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import java.util.concurrent.Executor;
|
|||
import java.util.function.BinaryOperator;
|
||||
|
||||
public enum ThreadSelector implements BinaryOperator<Executor> {
|
||||
SYNC((sync, parallel) -> sync),
|
||||
PARALLEL((sync, parallel) -> parallel);
|
||||
SYNC((sync, _) -> sync),
|
||||
PARALLEL((_, parallel) -> parallel);
|
||||
|
||||
private final BinaryOperator<Executor> selector;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ import net.minecraftforge.fml.loading.StringUtils;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ModConfig
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,67 +1,74 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
import org.gradle.api.plugins.jvm.JvmTestSuite
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'jvm-test-suite'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
switch (OperatingSystem.current()) {
|
||||
case OperatingSystem.LINUX:
|
||||
project.ext.lwjglNatives = "natives-linux"
|
||||
break
|
||||
case OperatingSystem.MAC_OS:
|
||||
project.ext.lwjglNatives = "natives-macos"
|
||||
break
|
||||
case OperatingSystem.WINDOWS:
|
||||
project.ext.lwjglNatives = "natives-windows"
|
||||
break
|
||||
case OperatingSystem.LINUX:
|
||||
project.ext.lwjglNatives = "natives-linux"
|
||||
break
|
||||
case OperatingSystem.MAC_OS:
|
||||
project.ext.lwjglNatives = "natives-macos"
|
||||
break
|
||||
case OperatingSystem.WINDOWS:
|
||||
project.ext.lwjglNatives = "natives-windows"
|
||||
break
|
||||
}
|
||||
|
||||
gradleutils.displayName = 'FML Early Display'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'A pretty looking, but prone to erroring screen displayed during Forge loading.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
implementation(libs.bundles.lwjgl)
|
||||
implementation('org.slf4j:slf4j-api:1.8.0-beta4')
|
||||
implementation(libs.jopt.simple)
|
||||
testImplementation('org.junit.jupiter:junit-jupiter-api:5.8.2')
|
||||
testImplementation('org.powermock:powermock-core:2.0.9')
|
||||
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.8.2')
|
||||
testRuntimeOnly('org.slf4j:slf4j-jdk14:1.8.0-beta4')
|
||||
testRuntimeOnly("org.lwjgl:lwjgl::$lwjglNatives")
|
||||
testRuntimeOnly("org.lwjgl:lwjgl-glfw::$lwjglNatives")
|
||||
testRuntimeOnly("org.lwjgl:lwjgl-opengl::$lwjglNatives")
|
||||
testRuntimeOnly("org.lwjgl:lwjgl-stb::$lwjglNatives")
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
implementation projects.fmlloader
|
||||
implementation projects.fmlcore
|
||||
implementation libs.bundles.lwjgl
|
||||
implementation earlyDisplayLibs.slf4j.api
|
||||
implementation libs.jopt.simple
|
||||
}
|
||||
|
||||
tasks.named('test', Test).configure {
|
||||
useJUnitPlatform()
|
||||
// See gradle/gradle#35070 (https://github.com/gradle/gradle/issues/35070)
|
||||
// We are making the list of providers first BEFORE mapping them to a provider of the resolved objects so that they can be finalized after configuration.
|
||||
var lwjglTestLibs = [
|
||||
dependencies.variantOf(earlyDisplayTestLibs.lwjgl) { classifier lwjglNatives },
|
||||
dependencies.variantOf(earlyDisplayTestLibs.lwjgl.glfw) { classifier lwjglNatives },
|
||||
dependencies.variantOf(earlyDisplayTestLibs.lwjgl.opengl) { classifier lwjglNatives },
|
||||
dependencies.variantOf(earlyDisplayTestLibs.lwjgl.stb) { classifier lwjglNatives }
|
||||
].with { list ->
|
||||
provider { list.collect { it.get() } }
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.earlydisplay',
|
||||
'Forge-Module-Layer': 'boot'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'FML Early Display',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FML Early Display',
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': '1.0'
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/earlydisplay/')
|
||||
testing.suites.named('test', JvmTestSuite) {
|
||||
useJUnitJupiter('5.8.2')
|
||||
|
||||
dependencies {
|
||||
implementation earlyDisplayTestLibs.powermock.core
|
||||
runtimeOnly earlyDisplayLibs.slf4j.jdk14
|
||||
runtimeOnly.bundle lwjglTestLibs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,24 +76,42 @@ tasks.withType(JavaCompile).configureEach {
|
|||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.earlydisplay',
|
||||
'Forge-Module-Layer' : 'boot'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': '1.0'
|
||||
], 'net/minecraftforge/fml/earlydisplay/')
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'fmlearlydisplay'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'A pretty looking, but prone to erroring screen displayed during Forge loading.'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,14 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
return "fmlearlywindow";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmediateWindowProvider selectBackend(String backend) {
|
||||
// We only support opengl
|
||||
if ("default".equals(backend) || "opengl".equals(backend))
|
||||
return this;
|
||||
return ImmediateWindowProvider.getFallbackHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable initialize(String[] arguments) {
|
||||
String mcVersion = FMLLoader.versionInfo().mcVersion();
|
||||
|
|
@ -137,7 +145,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
this.colourScheme = ColourScheme.BLACK;
|
||||
} else {
|
||||
try {
|
||||
// check the options file for the colour scheme
|
||||
// check the options file for the color scheme
|
||||
var optionLines = Files.readAllLines(FMLPaths.GAMEDIR.get().resolve(Path.of("options.txt")));
|
||||
var keyName = "darkMojangStudiosBackground:";
|
||||
for (String line : optionLines) {
|
||||
|
|
@ -459,7 +467,9 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
this.winWidth = x[0];
|
||||
this.winHeight = y[0];
|
||||
|
||||
// Setting the window position isn't supported on wayland, so check the error here
|
||||
glfwSetWindowPos(window, (vidmode.width() - this.winWidth) / 2 + monitorX, (vidmode.height() - this.winHeight) / 2 + monitorY);
|
||||
handleLastGLFWError();
|
||||
|
||||
// Attempt setting the icon
|
||||
// int[] channels = new int[1];
|
||||
|
|
@ -482,7 +492,10 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
|
||||
// Show the window
|
||||
glfwShowWindow(window);
|
||||
// Getting the window position isn't supported on wayland, so check the error here
|
||||
glfwGetWindowPos(window, x, y);
|
||||
handleLastGLFWError();
|
||||
|
||||
this.winX = x[0];
|
||||
this.winY = y[0];
|
||||
glfwGetFramebufferSize(window, x, y);
|
||||
|
|
@ -491,6 +504,18 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
glfwPollEvents();
|
||||
}
|
||||
|
||||
private static void handleLastGLFWError() {
|
||||
handleLastGLFWError((error, description) -> {
|
||||
if (error == GLFW_FEATURE_UNAVAILABLE) {
|
||||
// suppress window pos errors for unsupported platforms (wayland)
|
||||
LOGGER.debug(String.format("Suppressing GLFW error: [0x%X]%s", error, description));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("GLFW error: [0x%X]%s", error, description));
|
||||
});
|
||||
}
|
||||
|
||||
private void winResize(long window, int width, int height) {
|
||||
if (window == this.window && width != 0 && height != 0) {
|
||||
this.winWidth = width;
|
||||
|
|
@ -648,4 +673,4 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
|||
this.context.elementShader().close();
|
||||
SimpleBufferBuilder.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public class RenderElement {
|
|||
}
|
||||
|
||||
public static RenderElement forgeVersionOverlay(SimpleFont font, String version) {
|
||||
return new RenderElement(RenderElement.initializeText(font, (bb, fnt, ctx)->
|
||||
return new RenderElement(RenderElement.initializeText(font, (bb, _, ctx)->
|
||||
font.generateVerticesForTexts(ctx.scaledWidth() - font.stringWidth(version) - 10,
|
||||
ctx.scaledHeight() - font.lineSpacing() + font.descent() - 10, bb,
|
||||
new SimpleFont.DisplayText(version, ctx.colourScheme.foreground().packedint(RenderElement.globalAlpha)))));
|
||||
|
|
@ -178,11 +178,11 @@ public class RenderElement {
|
|||
var colour = (alpha << 24) | 0xFFFFFF;
|
||||
Renderer bar;
|
||||
if (pm.steps() == 0) {
|
||||
bar = progressBar(ctx->new int[] {(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y + font.lineSpacing() - font.descent(), BAR_WIDTH * ctx.scale()}, f->colour, frame -> indeterminateBar(frame, cnt == 0));
|
||||
bar = progressBar(ctx->new int[] {(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y + font.lineSpacing() - font.descent(), BAR_WIDTH * ctx.scale()}, _->colour, frame -> indeterminateBar(frame, cnt == 0));
|
||||
} else {
|
||||
bar = progressBar(ctx -> new int[]{(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y + font.lineSpacing() - font.descent(), BAR_WIDTH * ctx.scale()}, f -> colour, f -> new float[]{0f, pm.progress()});
|
||||
bar = progressBar(ctx -> new int[]{(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y + font.lineSpacing() - font.descent(), BAR_WIDTH * ctx.scale()}, _ -> colour, _ -> new float[]{0f, pm.progress()});
|
||||
}
|
||||
Renderer label = (bb, ctx, frame) -> renderText(font, text((ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y, pm.label().getText(), colour), bb, ctx);
|
||||
Renderer label = (bb, ctx, _) -> renderText(font, text((ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y, pm.label().getText(), colour), bb, ctx);
|
||||
return bar.then(label);
|
||||
}
|
||||
private static float[] indeterminateBar(int frame, boolean isActive) {
|
||||
|
|
@ -198,9 +198,9 @@ public class RenderElement {
|
|||
var y = 10 * context.scale();
|
||||
PerformanceInfo pi = context.performance();
|
||||
final int colour = hsvToRGB((1.0f - (float)Math.pow(pi.memory(), 1.5f)) / 3f, 1.0f, 0.5f);
|
||||
var bar = progressBar(ctx -> new int[]{(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y, BAR_WIDTH * ctx.scale()}, f -> colour, f -> new float[]{0f, pi.memory()});
|
||||
var bar = progressBar(ctx -> new int[]{(ctx.scaledWidth() - BAR_WIDTH * ctx.scale()) / 2, y, BAR_WIDTH * ctx.scale()}, _ -> colour, _ -> new float[]{0f, pi.memory()});
|
||||
var width = font.stringWidth(pi.text());
|
||||
Renderer label = (bb, ctx, frame) -> renderText(font, text(ctx.scaledWidth() / 2 - width / 2, y + 18, pi.text(), context.colourScheme.foreground().packedint(globalAlpha)), bb, ctx);
|
||||
Renderer label = (bb, ctx, _) -> renderText(font, text(ctx.scaledWidth() / 2 - width / 2, y + 18, pi.text(), context.colourScheme.foreground().packedint(globalAlpha)), bb, ctx);
|
||||
bar.then(label).accept(buffer, context, frameNumber);
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ public class RenderElement {
|
|||
}
|
||||
|
||||
private static Renderer initializeText(SimpleFont font, TextGenerator textGenerator) {
|
||||
return (bb, context, frame) -> renderText(font, textGenerator, bb, context);
|
||||
return (bb, context, _) -> renderText(font, textGenerator, bb, context);
|
||||
}
|
||||
|
||||
private static void renderText(final SimpleFont font, final TextGenerator textGenerator, final SimpleBufferBuilder bb, final DisplayContext context) {
|
||||
|
|
@ -262,7 +262,7 @@ public class RenderElement {
|
|||
}
|
||||
|
||||
private static TextGenerator text(int x, int y, String text, int colour) {
|
||||
return (bb, font, context) -> font.generateVerticesForTexts(x, y, bb, new SimpleFont.DisplayText(text, colour));
|
||||
return (bb, font, _) -> font.generateVerticesForTexts(x, y, bb, new SimpleFont.DisplayText(text, colour));
|
||||
}
|
||||
|
||||
private static Renderer initializeTexture(final String textureFileName, int size, int textureNumber, TextureRenderer positionAndColour) {
|
||||
|
|
|
|||
|
|
@ -1,69 +1,75 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
import groovy.transform.CompileDynamic
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.PackageScope
|
||||
import net.minecraftforge.forgedev.legacy.tasks.JarJarMetadataOptions
|
||||
import org.gradle.api.plugins.jvm.JvmTestSuite
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'jvm-test-suite'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias(libs.plugins.apt)
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
alias libs.plugins.apt
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
|
||||
configurations.forEach{ it.transitive = false }
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
|
||||
api(libs.bundles.asm) // Needed by all the black magic
|
||||
api(libs.forgespi)
|
||||
api(libs.mergetool.api)
|
||||
api(libs.log4j.api)
|
||||
api(libs.slf4j.api)
|
||||
api(libs.guava)
|
||||
api(libs.gson)
|
||||
api(libs.maven.artifact)
|
||||
api(libs.apache.commons)
|
||||
api(libs.bundles.night.config)
|
||||
api(libs.modlauncher)
|
||||
api(libs.mojang.logging)
|
||||
api(libs.jarjar.selector)
|
||||
api(libs.jarjar.meta)
|
||||
|
||||
implementation(libs.jopt.simple)
|
||||
implementation(libs.securemodules)
|
||||
implementation(libs.accesstransformers)
|
||||
implementation(libs.terminalconsoleappender)
|
||||
implementation(libs.jimfs)
|
||||
implementation(libs.roimfs)
|
||||
|
||||
// Needed because we have a custom log4j plugin, and they removed package scanning and require a data file to be generated
|
||||
implementation(libs.log4j.core)
|
||||
annotationProcessor(libs.bundles.log4j)
|
||||
|
||||
testCompileOnly(libs.jetbrains.annotations)
|
||||
testRuntimeOnly(libs.bootstrap)
|
||||
}
|
||||
gradleutils.displayName = 'FMLLoader'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Modifications to Minecraft to enable mod developers.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.fmlloader',
|
||||
'Forge-Module-Layer': 'boot'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'FMLLoader',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FMLLoader',
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': FORGE_VERSION
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/loading/')
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
// TODO [FMLLoader] Figure out a better way to lock transitive dependencies to the explicit versions shipped by the isntaller
|
||||
api(libs.bundles.asm ){ transitive = false } // Needed by all the black magic
|
||||
api(libs.forgespi ){ transitive = false }
|
||||
api(libs.mergetool.api ){ transitive = false }
|
||||
api(libs.log4j.api ){ transitive = false }
|
||||
api(libs.slf4j.api ){ transitive = false }
|
||||
api(libs.guava ){ transitive = false }
|
||||
api(libs.gson ){ transitive = false }
|
||||
api(libs.maven.artifact ){ transitive = false }
|
||||
api(libs.apache.commons ){ transitive = false }
|
||||
api(libs.bundles.night.config){ transitive = false }
|
||||
api(libs.modlauncher ){ transitive = false }
|
||||
api(libs.mojang.logging ){ transitive = false }
|
||||
api(libs.jarjar.selector ){ transitive = false }
|
||||
api(libs.jarjar.meta ){ transitive = false }
|
||||
|
||||
implementation(libs.jopt.simple ){ transitive = false }
|
||||
implementation(libs.securemodules ){ transitive = false }
|
||||
implementation(libs.accesstransformers ){ transitive = false }
|
||||
implementation(libs.terminalconsoleappender){ transitive = false }
|
||||
implementation(libs.jimfs ){ transitive = false }
|
||||
implementation(libs.roimfs ){ transitive = false }
|
||||
|
||||
// Needed because we have a custom log4j plugin, and they removed package scanning and require a data file to be generated
|
||||
implementation(libs.log4j.core ){ transitive = false }
|
||||
annotationProcessor(libs.bundles.log4j){ transitive = false }
|
||||
}
|
||||
|
||||
testing.suites.named('test', JvmTestSuite) {
|
||||
dependencies {
|
||||
compileOnly libs.jetbrains.annotations
|
||||
runtimeOnly libs.bootstrap
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,39 +77,81 @@ tasks.withType(JavaCompile).configureEach {
|
|||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.fmlloader',
|
||||
'Forge-Module-Layer' : 'boot'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': forgeVersion
|
||||
], 'net/minecraftforge/fml/loading/')
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'fmlloader'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Modifactions to Minecraft to enable mod developers.'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('writeForgeVersionJson') {
|
||||
doLast {
|
||||
file('src/main/resources/forge_version.json').json = [
|
||||
forge: FORGE_VERSION,
|
||||
mc: MC_VERSION,
|
||||
mcp: MCP_VERSION
|
||||
]
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('jarJarOptionsJson', net.minecraftforge.forge.tasks.JarJarMetadataOptions) {
|
||||
// A simple task to write JSON to a file. Using Task#doLast to output files is no longer supported.
|
||||
// This code may seem verbose, but it's better this way. If more projects need this, we can move it to buildSrc.
|
||||
@CompileStatic
|
||||
@PackageScope abstract class WriteForgeVersionJson extends DefaultTask {
|
||||
abstract @Input Property<String> getForgeVersion()
|
||||
abstract @Input Property<String> getMinecraftVersion()
|
||||
abstract @Input Property<String> getMcpVersion()
|
||||
|
||||
abstract @OutputFile RegularFileProperty getOutputFile()
|
||||
|
||||
@Inject
|
||||
WriteForgeVersionJson() {}
|
||||
|
||||
@TaskAction
|
||||
@CompileDynamic
|
||||
void exec() {
|
||||
var json = new groovy.json.JsonBuilder()
|
||||
json {
|
||||
forge this.forgeVersion.get()
|
||||
mc this.minecraftVersion.get()
|
||||
mcp this.mcpVersion.get()
|
||||
}
|
||||
this.outputFile.asFile.get().text = json.toPrettyString()
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('writeForgeVersionJson', WriteForgeVersionJson) {
|
||||
forgeVersion = project.forgeVersion
|
||||
minecraftVersion = project.minecraftVersion
|
||||
mcpVersion = project.mcpVersion
|
||||
|
||||
outputFile = file('src/main/resources/forge_version.json')
|
||||
}
|
||||
|
||||
tasks.register('jarJarOptionsJson', JarJarMetadataOptions) {
|
||||
metadataFile = project.file('src/main/resources/jarjar_options.json')
|
||||
// This is resolved too early by cpw.mods.modlauncher.TransformationServicesHandler.discoverServices(DiscoveryData) But eventually...
|
||||
//add(libs.mixin, 'org/spongepowered/asm/mixin/Mixin.class')
|
||||
|
|
@ -118,29 +166,25 @@ tasks.register('jarJarOptionsJson', net.minecraftforge.forge.tasks.JarJarMetadat
|
|||
}
|
||||
}
|
||||
|
||||
tasks.named('generateResources').configure {
|
||||
dependsOn('eclipseJdt')
|
||||
dependsOn('eclipseJdtApt')
|
||||
dependsOn('eclipseFactorypath')
|
||||
dependsOn('writeForgeVersionJson')
|
||||
dependsOn('jarJarOptionsJson')
|
||||
tasks.named('generateResources') {
|
||||
dependsOn(
|
||||
tasks.named('eclipseJdt'),
|
||||
tasks.named('eclipseJdtApt'),
|
||||
tasks.named('eclipseFactorypath'),
|
||||
tasks.named('writeForgeVersionJson', WriteForgeVersionJson),
|
||||
tasks.named('jarJarOptionsJson')
|
||||
)
|
||||
}
|
||||
|
||||
tasks.named('sourcesJar') {
|
||||
dependsOn('jarJarOptionsJson')
|
||||
}
|
||||
|
||||
eclipse {
|
||||
classpath {
|
||||
// We need to set the default output directory for the log4j annotation processor
|
||||
// Ideally we'd just set the value, but the eclipse plugin deduplicates the output directories
|
||||
// So we have to do a hacky whenMerged
|
||||
//defaultOutputDir = file('bin/main')
|
||||
file.whenMerged {
|
||||
entries.each { entry ->
|
||||
if (entry.kind == 'output' && entry.hasProperty('path'))
|
||||
entry.path = 'bin/main'
|
||||
}
|
||||
}
|
||||
eclipse.classpath {
|
||||
// We need to set the default output directory for the log4j annotation processor
|
||||
// Ideally we'd just set the value, but the eclipse plugin deduplicates the output directories
|
||||
// So we have to do a hacky whenMerged
|
||||
//defaultOutputDir = file('bin/main')
|
||||
file.whenMerged {
|
||||
entries.each { entry ->
|
||||
if (entry.kind == 'output' && entry.hasProperty('path'))
|
||||
entry.path = 'bin/main'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public class FMLConfig
|
|||
}
|
||||
if (!configSpec.isCorrect(configData)) {
|
||||
LOGGER.warn(CORE, "Configuration file {} is not correct. Correcting", configFile);
|
||||
configSpec.correct(configData, (action, path, incorrectValue, correctedValue) ->
|
||||
configSpec.correct(configData, (_, path, incorrectValue, correctedValue) ->
|
||||
LOGGER.info(CORE, "Incorrect key {} was corrected from {} to {}", path, incorrectValue, correctedValue));
|
||||
}
|
||||
configData.putAllComments(configComments);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ public class FMLEnvironment
|
|||
public static final boolean secureJarsEnabled = FMLLoader.isSecureJarEnabled();
|
||||
|
||||
static void setupInteropEnvironment(IEnvironment environment) {
|
||||
environment.computePropertyIfAbsent(IEnvironment.Keys.NAMING.get(), v->naming);
|
||||
environment.computePropertyIfAbsent(Environment.Keys.DIST.get(), v->dist);
|
||||
environment.computePropertyIfAbsent(IEnvironment.Keys.NAMING.get(), _->naming);
|
||||
environment.computePropertyIfAbsent(Environment.Keys.DIST.get(), _->dist);
|
||||
}
|
||||
|
||||
public static class Keys {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import net.minecraftforge.forgespi.Environment;
|
|||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
|
@ -42,7 +41,7 @@ public class FMLServiceProvider implements ITransformationService {
|
|||
LOGGER.debug(CORE, "Loading configuration");
|
||||
FMLConfig.load();
|
||||
LOGGER.debug(CORE, "Preparing ModFile");
|
||||
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile::new);
|
||||
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), _->ModFile::new);
|
||||
LOGGER.debug(CORE, "Preparing launch handler");
|
||||
FMLLoader.setupLaunchHandler(environment, arguments);
|
||||
FMLEnvironment.setupInteropEnvironment(environment);
|
||||
|
|
|
|||
|
|
@ -10,8 +10,13 @@ import net.minecraftforge.fml.loading.progress.StartupNotificationManager;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import joptsimple.OptionParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
|
@ -41,16 +46,62 @@ public class ImmediateWindowHandler {
|
|||
if (provider == null) {
|
||||
LOGGER.info("Failed to find ImmediateWindowProvider {}, disabling", providername);
|
||||
provider = new DummyProvider();
|
||||
} else {
|
||||
var backend = findBackend(arguments);
|
||||
var newProvider = provider.selectBackend(backend);
|
||||
if (provider != newProvider) {
|
||||
if (newProvider == null)
|
||||
newProvider = new DummyProvider();
|
||||
|
||||
LOGGER.info("ImmediateWindowProvider {} does not support {}, switching to {}", provider.name(), backend, newProvider.name());
|
||||
provider = newProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only update config if the provider isn't the dummy provider
|
||||
if (!Objects.equals(provider.name(), "dummyprovider"))
|
||||
FMLConfig.updateConfig(FMLConfig.ConfigValue.EARLY_WINDOW_PROVIDER, provider.name());
|
||||
|
||||
FMLLoader.progressWindowTick = provider.initialize(arguments);
|
||||
earlyProgress = StartupNotificationManager.addProgressBar("EARLY", 0);
|
||||
earlyProgress.label("Bootstrapping Minecraft");
|
||||
}
|
||||
|
||||
private static String findBackend(String[] arguments) {
|
||||
// Try and parse from the command line arguments
|
||||
var parser = new OptionParser();
|
||||
var backendOption = parser.accepts("graphicsBackend").withRequiredArg();
|
||||
parser.allowsUnrecognizedOptions();
|
||||
var parsed = parser.parse(arguments);
|
||||
|
||||
if (parsed.has(backendOption))
|
||||
return parsed.valueOf(backendOption).toLowerCase(Locale.ENGLISH);
|
||||
|
||||
|
||||
// Read the options.txt if it exists.
|
||||
var optionsFile = FMLPaths.GAMEDIR.get().resolve(Path.of("options.txt"));
|
||||
if (!Files.exists(optionsFile)) // Default is OpenGL first
|
||||
return "default";
|
||||
|
||||
List<String> lines = null;
|
||||
try {
|
||||
lines = Files.readAllLines(optionsFile);
|
||||
} catch (IOException e) {
|
||||
return "default"; // We failed to read for some reason, assume we're using the default.
|
||||
}
|
||||
|
||||
final String key = "preferredGraphicsBackend:";
|
||||
for (var line : lines) {
|
||||
if (line.startsWith(key)) {
|
||||
var backend = line.substring(key.length() + 1, line.length() - 1);
|
||||
return backend.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
return "default";
|
||||
}
|
||||
|
||||
public static long setupMinecraftWindow(final int width, final int height, final String title, final long monitor, final Supplier<Object> backend) {
|
||||
return provider.setupMinecraftWindow(width, height, title, monitor, backend);
|
||||
}
|
||||
|
|
@ -83,7 +134,7 @@ public class ImmediateWindowHandler {
|
|||
earlyProgress.label(message);
|
||||
}
|
||||
|
||||
private record DummyProvider() implements ImmediateWindowProvider {
|
||||
record DummyProvider() implements ImmediateWindowProvider {
|
||||
private static Method NV_HANDOFF;
|
||||
private static Method NV_POSITION;
|
||||
private static Method NV_OVERLAY;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,36 @@ import java.util.function.Supplier;
|
|||
* No doubt many more things can be said here.
|
||||
*/
|
||||
public interface ImmediateWindowProvider {
|
||||
/**
|
||||
* Returns a new instance of ImmediateWindowProvider which just bounces to the vanilla code.
|
||||
* This can be useful when you want to disable your provider and defer to vanilla behavior for some reason.
|
||||
*/
|
||||
public static ImmediateWindowProvider getFallbackHandler() {
|
||||
return new ImmediateWindowHandler.DummyProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of this window provider. Do NOT use fmlearlywindow.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* This is called before initialize, but after reading the preferred graphics backend config value from the user's
|
||||
* options.txt or command line.
|
||||
*
|
||||
* If you do not support the requested backend, you can return a new ImmediateWindowProvider that does.
|
||||
* {@link #getFallbackHandler()} can be used to get an instance that falls back to Vanilla's code effectively
|
||||
* disabling the early loading screen.
|
||||
*
|
||||
* @param backend - The backend the user has selected, known values: "default", "opengl", and "vulkan". However this
|
||||
* is read from the config file, or command line arguments so could be anything.
|
||||
* Default and OpenGL are treated the same, attempting to load OpenGL first, then Vulkan.
|
||||
* Vulkan attempts to load Vulkan first then OpenGL
|
||||
*/
|
||||
default ImmediateWindowProvider selectBackend(String backend) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called very early on to initialize ourselves. Use this to initialize the window and other GL core resources.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package net.minecraftforge.fml.loading;
|
|||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.modlauncher.api.INameMappingService;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Convert a maven coordinate into a Path.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class StringUtils {
|
|||
return java.util.stream.Stream.of(endings).anyMatch(lowerSearch::endsWith);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static URL toURL(final String string) {
|
||||
if (string == null || string.trim().isEmpty() || string.contains("myurl.me") || string.contains("example.invalid"))
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import org.jetbrains.annotations.ApiStatus;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@ApiStatus.Internal // since 1.21.1, will be made non-public in a later MC version
|
||||
public class VersionSupportMatrix {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ package net.minecraftforge.fml.loading.moddiscovery;
|
|||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.ImmediateWindowHandler;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.ModFileScanData;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -56,7 +55,7 @@ public final class BackgroundScanHandler {
|
|||
ImmediateWindowHandler.updateProgress("Scanning mod candidates");
|
||||
CompletableFuture<ModFileScanData> future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner)
|
||||
.whenComplete(file::setScanResult);
|
||||
if (DEBUG) future = future.whenComplete((r, t) -> addCompletedFile(file, t));
|
||||
if (DEBUG) future = future.whenComplete((_, t) -> addCompletedFile(file, t));
|
||||
file.setFutureScanResult(future);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public enum InvalidModIdentifier {
|
|||
LITELOADER(filePresent("litemod.json")),
|
||||
OPTIFINE(filePresent("optifine/Installer.class")),
|
||||
BUKKIT(filePresent("plugin.yml")),
|
||||
INVALIDZIP((f,zf) -> zf.isEmpty()); // note: only this one INVALIDZIP check is ran until the todo on this class is fixed
|
||||
INVALIDZIP((_,zf) -> zf.isEmpty()); // note: only this one INVALIDZIP check is ran until the todo on this class is fixed
|
||||
|
||||
private final BiPredicate<Path, Optional<ZipFile>> ident;
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ public enum InvalidModIdentifier {
|
|||
|
||||
private static BiPredicate<Path, Optional<ZipFile>> filePresent(String filename)
|
||||
{
|
||||
return (f, zfo) -> zfo.map(zf -> zf.getEntry(filename) != null).orElse(false);
|
||||
return (_, zfo) -> zfo.map(zf -> zf.getEntry(filename) != null).orElse(false);
|
||||
}
|
||||
|
||||
private static <T> Optional<T> optionalFromException(Supplier_WithExceptions<T, ? extends Exception> supp)
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ public class JarInJarDependencyLocator extends AbstractModProvider implements ID
|
|||
var ids = new TreeMap<String, List<Entry>>();
|
||||
for (var entry : selector.entries.values()) {
|
||||
if (entry != FAILED && entry.coord != null)
|
||||
ids.computeIfAbsent(entry.coord, id -> new ArrayList<>()).add(entry);
|
||||
ids.computeIfAbsent(entry.coord, _ -> new ArrayList<>()).add(entry);
|
||||
}
|
||||
|
||||
for (var entry : ids.entrySet()) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public final class MinecraftLocator extends AbstractModProvider implements IModL
|
|||
|
||||
// Minecraft itself.
|
||||
var meta = new ModJarMetadata();
|
||||
var mcjar = SecureJar.from(jar -> meta, paths);
|
||||
var mcjar = SecureJar.from(_ -> meta, paths);
|
||||
var mc = ModFileFactory.FACTORY.build(mcjar, this, MinecraftLocator::buildMinecraftTOML);
|
||||
meta.setModFile(mc);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ package net.minecraftforge.fml.loading.moddiscovery;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LanguageLoadingProvider;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
|
|
@ -26,7 +25,6 @@ import java.nio.file.FileSystems;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import com.electronwill.nightconfig.core.io.ParsingException;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.ModFileFactory;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
|
@ -24,6 +26,7 @@ public class ModFileParser {
|
|||
return parser.build(modFile);
|
||||
}
|
||||
|
||||
// Note: Although @Nullable, several other places in FML assume ModFileInfo is not null. Keep this in mind
|
||||
public static @Nullable IModFileInfo modsTomlParser(final IModFile imodFile) {
|
||||
ModFile modFile = (ModFile) imodFile;
|
||||
LOGGER.debug(LogMarkers.LOADING,"Considering mod file candidate {}", modFile.getFilePath());
|
||||
|
|
@ -32,11 +35,19 @@ public class ModFileParser {
|
|||
LOGGER.warn(LogMarkers.LOADING, "Mod file {} is missing mods.toml file", modFile.getFilePath());
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final FileConfig fileConfig = FileConfig.builder(modsjson).build();
|
||||
fileConfig.load();
|
||||
fileConfig.close();
|
||||
final NightConfigWrapper configWrapper = new NightConfigWrapper(fileConfig);
|
||||
return new ModFileInfo(modFile, configWrapper, configWrapper::setFile);
|
||||
} catch (ParsingException e) { // Handle landmine toml errors, e.g. incorrectly ported mods.
|
||||
LOGGER.error("Mod candidate {} contains a corrupt or misconfigured toml.", modFile.getFileName());
|
||||
throw new ModFileLoadingException("Mod candidate " + modFile.getFileName() + " contains a corrupt or misconfigured toml.");
|
||||
} catch (Exception other) { // Otherwise this is just someone who (probably) forgot a comma or something.
|
||||
LOGGER.error("Mod candidate {}'s toml .", modFile.getFileName());
|
||||
throw new ModFileLoadingException("Mod candidate " + modFile.getFileName() + " contains broken toml, likely due to a typo.");
|
||||
}
|
||||
|
||||
final FileConfig fileConfig = FileConfig.builder(modsjson).build();
|
||||
fileConfig.load();
|
||||
fileConfig.close();
|
||||
final NightConfigWrapper configWrapper = new NightConfigWrapper(fileConfig);
|
||||
return new ModFileInfo(modFile, configWrapper, configWrapper::setFile);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class StartupNotificationManager {
|
|||
private synchronized static void addMessage(Message.MessageType type, String message, int maxSize)
|
||||
{
|
||||
EnumMap<Message.MessageType, List<Message>> newMessages = new EnumMap<>(messages);
|
||||
newMessages.compute(type, (key, existingList) -> {
|
||||
newMessages.compute(type, (_, existingList) -> {
|
||||
List<Message> newList = new ArrayList<>();
|
||||
if (existingList != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
|||
protected static Path getForgeOnly(Path forge) {
|
||||
var packages = getPackages(); // Pulled out so it is passed to the lambda as value
|
||||
// We need to separate out our resources/code so that we can show up as a different data pack.
|
||||
var modJar = SecureJar.from((path, base) -> {
|
||||
var modJar = SecureJar.from((path, _) -> {
|
||||
if (!path.endsWith(".class")) return true;
|
||||
for (var pkg : packages)
|
||||
if (path.startsWith(pkg)) return true;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
|
|||
|
||||
// We want just the class files from the root of the input paths. So make a new union with a filter.
|
||||
var classes = UnionHelper.newFileSystem(
|
||||
(name, base) -> {
|
||||
(name, _) -> {
|
||||
if (name.endsWith("/")) {
|
||||
if (name.startsWith("/"))
|
||||
name = name.substring(1);
|
||||
|
|
@ -164,7 +164,7 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
|
|||
if ("value".equals(key)) {
|
||||
int idx = clsName.lastIndexOf('/');
|
||||
var pkg = clsName.substring(0, idx);
|
||||
mods.computeIfAbsent(pkg, k -> new HashSet<>()).add((String)value);
|
||||
mods.computeIfAbsent(pkg, _ -> new HashSet<>()).add((String)value);
|
||||
|
||||
idx = pkg.lastIndexOf('/');
|
||||
while (idx != -1) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ sealed abstract class ForgeProdLaunchHandler extends CommonLaunchHandler {
|
|||
|
||||
@Override
|
||||
public List<Path> getMinecraftPaths() {
|
||||
return List.of(getPathFromResource("net/minecraft/client/Minecraft.class"));
|
||||
// We use a marker because 3rd party launcher don't build their class paths correctly
|
||||
// https://github.com/MinecraftForge/MinecraftForge/issues/10797
|
||||
return List.of(getPathFromResource(".forge_patched_minecraft"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
"artifact": "MixinExtras"
|
||||
},
|
||||
"version": {
|
||||
"range": "[0.5.3,)",
|
||||
"artifactVersion": "0.5.3"
|
||||
"range": "[0.5.4,)",
|
||||
"artifactVersion": "0.5.4"
|
||||
},
|
||||
"path": "",
|
||||
"isObfuscated": false
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"artifact": "mixinextras-forge"
|
||||
},
|
||||
"version": {
|
||||
"artifactVersion": "0.5.3"
|
||||
"artifactVersion": "0.5.4"
|
||||
},
|
||||
"path": "",
|
||||
"isObfuscated": false
|
||||
|
|
|
|||
|
|
@ -1,73 +1,78 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias(libs.plugins.apt)
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
|
||||
configurations.forEach{ it.transitive = false }
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
|
||||
implementation(libs.bundles.asm) // Needed by all the black magic
|
||||
implementation(libs.log4j.api)
|
||||
implementation(libs.gson)
|
||||
implementation(libs.modlauncher)
|
||||
implementation(libs.coremods.api)
|
||||
|
||||
testCompileOnly(libs.jetbrains.annotations)
|
||||
}
|
||||
gradleutils.displayName = 'Forge Transformers'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Forge-specific transformers unrelated to the FML project.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.forge.transformers',
|
||||
'Forge-Module-Layer': 'boot'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'Forge Transformers',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'Forge Transformers',
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': FORGE_VERSION
|
||||
] as LinkedHashMap, 'net/minecraftforge/forge/transformers/')
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
from components.java
|
||||
artifactId = 'forge-transformers'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Forge-specific transformers unrelated to the FML project.'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
|
||||
implementation(libs.bundles.asm ){ transitive = false } // Needed by all the black magic
|
||||
implementation(libs.log4j.api ){ transitive = false }
|
||||
implementation(libs.gson ){ transitive = false }
|
||||
implementation(libs.modlauncher ){ transitive = false }
|
||||
implementation(libs.coremods.api){ transitive = false }
|
||||
|
||||
testCompileOnly(libs.jetbrains.annotations)
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.forge.transformers',
|
||||
'Forge-Module-Layer' : 'boot'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': forgeVersion
|
||||
], 'net/minecraftforge/forge/transformers/')
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom { pom ->
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ record FieldToMethodTransformer(String className, Map<String, String> fields) im
|
|||
throw new IllegalStateException("No field with name " + fieldName + " found");
|
||||
|
||||
if (!Modifier.isPrivate(foundField.access) || Modifier.isStatic(foundField.access))
|
||||
throw new IllegalStateException("Field " + fieldName + " is not private and an instance field");
|
||||
throw new IllegalStateException("Field " + classNode.name + '.' + fieldName + " is not private and an instance field");
|
||||
|
||||
var methodSignature = "()" + foundField.desc;
|
||||
var foundMethod = findMethod(classNode, methodName, methodSignature);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ record MethodRedirector() implements ITransformer<ClassNode> {
|
|||
"finalizeSpawn",
|
||||
"(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;",
|
||||
GSON.fromJson(new InputStreamReader(sneak(() -> MethodRedirector.class.getModule().getResourceAsStream("coremods/finalize_spawn_targets.json"))), Target[].class),
|
||||
insn -> new MethodInsnNode(
|
||||
_ -> new MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
"net/minecraftforge/event/ForgeEventFactory",
|
||||
"onFinalizeSpawn",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
[
|
||||
{
|
||||
"class": "net/minecraft/gametest/framework/GameTestHelper",
|
||||
"class": "net/minecraft/gametest/framework/GameTestEntityBuilder",
|
||||
"methods": [
|
||||
"spawn(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/entity/EntitySpawnReason;)Lnet/minecraft/world/entity/Entity;"
|
||||
"spawn()Lnet/minecraft/world/entity/Entity;"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
{
|
||||
"class": "net/minecraft/world/entity/EntityType",
|
||||
"methods": [
|
||||
"create(Lnet/minecraft/server/level/ServerLevel;Ljava/util/function/Consumer;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntitySpawnReason;ZZ)Lnet/minecraft/world/entity/Entity;"
|
||||
"create(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/PostSpawnProcessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntitySpawnReason;ZZ)Lnet/minecraft/world/entity/Entity;"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -42,12 +42,6 @@
|
|||
"finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/animal/frog/Tadpole",
|
||||
"methods": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/monster/Strider",
|
||||
"methods": [
|
||||
|
|
@ -85,24 +79,12 @@
|
|||
"finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/monster/zombie/ZombieVillager",
|
||||
"methods": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/npc/CatSpawner",
|
||||
"methods": [
|
||||
"spawnCat(Lnet/minecraft/core/BlockPos;Lnet/minecraft/server/level/ServerLevel;Z)V"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/npc/villager/Villager",
|
||||
"methods": [
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/entity/raid/Raid",
|
||||
"methods": [
|
||||
|
|
@ -158,11 +140,5 @@
|
|||
"methods": [
|
||||
"handleDataMarker(Ljava/lang/String;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/util/RandomSource;Lnet/minecraft/world/level/levelgen/structure/BoundingBox;)V"
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate",
|
||||
"methods": [
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -1,17 +1,29 @@
|
|||
# TODO Re-evaluate
|
||||
# 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.
|
||||
org.gradle.jvmargs=-Xmx6G
|
||||
org.gradle.daemon=false
|
||||
|
||||
org.gradle.warning.mode=all
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
JAVA_VERSION=25
|
||||
MC_VERSION=26.1
|
||||
MC_NEXT_VERSION=26.2
|
||||
MCP_VERSION=20260324.123823
|
||||
MAPPING_CHANNEL=official
|
||||
MAPPING_VERSION=26.1
|
||||
# TODO [ForgeDev] Enable this once ForgeDev 7 tasks are fully migrated
|
||||
org.gradle.configuration-cache=false
|
||||
org.gradle.configuration-cache.parallel=false
|
||||
#org.gradle.configuration-cache.problems=warn
|
||||
#org.gradle.configuration-cache.integrity-check=true
|
||||
|
||||
# Set to true before the first build of a new MC version, so we don't do compatibility checks
|
||||
CHECK_COMPATIBILITY=false
|
||||
# Set to true to allow for fuzzy patching. Useful during updateing
|
||||
UPDATING=false
|
||||
net.minecraftforge.gradleutils.ide.automatic.sources=true
|
||||
net.minecraftforge.gradleutils.compilation.defaults=true
|
||||
|
||||
net.minecraftforge.gradle.merge-source-sets=true
|
||||
|
||||
# Controls if the compatibility checks are auto-added to the 'check' task.
|
||||
# The check tasks are still created and can be run, they just are not grouped with the normal 'check' task.
|
||||
# Set to false for the first builds of a new Minecraft version.
|
||||
net.minecraftforge.forge.build.check.compatibility=false
|
||||
# Set to true to allow for fuzzy patching. Useful during updating.
|
||||
net.minecraftforge.forge.build.updating=false
|
||||
# Set to true to enable the 'validatePublish' task which is currently a work in progress
|
||||
net.minecraftforge.forgedev.validate.publish=false
|
||||
|
|
|
|||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
15
gradlew
vendored
15
gradlew
vendored
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
|
|
@ -55,7 +57,7 @@
|
|||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
|
@ -84,7 +86,7 @@ done
|
|||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
@ -112,7 +114,6 @@ case "$( uname )" in #(
|
|||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
|
|
@ -170,7 +171,6 @@ fi
|
|||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
|
|
@ -203,15 +203,14 @@ fi
|
|||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
|
|
|||
5
gradlew.bat
vendored
5
gradlew.bat
vendored
|
|
@ -13,6 +13,8 @@
|
|||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
|
|
@ -68,11 +70,10 @@ goto fail
|
|||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
|
|
|||
|
|
@ -1,66 +1,79 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
implementation(libs.unsafe)
|
||||
implementation(libs.securemodules)
|
||||
}
|
||||
gradleutils.displayName = 'JavaFMLMod'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Language provider for Minecraft Forge that provides basic Java mod functionality.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.javafmlmod',
|
||||
'FMLModType': 'LANGPROVIDER'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'JavaFMLMod',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'JavaFMLMod',
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': FORGE_VERSION
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/javafmlmod/')
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'javafmllanguage'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Language provider for Minecraft Forge that provides basic java mod functionality'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
implementation projects.fmlloader
|
||||
implementation projects.fmlcore
|
||||
implementation libs.unsafe
|
||||
implementation libs.securemodules
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.javafmlmod',
|
||||
'FMLModType' : 'LANGPROVIDER'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': forgeVersion
|
||||
], 'net/minecraftforge/fml/javafmlmod/')
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
.filter(ad -> ad.annotationType().equals(MODANNOTATION))
|
||||
.peek(ad -> LOGGER.debug(SCAN, "Found @Mod class {} with id {}", ad.clazz().getClassName(), ad.annotationData().get("value")))
|
||||
.map(ad -> new FMLModTarget(ad.clazz().getClassName(), (String)ad.annotationData().get("value")))
|
||||
.collect(Collectors.toMap(FMLModTarget::modId, Function.identity(), (a,b)->a));
|
||||
.collect(Collectors.toMap(FMLModTarget::modId, Function.identity(), (a, _) -> a));
|
||||
scanResult.addLanguageLoader(modTargetMap);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +1,77 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
gradleutils.displayName = 'LowCodeMod'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Language provider for Minecraft Forge that loads mods without a Java entrypoint.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.lowcodemod',
|
||||
'FMLModType': 'LANGPROVIDER'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'LowCodeMod',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1.0',
|
||||
'Implementation-Title': project.name,
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': FORGE_VERSION.split('\\.')[0]
|
||||
] as java.util.LinkedHashMap, 'net/minecraftforge/fml/lowcodemod/')
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'lowcodelanguage'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Language provider for Minecraft Forge that loads resource packs as mods'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
implementation projects.fmlloader
|
||||
implementation projects.fmlcore
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.lowcodemod',
|
||||
'FMLModType' : 'LANGPROVIDER'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1.0',
|
||||
'Implementation-Title' : project.name,
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': forgeVersion.split('\\.')[0]
|
||||
], 'net/minecraftforge/fml/lowcodemod/')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class LowCodeModLanguageProvider implements IModLanguageProvider
|
|||
.flatMap(fi->fi.getMods().stream())
|
||||
.map(IModInfo::getModId)
|
||||
.map(LowCodeModTarget::new)
|
||||
.collect(Collectors.toMap(LowCodeModTarget::modId, Function.identity(), (a, b)->a));
|
||||
.collect(Collectors.toMap(LowCodeModTarget::modId, Function.identity(), (a, _)->a));
|
||||
scanResult.addLanguageLoader(modTargetMap);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,64 +1,77 @@
|
|||
import net.minecraftforge.gradleutils.PomUtils
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias libs.plugins.licenser
|
||||
alias libs.plugins.gradleutils
|
||||
alias libs.plugins.gitversion
|
||||
alias libs.plugins.changelog
|
||||
id 'net.minecraftforge.forge.build.convention'
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.jetbrains.annotations)
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
}
|
||||
gradleutils.displayName = 'MCLanguage'
|
||||
final vendor = 'Forge Development LLC'
|
||||
description = 'Language provider for Minecraft Forge that provides Minecraft Itself.'
|
||||
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(javaVersion)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar).configure {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.mclanguageprovider',
|
||||
'FMLModType': 'LANGPROVIDER'
|
||||
] as LinkedHashMap)
|
||||
attributes([
|
||||
'Specification-Title': 'MCLanguage',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'MCLanguage',
|
||||
'Implementation-Vendor': 'Forge Development LLC',
|
||||
'Implementation-Version': '1.0'
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/mclanguageprovider/')
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
license {
|
||||
header = rootProject.file('LICENSE-header.txt')
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications.register('mavenJava', MavenPublication).configure {
|
||||
from components.java
|
||||
artifactId = 'mclanguage'
|
||||
pom {
|
||||
name = project.name
|
||||
description = 'Language provider for Minecraft Forge that provides Minecraft Itself'
|
||||
url = 'https://github.com/MinecraftForge/MinecraftForge'
|
||||
PomUtils.setGitHubDetails(pom, 'MinecraftForge')
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
changelog {
|
||||
from changelogBase
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly libs.jetbrains.annotations
|
||||
|
||||
implementation projects.fmlloader
|
||||
implementation projects.fmlcore
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.compilerArgs << '-Xlint:unchecked'
|
||||
}
|
||||
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Automatic-Module-Name': 'net.minecraftforge.mclanguageprovider',
|
||||
'FMLModType' : 'LANGPROVIDER'
|
||||
])
|
||||
attributes([
|
||||
'Specification-Title' : gradleutils.displayName.get(),
|
||||
'Specification-Vendor' : vendor,
|
||||
'Specification-Version' : '1',
|
||||
'Implementation-Title' : gradleutils.displayName.get(),
|
||||
'Implementation-Vendor' : vendor,
|
||||
'Implementation-Version': '1.0'
|
||||
], 'net/minecraftforge/fml/mclanguageprovider/')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
changelog.publish(it)
|
||||
gradleutils.promote(it)
|
||||
|
||||
from components.java
|
||||
|
||||
pom {
|
||||
description = project.description
|
||||
|
||||
gradleutils.pom.addRemoteDetails(pom)
|
||||
|
||||
licenses {
|
||||
license gradleutils.pom.licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ plugins {
|
|||
id 'java'
|
||||
id 'idea'
|
||||
id 'eclipse'
|
||||
id 'net.minecraftforge.gradle' version '[7.0.3,8)'
|
||||
id 'net.minecraftforge.gradle' version '[7.0.17,8)'
|
||||
}
|
||||
|
||||
version = '1.0.0'
|
||||
|
|
@ -19,8 +19,6 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(25)
|
|||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
||||
minecraft {
|
||||
mappings channel: 'official', version: '@MC_VERSION@'
|
||||
|
||||
runs {
|
||||
configureEach {
|
||||
workingDir = layout.projectDirectory.dir('run')
|
||||
|
|
|
|||
6
minecraft.versions.toml
Normal file
6
minecraft.versions.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[versions]
|
||||
java = "25"
|
||||
minecraft = "26.2"
|
||||
minecraft-next = "26.3"
|
||||
mcp = "20260616.103818"
|
||||
changelog-base = "65.0"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
--- a/com/mojang/blaze3d/opengl/GlCommandEncoder.java
|
||||
+++ b/com/mojang/blaze3d/opengl/GlCommandEncoder.java
|
||||
@@ -111,6 +_,9 @@
|
||||
@@ -201,6 +_,9 @@
|
||||
GlStateManager._colorMask(15);
|
||||
GlStateManager._clear(16384);
|
||||
GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, 0, 0);
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
--- a/com/mojang/blaze3d/opengl/GlConst.java
|
||||
+++ b/com/mojang/blaze3d/opengl/GlConst.java
|
||||
@@ -249,6 +_,10 @@
|
||||
@@ -239,6 +_,10 @@
|
||||
}
|
||||
|
||||
public static int toGlInternalId(final TextureFormat textureFormat) {
|
||||
+ return toGlInternalId(textureFormat, false);
|
||||
public static int toGlInternalId(final GpuFormat gpuFormat) {
|
||||
+ return toGlInternalId(gpuFormat, false);
|
||||
+ }
|
||||
+ public static int toGlInternalId(final TextureFormat textureFormat, final boolean stencil) {
|
||||
+ if (stencil && textureFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_DEPTH32F_STENCIL8;
|
||||
return switch (textureFormat) {
|
||||
case RGBA8 -> 32856;
|
||||
case RED8 -> 33321;
|
||||
@@ -258,6 +_,10 @@
|
||||
+ public static int toGlInternalId(final GpuFormat gpuFormat, final boolean stencil) {
|
||||
+ if (stencil && gpuFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_DEPTH32F_STENCIL8;
|
||||
return switch (gpuFormat) {
|
||||
case R8_UNORM -> 33321;
|
||||
case R8_SNORM -> 36756;
|
||||
@@ -291,6 +_,10 @@
|
||||
}
|
||||
|
||||
public static int toGlExternalId(final TextureFormat textureFormat) {
|
||||
+ return toGlExternalId(textureFormat, false);
|
||||
public static int toGlExternalId(final GpuFormat gpuFormat) {
|
||||
+ return toGlExternalId(gpuFormat, false);
|
||||
+ }
|
||||
+ public static int toGlExternalId(final TextureFormat textureFormat, final boolean stencil) {
|
||||
+ if (stencil && textureFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL;
|
||||
return switch (textureFormat) {
|
||||
case RGBA8 -> 6408;
|
||||
case RED8 -> 6403;
|
||||
@@ -267,6 +_,10 @@
|
||||
+ public static int toGlExternalId(final GpuFormat gpuFormat, final boolean stencil) {
|
||||
+ if (stencil && gpuFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL;
|
||||
return switch (gpuFormat) {
|
||||
case R8_UNORM, R8_SNORM, R16_UNORM, R16_SNORM, R16_FLOAT, R32_FLOAT -> 6403;
|
||||
case RG8_UNORM, RG8_SNORM, RG16_UNORM, RG16_SNORM, RG16_FLOAT, RG32_FLOAT -> 33319;
|
||||
@@ -308,6 +_,10 @@
|
||||
}
|
||||
|
||||
public static int toGlType(final TextureFormat textureFormat) {
|
||||
+ return toGlType(textureFormat, false);
|
||||
public static int toGlType(final GpuFormat gpuFormat) {
|
||||
+ return toGlType(gpuFormat, false);
|
||||
+ }
|
||||
+ public static int toGlType(final TextureFormat textureFormat, boolean stencil) {
|
||||
+ if (stencil && textureFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
return switch (textureFormat) {
|
||||
case RGBA8 -> 5121;
|
||||
case RED8 -> 5121;
|
||||
+ public static int toGlType(final GpuFormat gpuFormat, boolean stencil) {
|
||||
+ if (stencil && gpuFormat.hasDepthAspect()) return org.lwjgl.opengl.GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
return switch (gpuFormat) {
|
||||
case R8_UNORM, RG8_UNORM, RGB8_UNORM, RGBA8_UNORM, R8_UINT, RG8_UINT, RGBA8_UINT, S8_UINT, RGB8_UINT -> 5121;
|
||||
case R8_SNORM, RG8_SNORM, RGB8_SNORM, RGBA8_SNORM, R8_SINT, RG8_SINT, RGBA8_SINT, RGB8_SINT -> 5120;
|
||||
|
|
|
|||
|
|
@ -15,30 +15,30 @@
|
|||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final int CIRCULAR_LOG_SIZE = 10;
|
||||
private final Queue<GlDebug.LogEntry> MESSAGE_BUFFER = EvictingQueue.create(10);
|
||||
@@ -103,6 +_,8 @@
|
||||
@@ -83,6 +_,8 @@
|
||||
}
|
||||
|
||||
LOGGER.info("OpenGL debug message: {}", gldebug$logentry);
|
||||
LOGGER.info("OpenGL debug message: {}", entry);
|
||||
+ // TODO: [VEN] Trim the stack trace
|
||||
+ if (PRINT_STACKTRACE_ON_ERROR) LOGGER.info("Trace: ", new Throwable("GlDebug"));
|
||||
}
|
||||
|
||||
public List<String> getLastOpenGlDebugMessages() {
|
||||
@@ -126,7 +_,7 @@
|
||||
GlDebug gldebug1 = new GlDebug();
|
||||
enabledExtensions.add("GL_KHR_debug");
|
||||
GL11.glEnable(37600);
|
||||
- if (debugSynchronousGlLogs) {
|
||||
+ if (debugSynchronousGlLogs | PRINT_STACKTRACE_ON_ERROR) {
|
||||
GL11.glEnable(33346);
|
||||
}
|
||||
@@ -107,7 +_,7 @@
|
||||
GlDebug debug = new GlDebug();
|
||||
enabledExtensions.add("GL_KHR_debug");
|
||||
GL33C.glEnable(37600);
|
||||
- if (debugSynchronousGlLogs) {
|
||||
+ if (debugSynchronousGlLogs | PRINT_STACKTRACE_ON_ERROR) {
|
||||
GL33C.glEnable(33346);
|
||||
}
|
||||
|
||||
@@ -140,7 +_,7 @@
|
||||
} else if (glcapabilities.GL_ARB_debug_output && GlDevice.USE_GL_ARB_debug_output) {
|
||||
GlDebug gldebug = new GlDebug();
|
||||
enabledExtensions.add("GL_ARB_debug_output");
|
||||
- if (debugSynchronousGlLogs) {
|
||||
+ if (debugSynchronousGlLogs | PRINT_STACKTRACE_ON_ERROR) {
|
||||
GL11.glEnable(33346);
|
||||
}
|
||||
@@ -121,7 +_,7 @@
|
||||
} else if (caps.GL_ARB_debug_output && GlDevice.USE_GL_ARB_debug_output) {
|
||||
GlDebug debug = new GlDebug();
|
||||
enabledExtensions.add("GL_ARB_debug_output");
|
||||
- if (debugSynchronousGlLogs) {
|
||||
+ if (debugSynchronousGlLogs | PRINT_STACKTRACE_ON_ERROR) {
|
||||
GL33C.glEnable(33346);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
--- a/com/mojang/blaze3d/opengl/GlDevice.java
|
||||
+++ b/com/mojang/blaze3d/opengl/GlDevice.java
|
||||
@@ -129,7 +_,12 @@
|
||||
@@ -150,7 +_,12 @@
|
||||
final int depthOrLayers,
|
||||
final int mipLevels
|
||||
) {
|
||||
|
|
@ -9,12 +9,12 @@
|
|||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GpuTexture createTexture(final @Nullable Supplier<String> label, @GpuTexture.Usage final int usage, final TextureFormat format, final int width, final int height, final int depthOrLayers, final int mipLevels, final boolean stencil ) {
|
||||
+ public GpuTexture createTexture(final @Nullable Supplier<String> label, @GpuTexture.Usage final int usage, final GpuFormat format, final int width, final int height, final int depthOrLayers, final int mipLevels, final boolean stencil) {
|
||||
+ return this.createTexture(this.debugLabels.exists() && label != null ? label.get() : null, usage, format, width, height, depthOrLayers, mipLevels, stencil);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,6 +_,11 @@
|
||||
@@ -163,6 +_,11 @@
|
||||
final int depthOrLayers,
|
||||
final int mipLevels
|
||||
) {
|
||||
|
|
@ -22,33 +22,29 @@
|
|||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GpuTexture createTexture(@Nullable String label, @GpuTexture.Usage final int usage, final TextureFormat format, final int width, final int height, final int depthOrLayers, final int mipLevels, boolean stencil) {
|
||||
+ public GpuTexture createTexture(@Nullable String label, @GpuTexture.Usage final int usage, final GpuFormat format, final int width, final int height, final int depthOrLayers, final int mipLevels, boolean stencil) {
|
||||
GlStateManager.clearGlErrors();
|
||||
int i = GlStateManager._genTexture();
|
||||
int id = GlStateManager._genTexture();
|
||||
if (label == null) {
|
||||
@@ -169,14 +_,14 @@
|
||||
for (int k : GlConst.CUBEMAP_TARGETS) {
|
||||
for (int l = 0; l < mipLevels; l++) {
|
||||
GlStateManager._texImage2D(
|
||||
- k, l, GlConst.toGlInternalId(format), width >> l, height >> l, 0, GlConst.toGlExternalId(format), GlConst.toGlType(format), null
|
||||
+ k, l, GlConst.toGlInternalId(format, stencil), width >> l, height >> l, 0, GlConst.toGlExternalId(format, stencil), GlConst.toGlType(format, stencil), null
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i1 = 0; i1 < mipLevels; i1++) {
|
||||
GlStateManager._texImage2D(
|
||||
- j, i1, GlConst.toGlInternalId(format), width >> i1, height >> i1, 0, GlConst.toGlExternalId(format), GlConst.toGlType(format), null
|
||||
+ j, i1, GlConst.toGlInternalId(format, stencil), width >> i1, height >> i1, 0, GlConst.toGlExternalId(format, stencil), GlConst.toGlType(format, stencil), null
|
||||
);
|
||||
}
|
||||
@@ -186,9 +_,9 @@
|
||||
GlStateManager._texParameter(target, 34892, 0);
|
||||
}
|
||||
@@ -187,7 +_,7 @@
|
||||
} else if (j1 != 0) {
|
||||
throw new IllegalStateException("OpenGL error " + j1);
|
||||
|
||||
- int glInternalID = GlConst.toGlInternalId(format);
|
||||
- int glExternalID = GlConst.toGlExternalId(format);
|
||||
- int glType = GlConst.toGlType(format);
|
||||
+ int glInternalID = GlConst.toGlInternalId(format, stencil);
|
||||
+ int glExternalID = GlConst.toGlExternalId(format, stencil);
|
||||
+ int glType = GlConst.toGlType(format, stencil);
|
||||
if (glInternalID != 0 && glExternalID != 0 && glType != 0) {
|
||||
if (isCubemap) {
|
||||
for (int cubeTarget : GlConst.CUBEMAP_TARGETS) {
|
||||
@@ -211,7 +_,7 @@
|
||||
throw new IllegalStateException("OpenGL error " + error);
|
||||
}
|
||||
|
||||
- GlTexture texture = new GlTexture(usage, label, format, width, height, depthOrLayers, mipLevels, id, this.frameBufferCache);
|
||||
+ GlTexture texture = new GlTexture(usage, label, format, width, height, depthOrLayers, mipLevels, id, this.frameBufferCache, stencil);
|
||||
this.debugLabels.applyLabel(texture);
|
||||
return texture;
|
||||
} else {
|
||||
- GlTexture gltexture = new GlTexture(usage, label, format, width, height, depthOrLayers, mipLevels, i);
|
||||
+ GlTexture gltexture = new GlTexture(usage, label, format, width, height, depthOrLayers, mipLevels, i, stencil);
|
||||
this.debugLabels.applyLabel(gltexture);
|
||||
return gltexture;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
--- a/com/mojang/blaze3d/opengl/GlStateManager.java
|
||||
+++ b/com/mojang/blaze3d/opengl/GlStateManager.java
|
||||
@@ -86,6 +_,11 @@
|
||||
@@ -80,6 +_,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ public static boolean _isBlendEnabled() {
|
||||
+ public static boolean _isBlendEnabled(int index) {
|
||||
+ RenderSystem.assertOnRenderThread();
|
||||
+ return BLEND.mode.enabled;
|
||||
+ return BLEND[index].mode.enabled;
|
||||
+ }
|
||||
+
|
||||
public static void _disableBlend() {
|
||||
public static void _disableBlend(int index) {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
BLEND.mode.disable();
|
||||
@@ -380,9 +_,17 @@
|
||||
BLEND[index].mode.disable();
|
||||
@@ -390,9 +_,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22,8 +22,8 @@
|
|||
+
|
||||
public static void _texParameter(final int target, final int name, final int value) {
|
||||
RenderSystem.assertOnRenderThread();
|
||||
GL11.glTexParameteri(target, name, value);
|
||||
+ if (target == GL13.GL_TEXTURE1) {
|
||||
GL33C.glTexParameteri(target, name, value);
|
||||
+ if (target == GL33C.GL_TEXTURE1) {
|
||||
+ lastBrightnessX = name;
|
||||
+ lastBrightnessY = value;
|
||||
+ }
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
--- a/com/mojang/blaze3d/opengl/GlTexture.java
|
||||
+++ b/com/mojang/blaze3d/opengl/GlTexture.java
|
||||
@@ -28,8 +_,13 @@
|
||||
final int mipLevels,
|
||||
final int id
|
||||
@@ -27,9 +_,14 @@
|
||||
final int id,
|
||||
final FrameBufferCache frameBufferCache
|
||||
) {
|
||||
+ this(usage, label, format, width, height, depthOrLayers, mipLevels, id, false);
|
||||
+ this(usage, label, format, width, height, depthOrLayers, mipLevels, id, frameBufferCache, false);
|
||||
+ }
|
||||
+
|
||||
+ protected GlTexture(int usage, String label, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels, int id, boolean stencil) {
|
||||
+ protected GlTexture(@GpuTexture.Usage int usage, String label, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels, int id, FrameBufferCache frameBufferCache, boolean stencil) {
|
||||
super(usage, label, format, width, height, depthOrLayers, mipLevels);
|
||||
this.id = id;
|
||||
this.frameBufferCache = frameBufferCache;
|
||||
+ this.stencilEnabled = stencil;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,5 +_,12 @@
|
||||
@@ -84,5 +_,12 @@
|
||||
if (this.closed && this.views == 0) {
|
||||
this.destroyImmediately();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
--- a/com/mojang/blaze3d/pipeline/RenderTarget.java
|
||||
+++ b/com/mojang/blaze3d/pipeline/RenderTarget.java
|
||||
@@ -80,7 +_,7 @@
|
||||
@@ -83,7 +_,7 @@
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
if (this.useDepth) {
|
||||
- this.depthTexture = gpudevice.createTexture(() -> this.label + " / Depth", 15, TextureFormat.DEPTH32, width, height, 1, 1);
|
||||
+ this.depthTexture = gpudevice.createTexture(() -> this.label + " / Depth", 15, TextureFormat.DEPTH32, width, height, 1, 1, this.stencilEnabled);
|
||||
this.depthTextureView = gpudevice.createTextureView(this.depthTexture);
|
||||
- this.depthTexture = device.createTexture(() -> this.label + " / Depth", 15, GpuFormat.D32_FLOAT, width, height, 1, 1);
|
||||
+ this.depthTexture = device.createTexture(() -> this.label + " / Depth", 15, GpuFormat.D32_FLOAT, width, height, 1, 1, this.stencilEnabled);
|
||||
this.depthTextureView = device.createTextureView(this.depthTexture);
|
||||
}
|
||||
|
||||
@@ -124,5 +_,26 @@
|
||||
@@ -121,5 +_,26 @@
|
||||
|
||||
public @Nullable GpuTextureView getDepthTextureView() {
|
||||
return this.depthTextureView;
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
--- a/com/mojang/blaze3d/platform/Window.java
|
||||
+++ b/com/mojang/blaze3d/platform/Window.java
|
||||
@@ -97,8 +_,9 @@
|
||||
Monitor monitor = this.screenManager.getMonitor(GLFW.glfwGetPrimaryMonitor());
|
||||
@@ -101,8 +_,9 @@
|
||||
Monitor initialMonitor = monitorManager.getMonitor(GLFW.glfwGetPrimaryMonitor());
|
||||
this.windowedWidth = this.width = allowedWindowMinSize(displayData.width());
|
||||
this.windowedHeight = this.height = allowedWindowMinSize(displayData.height());
|
||||
- this.handle = this.createWindow(backend, this.width, this.height, title, this.fullscreen && monitor != null ? monitor.getMonitor() : 0L);
|
||||
+ this.handle = net.minecraftforge.fml.loading.ImmediateWindowHandler.setupMinecraftWindow(this.width, this.height, title, this.fullscreen && monitor != null ? monitor.getMonitor() : 0L, () -> backend);
|
||||
- this.handle = this.createWindow(backend, this.width, this.height, title, this.fullscreen && initialMonitor != null ? initialMonitor.monitor() : 0L);
|
||||
+ this.handle = net.minecraftforge.fml.loading.ImmediateWindowHandler.setupMinecraftWindow(this.width, this.height, title, this.fullscreen && initialMonitor != null ? initialMonitor.monitor() : 0L, () -> backend);
|
||||
this.backend = backend;
|
||||
+ if (!net.minecraftforge.fml.loading.ImmediateWindowHandler.positionWindow(Optional.ofNullable(monitor), w->this.width = this.windowedWidth = w, h->this.height = this.windowedHeight = h, x->this.x = this.windowedX = x, y->this.y = this.windowedY = y)) {
|
||||
if (monitor != null) {
|
||||
VideoMode videomode = monitor.getPreferredVidMode(this.fullscreen ? this.preferredFullscreenVideoMode : Optional.empty());
|
||||
this.windowedX = this.x = monitor.getX() + videomode.getWidth() / 2 - this.width / 2;
|
||||
@@ -110,6 +_,7 @@
|
||||
this.windowedX = this.x = aint1[0];
|
||||
this.windowedY = this.y = aint[0];
|
||||
+ if (!net.minecraftforge.fml.loading.ImmediateWindowHandler.positionWindow(Optional.ofNullable(initialMonitor), w->this.width = this.windowedWidth = w, h->this.height = this.windowedHeight = h, x->this.x = this.windowedX = x, y->this.y = this.windowedY = y)) {
|
||||
if (initialMonitor != null) {
|
||||
VideoMode mode = initialMonitor.getPreferredVidMode(this.fullscreen ? this.preferredFullscreenVideoMode : Optional.empty());
|
||||
this.windowedX = this.x = initialMonitor.x() + mode.getWidth() / 2 - this.width / 2;
|
||||
@@ -114,6 +_,7 @@
|
||||
this.windowedX = this.x = actualX[0];
|
||||
this.windowedY = this.y = actualY[0];
|
||||
}
|
||||
+ }
|
||||
|
||||
this.setMode();
|
||||
this.refreshFramebufferSize();
|
||||
@@ -300,6 +_,9 @@
|
||||
GLFW.glfwGetFramebufferSize(this.handle, aint, aint1);
|
||||
this.framebufferWidth = aint[0] > 0 ? aint[0] : 1;
|
||||
this.framebufferHeight = aint1[0] > 0 ? aint1[0] : 1;
|
||||
@@ -306,6 +_,9 @@
|
||||
outHeight[0] = this.isSoftScreen() ? outHeight[0] - 1 : outHeight[0];
|
||||
this.framebufferWidth = outWidth[0] > 0 ? outWidth[0] : 1;
|
||||
this.framebufferHeight = outHeight[0] > 0 ? outHeight[0] : 1;
|
||||
+ if (this.framebufferHeight == 0 || this.framebufferWidth == 0) {
|
||||
+ net.minecraftforge.fml.loading.ImmediateWindowHandler.updateFBSize(w -> this.framebufferWidth = w, h -> this.framebufferHeight = h);
|
||||
+ }
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
--- a/com/mojang/blaze3d/systems/GpuDevice.java
|
||||
+++ b/com/mojang/blaze3d/systems/GpuDevice.java
|
||||
@@ -61,6 +_,21 @@
|
||||
@@ -73,6 +_,21 @@
|
||||
return this.backend.createTexture(label, usage, format, width, height, depthOrLayers, mipLevels);
|
||||
}
|
||||
|
||||
+ /** Forge: same as {@link #createTexture(Supplier, int, TextureFormat, int, int, int)} but with stencil support */
|
||||
+ /** Forge: same as {@link #createTexture(Supplier, int, GpuFormat, int, int, int)} but with stencil support */
|
||||
+ public GpuTexture createTexture(
|
||||
+ final @Nullable Supplier<String> label,
|
||||
+ @GpuTexture.Usage final int usage,
|
||||
+ final TextureFormat format,
|
||||
+ final GpuFormat format,
|
||||
+ final int width,
|
||||
+ final int height,
|
||||
+ final int depthOrLayers,
|
||||
|
|
@ -21,18 +21,18 @@
|
|||
+
|
||||
public GpuTexture createTexture(
|
||||
final @Nullable String label,
|
||||
@GpuTexture.Usage final int usage,
|
||||
@@ -72,6 +_,21 @@
|
||||
final @GpuTexture.Usage int usage,
|
||||
@@ -84,6 +_,21 @@
|
||||
) {
|
||||
this.verifyTextureCreationArgs(usage, width, height, depthOrLayers, mipLevels);
|
||||
return this.backend.createTexture(label, usage, format, width, height, depthOrLayers, mipLevels);
|
||||
+ }
|
||||
+
|
||||
+ /** Forge: same as {@link #createTexture(Supplier, int, TextureFormat, int, int, int)} but with stencil support */
|
||||
+ /** Forge: same as {@link #createTexture(Supplier, int, GpuFormat, int, int, int)} but with stencil support */
|
||||
+ public GpuTexture createTexture(
|
||||
+ final @Nullable String label,
|
||||
+ @GpuTexture.Usage final int usage,
|
||||
+ final TextureFormat format,
|
||||
+ final GpuFormat format,
|
||||
+ final int width,
|
||||
+ final int height,
|
||||
+ final int depthOrLayers,
|
||||
|
|
@ -43,4 +43,4 @@
|
|||
+ return this.backend.createTexture(label, usage, format, width, height, depthOrLayers, mipLevels, stencil);
|
||||
}
|
||||
|
||||
private void verifyTextureCreationArgs(@GpuTexture.Usage final int usage, final int width, final int height, final int depthOrLayers, final int mipLevels) {
|
||||
private void verifyTextureCreationArgs(final @GpuTexture.Usage int usage, final int width, final int height, final int depthOrLayers, final int mipLevels) {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
--- a/com/mojang/blaze3d/systems/GpuDeviceBackend.java
|
||||
+++ b/com/mojang/blaze3d/systems/GpuDeviceBackend.java
|
||||
@@ -30,9 +_,19 @@
|
||||
@Nullable Supplier<String> label, @GpuTexture.Usage final int usage, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels
|
||||
@@ -32,7 +_,17 @@
|
||||
@Nullable Supplier<String> label, @GpuTexture.Usage int usage, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels
|
||||
);
|
||||
|
||||
+ /** Forge: same as {@link #createTexture(Supplier<String>, int, TextureFormat, int, int, int)} but with stencil support */
|
||||
+ default GpuTexture createTexture(@Nullable Supplier<String> label, @GpuTexture.Usage final int usage, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels, boolean stencil) {
|
||||
+ /** Forge: same as {@link #createTexture(Supplier<String>, int, GpuFormat, int, int, int)} but with stencil support */
|
||||
+ default GpuTexture createTexture(@Nullable Supplier<String> label, @GpuTexture.Usage final int usage, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels, boolean stencil) {
|
||||
+ return createTexture(label, usage, format, width, height, depthOrLayers, mipLevels);
|
||||
+ }
|
||||
+
|
||||
GpuTexture createTexture(
|
||||
@Nullable String label, @GpuTexture.Usage final int usage, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels
|
||||
);
|
||||
GpuTexture createTexture(@Nullable String label, @GpuTexture.Usage int usage, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels);
|
||||
+
|
||||
+ /** Forge: same as {@link #createTexture(String, int, TextureFormat, int, int, int)} but with stencil support */
|
||||
+ default GpuTexture createTexture(@Nullable String label, @GpuTexture.Usage final int usage, TextureFormat format, int width, int height, int depthOrLayers, int mipLevels, boolean stencil) {
|
||||
+ /** Forge: same as {@link #createTexture(String, int, GpuFormat, int, int, int)} but with stencil support */
|
||||
+ default GpuTexture createTexture(@Nullable String label, @GpuTexture.Usage final int usage, GpuFormat format, int width, int height, int depthOrLayers, int mipLevels, boolean stencil) {
|
||||
+ return createTexture(label, usage, format, width, height, depthOrLayers, mipLevels);
|
||||
+ }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
--- a/com/mojang/blaze3d/textures/GpuTexture.java
|
||||
+++ b/com/mojang/blaze3d/textures/GpuTexture.java
|
||||
@@ -8,7 +_,7 @@
|
||||
@@ -9,7 +_,7 @@
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,31 @@
|
|||
--- a/com/mojang/blaze3d/vertex/VertexFormat.java
|
||||
+++ b/com/mojang/blaze3d/vertex/VertexFormat.java
|
||||
@@ -29,6 +_,7 @@
|
||||
private final int[] offsetsByElement = new int[32];
|
||||
private @Nullable GpuBuffer immediateDrawVertexBuffer;
|
||||
private @Nullable GpuBuffer immediateDrawIndexBuffer;
|
||||
@@ -19,6 +_,7 @@
|
||||
private final int vertexSize;
|
||||
private final int stepRate;
|
||||
private final List<VertexFormatElement> elementValues;
|
||||
+ private final com.google.common.collect.ImmutableMap<String, VertexFormatElement> elementMapping;
|
||||
|
||||
private VertexFormat(final List<VertexFormatElement> elements, final List<String> names, final IntList offsets, final int vertexSize) {
|
||||
this.elements = elements;
|
||||
@@ -41,6 +_,11 @@
|
||||
int j = vertexformatelement != null ? elements.indexOf(vertexformatelement) : -1;
|
||||
this.offsetsByElement[i] = j != -1 ? offsets.getInt(j) : -1;
|
||||
private VertexFormat(final List<VertexFormatElement> elements, final int vertexSize, final int stepRate) {
|
||||
this.vertexSize = vertexSize;
|
||||
@@ -29,6 +_,11 @@
|
||||
}
|
||||
|
||||
this.elementValues = elements;
|
||||
+
|
||||
+ ImmutableMap.Builder<String, VertexFormatElement> elementMapping = ImmutableMap.builder();
|
||||
+ for (int i = 0; i < elements.size(); i++)
|
||||
+ elementMapping.put(names.get(i), elements.get(i));
|
||||
+ var elementMapping = com.google.common.collect.ImmutableMap.<String, VertexFormatElement>builder();
|
||||
+ for (var element : elements)
|
||||
+ elementMapping.put(element.name(), element);
|
||||
+ this.elementMapping = elementMapping.buildOrThrow();
|
||||
}
|
||||
|
||||
public static VertexFormat.Builder builder() {
|
||||
@@ -139,6 +_,9 @@
|
||||
this.immediateDrawIndexBuffer = uploadToBuffer(this.immediateDrawIndexBuffer, buffer, 72, () -> "Immediate index buffer for " + this);
|
||||
return this.immediateDrawIndexBuffer;
|
||||
public static VertexFormat.Builder builder(final int stepRate) {
|
||||
@@ -69,6 +_,8 @@
|
||||
public int hashCode() {
|
||||
return this.elementValues.hashCode();
|
||||
}
|
||||
+
|
||||
+ public ImmutableMap<String, VertexFormatElement> getElementMapping() { return elementMapping; }
|
||||
+ public int getOffset(int index) { return offsetsByElement[index]; }
|
||||
+ public com.google.common.collect.ImmutableMap<String, VertexFormatElement> getElementMapping() { return elementMapping; }
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class Builder {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
--- a/com/mojang/math/Transformation.java
|
||||
+++ b/com/mojang/math/Transformation.java
|
||||
@@ -17,7 +_,7 @@
|
||||
@@ -14,7 +_,7 @@
|
||||
import org.joml.Vector3fc;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
|
|
@ -15,15 +15,15 @@
|
|||
);
|
||||
+ }
|
||||
+
|
||||
+ private Matrix3f normalTransform = null;
|
||||
+ public Matrix3f getNormalMatrix() {
|
||||
+ private org.joml.Matrix3f normalTransform = null;
|
||||
+ public org.joml.Matrix3f getNormalMatrix() {
|
||||
+ checkNormalTransform();
|
||||
+ return normalTransform;
|
||||
+ }
|
||||
+
|
||||
+ private void checkNormalTransform() {
|
||||
+ if (normalTransform == null) {
|
||||
+ normalTransform = new Matrix3f(matrix);
|
||||
+ normalTransform = new org.joml.Matrix3f(matrix);
|
||||
+ normalTransform.invert();
|
||||
+ normalTransform.transpose();
|
||||
+ }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
@Override
|
||||
+ public boolean keyPressed(net.minecraft.client.input.KeyEvent event) {
|
||||
+ if (event.key() == org.lwjgl.glfw.GLFW.GLFW_KEY_ESCAPE) {
|
||||
+ minecraft.setScreen(this.nextScreen);
|
||||
+ minecraft.gui.setScreen(this.nextScreen);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return super.keyPressed(event);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
--- a/com/mojang/realmsclient/gui/screens/RealmsResetWorldScreen.java
|
||||
+++ b/com/mojang/realmsclient/gui/screens/RealmsResetWorldScreen.java
|
||||
@@ -303,7 +_,7 @@
|
||||
int k = this.getY();
|
||||
graphics.blit(RenderPipelines.GUI_TEXTURED, this.image, j + 2, k + 2, 0.0F, 0.0F, 56, 56, 56, 56, 56, 56, i);
|
||||
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_FRAME_SPRITE, j, k, 60, 60, i);
|
||||
- int l = flag ? -6250336 : -1;
|
||||
+ int l = getFGColor();
|
||||
graphics.centeredText(RealmsResetWorldScreen.this.font, this.getMessage(), j + 28, k - 14, l);
|
||||
@@ -300,7 +_,7 @@
|
||||
int y = this.getY();
|
||||
graphics.blit(RenderPipelines.GUI_TEXTURED, this.image, x + 2, y + 2, 0.0F, 0.0F, 56, 56, 56, 56, 56, 56, color);
|
||||
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, SLOT_FRAME_SPRITE, x, y, 60, 60, color);
|
||||
- int textColor = hoveredOrFocused ? -6250336 : -1;
|
||||
+ int textColor = getFGColor();
|
||||
graphics.centeredText(RealmsResetWorldScreen.this.font, this.getMessage(), x + 28, y - 14, textColor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
--- a/net/minecraft/CrashReport.java
|
||||
+++ b/net/minecraft/CrashReport.java
|
||||
@@ -58,14 +_,9 @@
|
||||
if (this.uncategorizedStackTrace != null && this.uncategorizedStackTrace.length > 0) {
|
||||
if (this.uncategorizedStackTrace.length > 0) {
|
||||
builder.append("-- Head --\n");
|
||||
builder.append("Thread: ").append(Thread.currentThread().getName()).append("\n");
|
||||
- builder.append("Stacktrace:\n");
|
||||
-
|
||||
- for (StackTraceElement stacktraceelement : this.uncategorizedStackTrace) {
|
||||
- builder.append("\t").append("at ").append(stacktraceelement);
|
||||
- for (StackTraceElement element : this.uncategorizedStackTrace) {
|
||||
- builder.append("\t").append("at ").append(element);
|
||||
- builder.append("\n");
|
||||
- }
|
||||
-
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
+ builder.append(net.minecraftforge.logging.CrashReportExtender.generateEnhancedStackTrace(this.uncategorizedStackTrace));
|
||||
}
|
||||
|
||||
for (CrashReportCategory crashreportcategory : this.details) {
|
||||
for (CrashReportCategory entry : this.details) {
|
||||
@@ -73,6 +_,7 @@
|
||||
builder.append("\n\n");
|
||||
}
|
||||
|
|
@ -26,23 +26,20 @@
|
|||
this.systemReport.appendToCrashReportString(builder);
|
||||
}
|
||||
|
||||
@@ -92,18 +_,7 @@
|
||||
throwable.setStackTrace(this.exception.getStackTrace());
|
||||
@@ -84,15 +_,7 @@
|
||||
exception = replaceMessage(exception, this.title);
|
||||
}
|
||||
|
||||
- String s;
|
||||
- try {
|
||||
- stringwriter = new StringWriter();
|
||||
- printwriter = new PrintWriter(stringwriter);
|
||||
- throwable.printStackTrace(printwriter);
|
||||
- s = stringwriter.toString();
|
||||
- writer = new StringWriter();
|
||||
- printWriter = new PrintWriter(writer);
|
||||
- exception.printStackTrace(printWriter);
|
||||
- return writer.toString();
|
||||
- } finally {
|
||||
- IOUtils.closeQuietly((Writer)stringwriter);
|
||||
- IOUtils.closeQuietly((Writer)printwriter);
|
||||
- IOUtils.closeQuietly(writer);
|
||||
- IOUtils.closeQuietly(printWriter);
|
||||
- }
|
||||
-
|
||||
- return s;
|
||||
+ return net.minecraftforge.logging.CrashReportExtender.generateEnhancedStackTrace(throwable);
|
||||
+ return net.minecraftforge.logging.CrashReportExtender.generateEnhancedStackTrace(exception);
|
||||
}
|
||||
|
||||
public String getFriendlyReport(final ReportType reportType, final List<String> extraComments) {
|
||||
private static Throwable copyProperties(final Throwable original, final Throwable copy) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue