Compare commits

..
47 Commits
Author SHA1 Message Date
LexManos 7878d97fbb Add protection against large network channel lists 2026-10-14 20:04:33 -07:00
LexManos 8b2980400b Fix legacy object holders not being fired in the registry specific codepath
Better optimize the scanning for object holders by unrolling streams.
2026-10-13 10:05:59 -07:00
BonsUnleashedandLexManos 58c92b1e76 Store object holder handlers per registry name (#10899)
Co-authored-by: LexManos <[email protected]>
2026-10-12 17:14:32 -07:00
LexManos 01568f90fa Fix generic errors in new Eclipse compiler 2026-10-12 17:14:26 -07:00
Meme Man fba9c66164 Update equality check for RegistryObject to include RegistryObject#key. (#10864) 2026-08-04 19:10:36 +01:00
Matt afaba58edc Toml parsing errors are now visible in the latest log (#10842) 2026-07-09 13:01:35 -07:00
Jonathing 8bdf29553b Migrate the MDK to ForgeGradle 7
Backport of d29524b to 1.21.3
2026-03-18 23:10:05 +00:00
Paint_Ninja f6867c2151 Bump ASM and EventBus
- ASM 9.9.1 for Java 26 support
- EventBus 6.2.33 for Event#cancel() convenience method and further performance improvements
2026-03-17 20:56:04 +00:00
Paint_Ninja 63fa38ba14 Skip processing vanilla classes in RuntimeDistCleaner when running on a client
Backport of #10682 to 1.21.3
2026-03-17 20:43:17 +00:00
LexManos e6318f8793 Update SecureModules to address ZipPath bug with brackets. Closes #10755 2026-01-20 18:45:24 -08:00
LexManos 0bee88f4c0 Mark applyServerBinpatches as a dependency of BundleList. Fixes: #10729 2025-12-04 09:19:42 -08:00
LexManos 75650bde6b Migrate to Github Actions 2025-12-02 14:47:59 -08:00
MattandLexManos 29f1a5c117 [1.21.3] Fix crafter not inserting into iitemhandler (#10667) (#10670)
Co-authored-by: LexManos <[email protected]>
2025-09-25 13:36:49 -07:00
Paint_Ninja aee3baf4ce Bump ASM to 9.8 for Java 25 runtime support 2025-09-22 11:54:36 +01:00
Matt c73c954e46 Add ForgeLayeredDraw & AddGuiOverlayLayersEvent as API for gui overlay management. (#10580) 2025-07-27 10:17:44 -07:00
Jonathing 371938199e Add #forge:chorus_additionally_grows_on (#10460) 2025-04-11 09:49:46 -07:00
Jonathing c047cf136c 1.21.3 RB 1
https://forums.minecraftforge.net/topic/154393-forge-531-minecraft-1213/
2025-03-01 16:56:32 -05:00
Jonathing f4287ecc81 Add missed license headers (#10475) 2025-03-01 21:35:03 +00:00
JonathingandLexManos 364a1e737f Speed up mod annotation scanning by ~30% (#10466)
Co-authored-by: LexManos <[email protected]>
2025-03-01 21:34:40 +00:00
Jonathing 45a977bb33 [1.21.3] Bump dependencies, most notably EventBus (#10385)
- CoreMods 5.2.4 -> 5.2.6
- EventBus 6.2.15 -> 6.2.27
    - Reduced memory usage
    - Further performance improvements
    - Fixed EventBus#39, unregistered listeners are now immediately reclaimable by the GC
- Apache MavenArtifact 3.8.5 -> 3.8.8
- NightConfig 3.7.3 -> 3.7.4
2025-02-12 17:51:46 -08:00
Jonathing ab00c907e7 Add fast graphics render type to block model jsons (#10395)
Make modded leaves behave like vanilla leaves by default (Fixes #10389)
2025-02-12 17:39:27 -08:00
979abb2b93 Re-introduce ItemStack Capabilities (#10362)
Co-authored-by: RealMangoRage <[email protected]>
Co-authored-by: LexManos <[email protected]>
2025-02-12 17:30:29 -08:00
Jonathing 056360b050 Re-introduce IForgeItem.damageItem when an item takes damage, Fixes #10344 (#10372) 2025-02-12 17:29:44 -08:00
Jonathing 960fce505c Add updated tag context to AddReloadListenerEvent (#10416)
Fixes using custom tags in GlobalLootModifiers.
2025-02-12 17:21:30 -08:00
JonathingandLexManos ea597ff45a Fix redstone update order not matching vanilla. (#10392)
Fix redstone updates for comparators going up/down incorrectly. Related: #9973
Fix game test structure rotations being inconsistant (#10391)

Co-authored-by: LexManos <[email protected]>
2025-02-12 17:11:56 -08:00
Jonathing f35dce7eb3 Fix corrupted and invalidly symlinked worlds crashing on level select (#10415) 2025-02-12 17:03:06 -08:00
Jonathing ef224bd2b8 Fix ModelDiscovery using Item components early (#10418) 2025-02-12 17:02:52 -08:00
Jonathing 0749f49b6c Fix forced chunks never being ticked by the server (#10365) 2025-02-12 13:37:21 -08:00
Jonathing 5c508efaa9 Fix shield disabling being completely ignored (#10317) 2025-01-27 15:28:07 -08:00
JonathingandJoseph T. McQuigg dbafe039d8 Fix issues in VillagerTrades.EmeraldsForVillagerTypeItem related to custom Villager Types (#10357)
Co-authored-by: Joseph T. McQuigg <[email protected]>
2025-01-27 15:27:42 -08:00
JonathingandLexManos b36ee22925 GameTestHelper additions (#10339)
Co-authored-by: LexManos <[email protected]>
2025-01-27 09:44:26 -08:00
Jonathing 287ee7b0b5 Update Gradle to 8.12.1 (#10353)
IntelliJ download sources in MDK
2025-01-27 09:44:11 -08:00
Jonathing 5f67621477 Fix JOpt Simple by bumping ModLaucnher (#10348) 2025-01-27 09:43:49 -08:00
Jonathing f237e7a8c3 Fix incorrect method reference in TntBlock.explode() (#10327) 2025-01-25 18:15:54 +00:00
Jonathing a54420de36 Fix JOpt Simple needing a strict version requirement declaration (#10312) 2025-01-25 18:15:36 +00:00
Jonathing 65dbdc8eb0 Bump dependencies (#10275)
- EventBus 6.2.8 -> 6.2.15
- Bootstrap 2.1.3 -> 2.1.8
- SecureModules 2.2.20 -> 2.2.21
- AccessTransformers 8.2.0 -> 8.2.1
- ModLauncher 10.2.2 -> 10.2.3
These bumps include further cleanup and optimisations.
2025-01-04 16:17:38 +00:00
Jonathing d42979f620 Simplify Title Screen Brandings (#10288) 2025-01-02 21:34:03 -08:00
Jonathing ac56afc99c Clean and fix Forge's internal coremods, fixes finalizeSpawn hook. 2024-12-30 14:36:16 -08:00
Gabriel Harris-Rouquette 81b7bfe4ea Update jline for better darwin/arm64 support (#10281) 2024-12-30 09:46:25 -08:00
Jonathing 4cbcf64ce1 Bump CoreMods to 5.2.4 (#10267) 2024-12-23 15:36:20 -08:00
JonathingandPaint_Ninja 29b763a0c3 Simplify memory usage display on loading screen (#10237)
Co-authored-by: Paint_Ninja <[email protected]>
2024-12-23 12:52:39 -08:00
JonathingandPaint_Ninja 52f41a4448 Deprecate @ObjectHolder, add a couple of fast-paths (#10232)
Co-authored-by: Paint_Ninja <[email protected]>
2024-12-23 12:51:51 -08:00
JonathingandPaint_Ninja 597409e2f2 Skip Vanilla classes for the CapabilityTokenSubclass transformer (#10225)
Co-authored-by: Paint_Ninja <[email protected]>
2024-12-23 12:42:07 -08:00
JonathingandPaint_Ninja 21fbd72585 Skip Forge classes in the RuntimeEnumExtender transformer (#10220)
Mod classes are still transformed as usual

Co-authored-by: Paint_Ninja <[email protected]>
2024-12-23 12:30:09 -08:00
JonathingandPaint_Ninja 83a09f7584 Skip processing Forge classes in RuntimeDistCleaner (#10212)
Co-authored-by: Paint_Ninja <[email protected]>
2024-12-23 12:19:40 -08:00
Jonathing 0e864fbe6e Fix NightConfig FileWatcher causing dedicated server to hang when exiting (#10214) 2024-12-23 12:09:22 -08:00
Jonathing 2fd8900c01 Allow mipmap lowering to be disabled (#10256) 2024-12-23 11:57:00 -08:00
1212 changed files with 16423 additions and 18820 deletions

No files matched your search

-1
View File
@@ -3,7 +3,6 @@
*.patch text eol=lf
*.java text eol=lf
*.gradle text eol=crlf
**/MANIFEST.MF text eol=crlf
*.png binary
*.gif binary
*.exe binary
+1 -1
View File
@@ -2,7 +2,7 @@ name: Publish
on:
push:
branches: [ '1.21.8' ]
branches: [ '1.21.3' ]
permissions:
contents: read
-5
View File
@@ -41,8 +41,3 @@ src/*/generated/**/.cache/
/ForgeRoot.ipr
/ForgeRoot.iws
# APT stuff
/*/.gitignore
/*/.factorypath
/*/.apt_generated/
+5 -4
View File
@@ -4,11 +4,11 @@ import net.minecraftforge.gradleutils.PomUtils
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 'net.minecraftforge.gradleutils' version '[2.3.0,2.4.0)'
id 'eclipse'
id 'de.undercouch.download' version '5.4.0'
id 'net.minecraftforge.gradle.patcher' version '[6.0.54,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0.45,6.2)' apply false
id 'net.minecraftforge.gradle.patcher' version '[6.0.22,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0.22,6.2)' apply false
id 'net.minecraftforge.gradlejarsigner' version '1.0.4'
id 'org.barfuin.gradle.taskinfo' version '2.1.0'
}
@@ -16,7 +16,8 @@ plugins {
Util.init() //Init all our extension methods!
ext {
VERSION = gitversion.getMCTagOffsetBranch(MC_VERSION)
GIT_INFO = gradleutils.gitInfo
VERSION = gradleutils.getFilteredMCTagOffsetBranchVersion(true, '[0-9]', MC_VERSION)
FORGE_VERSION = VERSION.substring(MC_VERSION.length() + 1)
}
+1 -1
View File
@@ -6,7 +6,7 @@ repositories {
dependencies {
implementation 'org.ow2.asm:asm:9.9.1'
implementation 'org.ow2.asm:asm-tree:9.9.1'
implementation 'net.minecraftforge:srgutils:0.6.8'
implementation 'net.minecraftforge:srgutils:0.6.2'
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'
+20 -54
View File
@@ -71,7 +71,7 @@ sourceSets {
}
}
final String SPEC_VERSION = gitversion.info.tag
final String SPEC_VERSION = gradleutils.gitInfo.tag
// The new versioning sceme is <MCVersion>-<ForgeMC>.<RB>.<CommitsSinceRB>
// ForgeMC is a unique identifier for every MC version we have supported.
@@ -91,18 +91,18 @@ final String MAVEN_PATH = ext.MAVEN_PATH
final String BINPATCH_TOOL = 'net.minecraftforge:binarypatcher:1.2.0:fatjar'
final String INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.4.3'
final String FART = 'net.minecraftforge:ForgeAutoRenamingTool:1.0.6'
final String S2S_TOOL = 'net.minecraftforge:Srg2Source:8.1.1:fatjar'
final String S2S_TOOL = 'net.minecraftforge:Srg2Source:8.1.0:fatjar'
configurations {
// Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it.
bootstrap { transitive = false }
installer {
installer {
extendsFrom(bootstrap)
transitive = false
transitive = false
}
installerextra {
installerextra {
extendsFrom(bootstrap)
transitive = false
transitive = false
}
api.extendsFrom(installer)
}
@@ -116,14 +116,14 @@ dependencies {
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.typetools) // Dep of EventBus
installer(libs.forgespi)
installer(libs.coremods)
installer(libs.nashorn) // Dep of Coremods
@@ -141,14 +141,11 @@ dependencies {
installer(project(':javafmllanguage'))
installer(project(':lowcodelanguage'))
installer(project(':mclanguage'))
installer(project(':forge-transformers'))
installerextra("${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:srg2off")
runtimeOnly(libs.bootstrap)
runtimeOnly(libs.bootstrap.dev)
annotationProcessor(libs.eventbus.validator)
}
tasks.named('extractRangeMap').configure {
@@ -168,7 +165,7 @@ patcher {
runs {
forge_client {
property 'eventbus.api.strictRuntimeChecks', 'true'
property 'eventbus.checkTypesOnDispatch', 'true'
property 'org.lwjgl.system.SharedLibraryExtractDirectory', 'lwjgl_dll'
args '--launchTarget', 'forge_dev_client',
@@ -211,6 +208,7 @@ patcher {
'--all',
'--validate',
'--output', rootProject.file('src/main/generated/'),
'--validate',
'--existing', sourceSets.main.resources.srcDirs[0],
'--assetsDir', downloadAssets.output,
'--assetIndex', "{asset_index}"
@@ -228,30 +226,6 @@ patcher {
'--assetsDir', downloadAssets.output,
'--assetIndex', "{asset_index}"
}
forge_client_data {
args '--launchTarget', 'forge_dev_client_data',
'--mod', 'forge',
'--all',
'--output', rootProject.file('src/main/generated/'),
'--existing', sourceSets.main.resources.srcDirs[0],
'--assetsDir', downloadAssets.output,
'--assetIndex', "{asset_index}"
}
forge_client_data_test {
source sourceSets.test
args '--launchTarget', 'forge_dev',
'--launchEntry', 'minecraft/net.minecraft.client.data.Main',
'--launchData',
'--mod', '.+',
'--all',
'--output', rootProject.file('src/test/generated/'),
'--existing', sourceSets.main.resources.srcDirs[0],
'--existing', sourceSets.test.resources.srcDirs[0],
'--assetsDir', downloadAssets.output,
'--assetIndex', "{asset_index}"
}
}
}
@@ -293,11 +267,11 @@ tasks.register('downloadCrowdin', Download) {
tasks.userdevConfig.configure {
configurations.installer.allDependencies.forEach {
def dep = it.toString()
if (it instanceof ProjectDependency)
if (it instanceof ProjectDependency)
dep = "net.minecraftforge:$it.dependencyProject.name:$it.dependencyProject.version"
libraries.add(dep)
}
inject = '' // We don't have a userdev sourceset anymore. Empty as a gradle workaround...
runs {
client {
@@ -309,13 +283,6 @@ tasks.userdevConfig.configure {
args '--assetsDir', '{assets_root}'
}
clientData {
environment 'MCP_MAPPINGS', '{mcp_mappings}'
args '--launchTarget', "forge_userdev_client_data"
args '--assetIndex', '{asset_index}'
args '--assetsDir', '{assets_root}'
}
server {
environment 'MCP_MAPPINGS', '{mcp_mappings}'
property 'forge.enableGameTest', 'true'
@@ -525,7 +492,7 @@ tasks.register('serverShimJar', Jar) {
from {
zipTree(downloadServerShim.output).find { it.name == 'MANIFEST.MF' }
}
attributes('Class-Path': configurations.bootstrap.resolvedConfiguration.resolvedArtifacts.collect { "libraries/${Util.getMavenInfoFromDep(it).path}" }.join(' '))
}
archiveClassifier = 'shim'
@@ -618,7 +585,7 @@ tasks.register('checkJarCompatibility', CheckJarCompatibility) {
baseLibraries.from(project.tasks.named('createJoinedSRG').flatMap { it.output })
inputJar = project.tasks.named('reobfJar').flatMap { it.output }
commonLibraries.from(project.configurations.minecraftImplementation)
commonLibraries.from(project.configurations.installer)
}
@@ -639,11 +606,11 @@ tasks.register('launcherJson', LauncherJson).configure {
tasks.register('installerJson', InstallerJson) {
icon = rootProject.file('icon.ico')
// Json to install into the client's launcher
dependsOn(launcherJson)
input.from(launcherJson.output)
// Download Official Mappings
dependsOn(downloadClientMappings, downloadServerMappings)
input.from(downloadClientMappings.output, downloadServerMappings.output)
@@ -958,8 +925,7 @@ tasks.register('mdkZip', Zip) {
MAPPING_CHANNEL: MAPPING_CHANNEL,
MAPPING_VERSION: MAPPING_VERSION,
FORGE_SPEC_VERSION: SPEC_VERSION.split("\\.")[0],
MC_NEXT_VERSION: MC_NEXT_VERSION,
EVENTBUS_VERSION: libs.versions.eventbus.get()
MC_NEXT_VERSION: MC_NEXT_VERSION
])
rename 'gitignore\\.txt', '.gitignore'
rename 'gitattributes\\.txt', '.gitattributes'
@@ -1006,7 +972,7 @@ if (project.hasProperty('UPDATE_MAPPINGS')) {
tasks.named('javadoc', Javadoc).configure {
description 'Generates the combined javadocs for the FML projects and the main Forge project'
var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage', ':forge-transformers' ]
var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage' ]
source includedProjects.collect { project(it).sourceSets.main.allJava }
classpath = classpath + files(includedProjects.collect { project(it).sourceSets.main.compileClasspath })
@@ -1100,7 +1066,7 @@ publishing {
license gradleutils.pom.Licenses.LGPLv2_1
}
}
repositories {
maven gradleutils.publishingForgeMaven
}
+1 -1
View File
@@ -44,7 +44,7 @@ tasks.withType(JavaCompile).configureEach {
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.
options.forkOptions.jvmArgs += '-Xmx3G' // 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
+2 -8
View File
@@ -2,8 +2,8 @@
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.21.8-&query=$.promos["1.21.8-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.21.8-&query=$.promos["1.21.8-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.21.3-&query=$.promos["1.21.3-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.21.3-&query=$.promos["1.21.3-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)][Download] [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)][Discord] [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)][Patreon]
Forge is a free, open-source modding API all of your favourite mods use!
@@ -70,11 +70,6 @@ Please ensure you have a valid email address associated with your GitHub account
to use and modify. However, it costs money to run such a large project as this, so please consider
[becoming a patron][Patreon].*
### Thanks
[![YourKit](https://www.yourkit.com/images/yklogo.png)](https://www.yourkit.com/)
YourKit for providing us accesss to their [YourKit Java Profiler] which helps identify bottlenecks and places for improvment.
[Contributing]: ./CONTRIBUTING.md
[CLA]: https://cla-assistant.io/MinecraftForge/MinecraftForge
@@ -98,4 +93,3 @@ YourKit for providing us accesss to their [YourKit Java Profiler] which helps id
[Pull-Requests]: https://docs.minecraftforge.net/en/latest/forgedev/#making-changes-and-pull-requests
[Patreon]: https://www.patreon.com/LexManos
[YourKit Java Profiler]: https://www.yourkit.com/java/profiler/
+1 -2
View File
@@ -10,10 +10,9 @@ plugins {
apply from: rootProject.file('build_shared.gradle')
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
api(libs.eventbus)
annotationProcessor(libs.eventbus.validator)
implementation(project(':fmlloader'))
implementation(libs.commons.io)
@@ -5,7 +5,7 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.loading.FMLLoader;
@@ -29,7 +29,7 @@ public class Bindings {
/**
* @return A supplier of net.minecraftforge.common.MinecraftForge#EVENT_BUS
*/
public static Supplier<BusGroup> getForgeBus() {
public static Supplier<IEventBus> getForgeBus() {
return PROVIDER.getForgeBusSupplier();
}
@@ -25,18 +25,7 @@ import java.util.function.Supplier;
* <li>When you want to call one thing on one side, another thing on the other and return a result {@link #safeRunForDist(Supplier, Supplier)}</li>
* <li>When you want to run something on one side {@link #safeRunWhenOn(Dist, Supplier)}</li>
* </ul>
*
* @deprecated Historically, this allowed for safe execution of code on the correct side by exploiting a low-level
* detail in Java 8, but in newer versions a simple if check is enough.
* <br>
* For example:
* <pre>{@code
* if (FMLEnvironment.dist.isClient()) {
* // client code here
* }
* }</pre>
*/
@Deprecated(since = "1.21.5", forRemoval = true)
public final class DistExecutor
{
private static final Logger LOGGER = LogManager.getLogger();
@@ -5,13 +5,13 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.config.IConfigEvent;
import java.util.function.Supplier;
public interface IBindingsProvider {
Supplier<BusGroup> getForgeBusSupplier();
Supplier<IEventBus> getForgeBusSupplier();
Supplier<I18NParser> getMessageParser();
Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration();
}
@@ -5,6 +5,8 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import java.util.Optional;
@@ -59,13 +61,14 @@ public interface IModLoadingState {
/**
* Builds the transition task for this state with a blank pre-sync and post-sync task.
*
* @param <T> a type of event fired on the mod-specific event bus
* @param syncExecutor a synchronous executor
* @param parallelExecutor a parallel executor
* @param progressBar a progress meter for tracking progress
* @return a transition task for this state
* @see #buildTransition(Executor, Executor, ProgressMeter, Function, Function)
*/
default Optional<CompletableFuture<Void>> buildTransition(
default <T extends Event & IModBusEvent> Optional<CompletableFuture<Void>> buildTransition(
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar
@@ -80,6 +83,7 @@ public interface IModLoadingState {
* Builds the transition task for this state. The pre-sync and post-sync task functions allow the transition builder
* to run these tasks on the same executor as the actual event dispatch and pre/post hooks.
*
* @param <T> a type of event fired on the mod-specific event bus
* @param syncExecutor a synchronous executor
* @param parallelExecutor a parallel executor
* @param progressBar a progress meter for tracking progress
@@ -87,6 +91,7 @@ public interface IModLoadingState {
* @param postSyncTask a function which returns a task to run after event post-dispatch hook
* @return a transition task for this state
*/
<T extends Event & IModBusEvent>
Optional<CompletableFuture<Void>> buildTransition(final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
@@ -5,6 +5,7 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
@@ -19,7 +20,7 @@ import org.jetbrains.annotations.Nullable;
public interface IModStateTransition {
/** Magic value to allow me to optimize the futures list by ignoring the default value without making old methods nullable. */
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> NULL_HOOK = (e, g) -> CompletableFuture.completedFuture(null);
public static final BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> NULL_HOOK = (e, g) -> CompletableFuture.completedFuture(null);
static IModStateTransition buildNoopTransition() {
return ModStateTransitionHelper.NOOP;
@@ -50,7 +51,7 @@ public interface IModStateTransition {
}
@Nullable
default <T extends IModBusEvent> EventGenerator<T> eventFunction() {
default <T extends Event & IModBusEvent> EventGenerator<T> eventFunction() {
return null;
}
@@ -73,8 +74,8 @@ public interface IModStateTransition {
@Deprecated(since = "1.21.3", forRemoval = true)
default BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> postDispatchHook() { return NULL_HOOK; }
interface EventGenerator<T extends IModBusEvent> extends Function<ModContainer, T> {
static <FN extends IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
interface EventGenerator<T extends Event & IModBusEvent> extends Function<ModContainer, T> {
static <FN extends Event & IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
return fn::apply;
}
}
@@ -5,6 +5,7 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.IModBusEvent;
@@ -161,5 +162,5 @@ public abstract class ModContainer {
* Accept an arbitrary event for processing by the mod. Probably posted to an event bus in the lower level container.
* @param e Event to accept
*/
protected <T extends IModBusEvent> void acceptEvent(T e) {}
protected <T extends Event & IModBusEvent> void acceptEvent(T e) {}
}
@@ -6,6 +6,7 @@
package net.minecraftforge.fml;
import com.google.common.collect.ImmutableList;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.fml.loading.FMLLoader;
@@ -87,7 +88,7 @@ public class ModLoader {
this.loadingModList = FMLLoader.getLoadingModList();
this.loadingExceptions = this.loadingModList.getErrors().stream()
.flatMap(ModLoadingException::fromEarlyException)
.collect(Collectors.toList());
.toList();
this.loadingWarnings = this.loadingModList.getBrokenFiles().stream()
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
.collect(Collectors.toList());
@@ -154,13 +155,11 @@ public class ModLoader {
loadingStateValid = false;
throw new LoadingFailedException(loadingExceptions);
}
var failedBounds = new ArrayList<ForgeFeature.Bound>();
for (var mod : loadingModList.getMods()) {
for (var feature : mod.getForgeFeatures()) {
if (!ForgeFeature.testFeature(FMLEnvironment.dist, feature))
failedBounds.add(feature);
}
}
List<? extends ForgeFeature.Bound> failedBounds = loadingModList.getMods().stream()
.map(ModInfo::getForgeFeatures)
.flatMap(List::stream)
.filter(bound -> !ForgeFeature.testFeature(FMLEnvironment.dist, bound))
.toList();
if (!failedBounds.isEmpty()) {
LOGGER.fatal(CORE, "Failed to validate feature bounds for mods: {}", failedBounds);
@@ -358,53 +357,49 @@ public class ModLoader {
return completedStates.contains(state);
}
public <T extends IModBusEvent> void runEventGenerator(Function<ModContainer, T> generator) {
public <T extends Event & IModBusEvent> void runEventGenerator(Function<ModContainer, T> generator) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event generator to a broken mod state");
return;
}
for (var mod : ModList.get().getLoadedMods())
mod.acceptEvent(generator.apply(mod));
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(generator.apply(mc)));
}
public <T extends IModBusEvent> void postEvent(T e) {
var cls = e.getClass();
public <T extends Event & IModBusEvent> void postEvent(T e) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
return;
}
for (var mod : ModList.get().getLoadedMods())
mod.acceptEvent(e);
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(e));
}
public <T extends IModBusEvent> T postEventWithReturn(T e) {
public <T extends Event & IModBusEvent> T postEventWithReturn(T e) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
return e;
}
for (var mod : ModList.get().getLoadedMods())
mod.acceptEvent(e);
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(e));
return e;
}
@SuppressWarnings("removal")
public <T extends IModBusEvent> void postEventWrapContainerInModOrder(T event) {
public <T extends Event & IModBusEvent> void postEventWrapContainerInModOrder(T event) {
postEventWithWrapInModOrder(event,
(mc, e) -> ModLoadingContext.get().setActiveContainer(mc),
(mc, e) -> ModLoadingContext.get().setActiveContainer(null)
);
}
public <T extends IModBusEvent> void postEventWithWrapInModOrder(T e, BiConsumer<ModContainer, T> pre, BiConsumer<ModContainer, T> post) {
public <T extends Event & IModBusEvent> void postEventWithWrapInModOrder(T e, BiConsumer<ModContainer, T> pre, BiConsumer<ModContainer, T> post) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
return;
}
for (var mod : ModList.get().getLoadedMods()) {
pre.accept(mod, e);
mod.acceptEvent(e);
post.accept(mod, e);
}
ModList.get().forEachModInOrder(mc -> {
pre.accept(mc, e);
mc.acceptEvent(e);
post.accept(mc, e);
});
}
public List<ModLoadingWarning> getWarnings() {
@@ -421,7 +416,7 @@ public class ModLoader {
return runningDataGen;
}
private static final class ErroredModContainer extends ModContainer {
private static class ErroredModContainer extends ModContainer {
public ErroredModContainer() {
super();
}
@@ -5,6 +5,8 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import java.util.Optional;
@@ -34,7 +36,7 @@ public record ModLoadingState(
Optional<IModStateTransition> transition
) implements IModLoadingState {
@Override
public Optional<CompletableFuture<Void>> buildTransition(
public <T extends Event & IModBusEvent> Optional<CompletableFuture<Void>> buildTransition(
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
@@ -9,16 +9,15 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jetbrains.annotations.ApiStatus;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.IModStateTransition.EventGenerator;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
@@ -42,7 +41,7 @@ class ModStateTransitionHelper {
if (t.stream().noneMatch(e -> e.exception() != null)) {
return CompletableFuture.completedFuture(null);
} else {
final var throwables = t.stream().map(FutureResult::exception).filter(Objects::nonNull).toList();
final var throwables = t.stream().map(FutureResult::exception).filter(e -> e != null).toList();
CompletableFuture<Void> cf = new CompletableFuture<>();
final RuntimeException accumulator = new RuntimeException();
cf.completeExceptionally(accumulator);
@@ -71,15 +70,13 @@ class ModStateTransitionHelper {
for (var future : futures) {
int i = list.size();
list.add(null);
@SuppressWarnings("unchecked") // Bypass a weird javac error with generic by forcing it to be the exact type we want.
var raw = ((CompletableFuture<V>)future);
results[i] = raw.whenComplete((result, exception) -> list.set(i, new FutureResult<>(result, exception)));
results[i] = future.whenComplete((result, exception) -> list.set(i, new FutureResult<>(result, exception)));
}
return CompletableFuture.allOf(results).handle((r, th)->null).thenApply(res -> list);
}
private static <T extends IModBusEvent> void addCompletableFutureTaskForModDispatch(
private static <T extends Event & IModBusEvent> void addCompletableFutureTaskForModDispatch(
final IModStateTransition transition,
final Executor executor,
final List<CompletableFuture<Void>> completableFutures,
@@ -138,14 +135,14 @@ class ModStateTransitionHelper {
completableFutures.add(postDispatchHook);
}
private static <T extends IModBusEvent> CompletableFuture<Void> getHook(BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> hook, Executor executor, EventGenerator<T> eventGenerator) {
private static <T extends Event & IModBusEvent> CompletableFuture<Void> getHook(BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> hook, Executor executor, EventGenerator<T> eventGenerator) {
if (hook == null || hook == IModStateTransition.NULL_HOOK) return null;
@SuppressWarnings("unchecked")
var hookTyped = (BiFunction<Executor, EventGenerator<T>, CompletableFuture<Void>>)hook;
return hookTyped.apply(executor, eventGenerator);
}
static <T extends IModBusEvent> CompletableFuture<Void> build(
static <T extends Event & IModBusEvent> CompletableFuture<Void> build(
final IModStateTransition transition,
final String name,
final Executor syncExecutor,
@@ -5,7 +5,7 @@
package net.minecraftforge.fml.config;
import net.minecraftforge.eventbus.api.event.InheritableEvent;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.Bindings;
import java.util.function.Function;
@@ -29,7 +29,7 @@ public interface IConfigEvent {
ModConfig getConfig();
@SuppressWarnings("unchecked")
default <T extends InheritableEvent & IConfigEvent> T self() {
default <T extends Event & IConfigEvent> T self() {
return (T) this;
}
}
@@ -5,27 +5,8 @@
package net.minecraftforge.fml.event;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.api.event.InheritableEvent;
/**
* Marker interface for events dispatched on the ModLifecycle event bus instead of the primary event bus
*/
public interface IModBusEvent extends InheritableEvent {
/**
* @param modEventBusGroup Obtained from {@link net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext#getModBusGroup()} or your language provider's equivalent.
* @param eventClass The event type you want to get the associated bus for.
*/
static <T extends IModBusEvent> EventBus<T> getBus(BusGroup modEventBusGroup, Class<T> eventClass) {
// Do not copy! Temporary solution until the FML rewrite is complete. May throw in future
// without prior notice.
//
// Mods creating their own events should directly assign the result of the create method to a
// static final field in their event class, without wrapping or calling multiple times.
//
// Mods using existing events should instead use the existing static final BUS field in the
// event class (for most events) or getBus(BusGroup) method (for mod bus events).
return EventBus.create(modEventBusGroup, eventClass);
}
public interface IModBusEvent {
}
+1 -1
View File
@@ -28,7 +28,7 @@ java {
}
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
implementation(project(':fmlloader'))
implementation(project(':fmlcore'))
implementation(libs.bundles.lwjgl)
@@ -90,12 +90,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
// The GL ID of the window. Used for all operations
private long window;
// The thread that contains and ticks the window while Forge is loading mods
private static final ScheduledExecutorService renderScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
final var thread = Executors.defaultThreadFactory().newThread(r);
thread.setName("EarlyDisplay");
thread.setDaemon(true);
return thread;
});
private ScheduledExecutorService renderScheduler;
private int fbWidth;
private int fbHeight;
private int fbScale;
@@ -154,7 +149,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
}
this.maximized = parsed.has(maximizedopt) || FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_MAXIMIZED);
StartupNotificationManager.modLoaderConsumer().ifPresent(c->c.accept("Forge loading " + FMLLoader.versionInfo().forgeVersion()));
StartupNotificationManager.modLoaderConsumer().ifPresent(c->c.accept("Forge loading " + forgeVersion));
performanceInfo = new PerformanceInfo();
return start(mcVersion, forgeVersion);
}
@@ -243,7 +238,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
var date = Calendar.getInstance();
if (FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_SQUIR) || (date.get(Calendar.MONTH) == Calendar.APRIL && date.get(Calendar.DAY_OF_MONTH) == 1))
this.elements.addFirst(RenderElement.squir());
this.elements.add(0, RenderElement.squir());
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -292,6 +287,12 @@ public class DisplayWindow implements ImmediateWindowProvider {
* Start the window and Render Thread; we're ready to go.
*/
public Runnable start(@Nullable String mcVersion, final String forgeVersion) {
renderScheduler = Executors.newSingleThreadScheduledExecutor(r -> {
final var thread = Executors.defaultThreadFactory().newThread(r);
thread.setName("EarlyDisplay");
thread.setDaemon(true);
return thread;
});
initWindow(mcVersion);
this.initializationFuture = renderScheduler.schedule(() -> initRender(mcVersion, forgeVersion), 1, TimeUnit.MILLISECONDS);
return this::periodicTick;
@@ -303,7 +304,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
return this.glVersion;
}
private static void crashElegantly(String errorDetails) {
private void crashElegantly(String errorDetails) {
StringBuilder msgBuilder = new StringBuilder(2000);
msgBuilder.append("Failed to initialize graphics window with current settings.\n");
msgBuilder.append("\n\n");
@@ -511,7 +512,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
this.winY = y;
}
}
private static void handleLastGLFWError(BiConsumer<Integer, String> handler) {
private void handleLastGLFWError(BiConsumer<Integer, String> handler) {
try (MemoryStack memorystack = MemoryStack.stackPush()) {
PointerBuffer pointerbuffer = memorystack.mallocPointer(1);
int error = glfwGetError(pointerbuffer);
@@ -639,7 +640,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
}
public void addMojangTexture(final int textureId) {
this.elements.addFirst(RenderElement.mojang(textureId, framecount));
this.elements.add(0, RenderElement.mojang(textureId, framecount));
}
public void close() {
@@ -22,8 +22,8 @@ public class RenderElement {
static int globalAlpha = 255;
private int retireCount;
@FunctionalInterface
interface Renderer {
void accept(SimpleBufferBuilder bb, DisplayContext context, int frame);
default Renderer then(Renderer r) {
@@ -38,9 +38,6 @@ public class RenderElement {
interface TextureRenderer {
void accept(SimpleBufferBuilder bb, DisplayContext context, int[] size, int frame);
}
/** @deprecated Use {@link Renderer} directly. This was always eagerly resolved, making it an unnecessary wrapper. */
@Deprecated(since = "1.21.5", forRemoval = true)
@FunctionalInterface
interface Initializer extends Supplier<Renderer> {}
@@ -59,18 +56,11 @@ public class RenderElement {
}
}
/** @deprecated Use {@link RenderElement#RenderElement(Renderer)} instead */
@Deprecated(since = "1.21.5", forRemoval = true)
public RenderElement(final Initializer rendererInitializer) {
this.bb = new SimpleBufferBuilder(1);
this.renderer = rendererInitializer.get();
}
public RenderElement(Renderer renderer) {
this.bb = new SimpleBufferBuilder(1);
this.renderer = renderer;
}
public boolean render(DisplayContext ctx, int count) {
this.renderer.accept(bb, ctx, count);
return this.retireCount == 0 || this.retireCount < count;
@@ -85,7 +75,7 @@ public class RenderElement {
List<SimpleFont.DisplayText> texts = new ArrayList<>();
for (int i = messages.size() - 1; i >= 0; i--) {
final StartupNotificationManager.AgeMessage pair = messages.get(i);
final float fade = Math.clamp((4000.0f - (float) pair.age() - ( i - 4 ) * 1000.0f) / 5000.0f, 0.0f, 1.0f);
final float fade = clamp((4000.0f - (float) pair.age() - ( i - 4 ) * 1000.0f) / 5000.0f, 0.0f, 1.0f);
if (fade <0.01f) continue;
Message msg = pair.message();
int colour = Math.min((int)(fade * 255f), globalAlpha) << 24 | 0xFFFFFF;
@@ -94,9 +84,19 @@ public class RenderElement {
font.generateVerticesForTexts(10, context.scaledHeight() - texts.size() * font.lineSpacing() + font.descent() - 10, bb, texts.toArray(SimpleFont.DisplayText[]::new));
}
public static RenderElement monag() {
return new RenderElement(RenderElement.initializeTexture("monagstudios.png", 45000, 4, (bb, ctx, sz, frame) -> {
var size = 256;
var x0 = (ctx.width() - 2 * size) / 2;
var y0 = 64;
QuadHelper.loadQuad(bb, x0, x0+size, y0, y0+size/2f, 0f, 1f, 0f, 0.5f, 0xFFFFFFFF);
QuadHelper.loadQuad(bb, x0+size, x0+2*size, y0, y0+size/2f, 0f, 1f, 0.5f, 1f, 0xFFFFFFFF);
}));
}
public static RenderElement mojang(final int textureId, final int frameStart) {
return new RenderElement((bb, ctx, frame) -> {
return new RenderElement(()->(bb, ctx, frame) -> {
var size = 256 * ctx.scale();
var x0 = (ctx.scaledWidth() - 2 * size) / 2;
var y0 = 64 * ctx.scale() + 32;
@@ -148,11 +148,11 @@ public class RenderElement {
}));
}
public static RenderElement progressBars(SimpleFont font) {
return new RenderElement((bb, ctx, frame) -> RenderElement.startupProgressBars(font, bb, ctx, frame));
return new RenderElement(() -> (bb, ctx, frame) -> RenderElement.startupProgressBars(font, bb, ctx, frame));
}
public static RenderElement performanceBar(SimpleFont font) {
return new RenderElement((bb, ctx, frame) -> RenderElement.memoryInfo(font, bb, ctx, frame));
return new RenderElement(() -> (bb, ctx, frame) -> RenderElement.memoryInfo(font, bb, ctx, frame));
}
public static void startupProgressBars(SimpleFont font, final SimpleBufferBuilder buffer, final DisplayContext context, final int frameNumber) {
@@ -187,10 +187,10 @@ public class RenderElement {
}
private static float[] indeterminateBar(int frame, boolean isActive) {
if (RenderElement.globalAlpha != 0xFF || !isActive) {
return new float[] { 0f, 1f };
return new float[] {0f,1f};
} else {
int progress = frame % 100;
return new float[] { Math.clamp((progress - 2) / 100f, 0f, 1f), Math.clamp((progress + 2) / 100f, 0f, 1f) };
var progress = frame % 100;
return new float[]{clamp((progress - 2) / 100f, 0f, 1f), clamp((progress + 2) / 100f, 0f, 1f)};
}
}
@@ -249,8 +249,8 @@ public class RenderElement {
};
}
private static Renderer initializeText(SimpleFont font, TextGenerator textGenerator) {
return (bb, context, frame) -> renderText(font, textGenerator, bb, context);
private static Initializer initializeText(SimpleFont font, TextGenerator textGenerator) {
return () -> (bb, context, frame) -> renderText(font, textGenerator, bb, context);
}
private static void renderText(final SimpleFont font, final TextGenerator textGenerator, final SimpleBufferBuilder bb, final DisplayContext context) {
@@ -264,13 +264,14 @@ 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));
}
private static Renderer initializeTexture(final String textureFileName, int size, int textureNumber, TextureRenderer positionAndColour) {
int[] imgSize = STBHelper.loadTextureFromClasspath(textureFileName, size, GL_TEXTURE0 + textureNumber + INDEX_TEXTURE_OFFSET);
return (bb, ctx, frame) -> {
ctx.elementShader().updateTextureUniform(textureNumber + INDEX_TEXTURE_OFFSET);
ctx.elementShader().updateRenderTypeUniform(ElementShader.RenderType.TEXTURE);
renderTexture(bb, ctx, frame, imgSize, positionAndColour);
private static Initializer initializeTexture(final String textureFileName, int size, int textureNumber, TextureRenderer positionAndColour) {
return ()->{
int[] imgSize = STBHelper.loadTextureFromClasspath(textureFileName, size, GL_TEXTURE0 + textureNumber + INDEX_TEXTURE_OFFSET);
return (bb, ctx, frame) -> {
ctx.elementShader().updateTextureUniform(textureNumber + INDEX_TEXTURE_OFFSET);
ctx.elementShader().updateRenderTypeUniform(ElementShader.RenderType.TEXTURE);
renderTexture(bb, ctx, frame, imgSize, positionAndColour);
};
};
}
@@ -280,13 +281,21 @@ public class RenderElement {
bb.draw();
}
@Deprecated(since = "1.21.5", forRemoval = true)
public static float clamp(float num, float min, float max) {
return Math.clamp(num, min, max);
if (num < min) {
return min;
} else {
return Math.min(num, max);
}
}
public static int clamp(int num, int min, int max) {
return Math.min(max, Math.max(num, min));
if (num < min) {
return min;
} else {
return Math.min(num, max);
}
}
public static int hsvToRGB(float hue, float saturation, float value) {
@@ -22,7 +22,7 @@ public class SimpleFont {
private final int textureNumber;
private final int lineSpacing;
private final int descent;
private static final int GLYPH_COUNT = 127 - 32;
private final int GLYPH_COUNT = 127-32;
private final Glyph[] glyphs;
private record Glyph(char c, int charwidth, int[] pos, float[] uv) {
@@ -120,7 +120,7 @@ public class SimpleFont {
case '\n', '\t' -> 0;
case ' ' -> glyphs[0].charwidth();
default -> {
if (c - 32 < GLYPH_COUNT && c > 32) {
if (c - 32 < this.GLYPH_COUNT && c > 32) {
yield this.glyphs[c - 32].charwidth();
} else {
yield 0;
@@ -151,7 +151,7 @@ public class SimpleFont {
case '\t' -> new Pos(pos.x()+font.glyphs[0].charwidth() * 4, pos.y(), pos.minx());
case ' ' -> new Pos(pos.x()+font.glyphs[0].charwidth(), pos.y(), pos.minx());
default -> {
if (c-32 < GLYPH_COUNT && c > 32) {
if (c-32 < font.GLYPH_COUNT && c > 32) {
pos = font.glyphs[c - 32].loadQuad(pos, colour(), bb);
}
yield pos;
+3 -23
View File
@@ -5,7 +5,6 @@ plugins {
id 'maven-publish'
id 'net.minecraftforge.licenser'
id 'net.minecraftforge.gradleutils'
alias(libs.plugins.apt)
}
apply from: rootProject.file('build_shared.gradle')
@@ -13,7 +12,7 @@ apply from: rootProject.file('build_shared.gradle')
configurations.forEach{ it.transitive = false }
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
api(libs.bundles.asm) // Needed by all the black magic
api(libs.forgespi)
@@ -37,11 +36,10 @@ dependencies {
implementation(libs.terminalconsoleappender)
implementation(libs.jimfs)
// 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)
testCompileOnly(libs.nulls)
testRuntimeOnly(libs.bootstrap)
}
@@ -87,7 +85,7 @@ publishing {
license PomUtils.Licenses.LGPLv2_1
}
}
repositories {
maven gradleutils.publishingForgeMaven
}
@@ -104,23 +102,5 @@ tasks.register('writeForgeVersionJson') {
}
tasks.named('generateResources').configure {
dependsOn('eclipseJdt')
dependsOn('eclipseJdtApt')
dependsOn('eclipseFactorypath')
dependsOn('writeForgeVersionJson')
}
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'
}
}
}
}
@@ -10,8 +10,6 @@ import java.util.List;
import java.util.stream.Collectors;
import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.loading.LoadingModList;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -49,14 +47,9 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
private static final class LazyInit {
private LazyInit() {}
private static final boolean ANY_MODS = LoadingModList.get().getMods().size() > 2; // 2: forge, minecraft
}
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty || !LazyInit.ANY_MODS)
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
@@ -75,11 +68,6 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
if (!classNode.interfaces.contains(MARKER_IFACE.getInternalName()))
return ComputeFlags.NO_REWRITE;
if (!classNode.name.startsWith("net/minecraft/")) {
LOGGER.warn("IExtensibleEnum found on non-Minecraft class: {}", classType.getClassName());
LOGGER.warn("This behaviour is deprecated for removal and will have no effect in a future MC release. Please use a record with static final field instances instead.");
}
Type array = Type.getType("[" + classType.getDescriptor());
String arrayDesc = array.getDescriptor();
@@ -6,13 +6,14 @@
package net.minecraftforge.fml.loading;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class BackgroundWaiter {
private static final ExecutorService runner = Executors.newSingleThreadExecutor();
public static void runAndTick(Runnable r, Runnable tick) {
var runner = Executors.newSingleThreadExecutor();
ImmediateWindowHandler.updateProgress("Loading bootstrap resources");
final Future<?> work = runner.submit(r);
do {
@@ -56,6 +56,7 @@ public class FMLLoader {
checkPackage(ITransformationService.class, "4.0", "ModLauncher");
accessTransformer = getPlugin(env, "accesstransformer", "1.0", "AccessTransformer");
/*eventBus =*/ getPlugin(env, "eventbus", "1.0", "EventBus");
runtimeDistCleaner = getPlugin(env, "runtimedistcleaner", "1.0", "RuntimeDistCleaner");
coreModProvider = getSingleService(ICoreModProvider.class, "CoreMod");
LOGGER.debug(CORE, "FML found CoreMod version : {}", JarVersionLookupHandler.getInfo(coreModProvider.getClass()).impl().version().orElse("MISSING"));
@@ -174,7 +175,7 @@ public class FMLLoader {
}
public static void addAccessTransformer(Path atPath, ModFile modName) {
LOGGER.debug(SCAN, "Adding Access Transformer {} in {}", atPath, modName.getFilePath());
LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
accessTransformer.offerResource(atPath, modName.getFileName());
}
@@ -7,6 +7,7 @@ package net.minecraftforge.fml.loading;
import com.mojang.logging.LogUtils;
import cpw.mods.modlauncher.api.*;
import joptsimple.OptionSpecBuilder;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.forgespi.Environment;
import org.jetbrains.annotations.NotNull;
@@ -18,6 +19,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class FMLServiceProvider implements ITransformationService {
@@ -5,13 +5,11 @@
package net.minecraftforge.fml.loading;
import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.locating.IModFile;
import org.slf4j.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -26,7 +24,6 @@ import java.util.stream.Collectors;
* loading package</em>
*/
public class LoadingModList {
private static final Logger LOGGER = LogUtils.getLogger();
private static LoadingModList INSTANCE;
private final List<ModFileInfo> modFiles;
private final List<ModInfo> sortedList;
@@ -70,22 +67,13 @@ public class LoadingModList {
}
public void addAccessTransformers() {
var errors = new ArrayList<EarlyLoadingException.ExceptionData>();
for (ModFileInfo modFile : modFiles) {
ModFile mod = modFile.getFile();
for (Path at : mod.getAccessTransformers()) {
if (!Files.exists(at)) {
var message = "Invalid mod file: " + modFile.getFile().getFileName() + ". Missing Access Transformer: " + at;
errors.add(new EarlyLoadingException.ExceptionData(message));
LOGGER.error(message);
} else {
FMLLoader.addAccessTransformer(at, mod);
}
var at = mod.getAccessTransformer().orElse(null);
if (at != null) {
FMLLoader.addAccessTransformer(at, mod);
}
}
if (!errors.isEmpty()) {
preLoadErrors.add(new EarlyLoadingException("Invalid Access Transformers", null, errors));
}
}
public void addForScanning(BackgroundScanHandler backgroundScanHandler) {
@@ -40,25 +40,6 @@ public final class RuntimeDistCleaner implements ILaunchPluginService {
return "runtimedistcleaner";
}
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
if (internalName.startsWith("net/minecraftforge/"))
return NAY;
// No Vanilla classes use @OnlyIn(Dist.SERVER), so we can skip them entirely when we're running on a client
if (FMLEnvironment.dist.isClient() && (internalName.startsWith("net/minecraft/") || internalName.startsWith("com/mojang/")))
return NAY;
return YAY;
}
@Override
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason) {
var changed = false;
@@ -217,6 +198,25 @@ public final class RuntimeDistCleaner implements ILaunchPluginService {
};
}
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
if (internalName.startsWith("net/minecraftforge/"))
return NAY;
// No Vanilla classes use @OnlyIn(Dist.SERVER), so we can skip them entirely when we're running on a client
if (FMLEnvironment.dist.isClient() && (internalName.startsWith("net/minecraft/") || internalName.startsWith("com/mojang/")))
return NAY;
return YAY;
}
private static class LambdaGatherer extends MethodVisitor {
private static final Handle META_FACTORY = new Handle(Opcodes.H_INVOKESTATIC,
"java/lang/invoke/LambdaMetafactory", "metafactory",
@@ -18,7 +18,9 @@ import org.apache.logging.log4j.util.PerformanceSensitive;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A wrapper for {@link HighlightConverter} that auto-disables ANSI when the terminal doesn't support it.
@@ -9,6 +9,7 @@ import cpw.mods.modlauncher.api.LamdbaExceptionUtils.Supplier_WithExceptions;
import net.minecraftforge.fml.loading.StringUtils;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.stream.Stream;
@@ -43,10 +43,10 @@ public final class MinecraftLocator extends AbstractModProvider implements IModL
mods.set("modId", "minecraft");
mods.set("version", FMLLoader.versionInfo().mcVersion());
mods.set("displayName", "Minecraft");
//mods.set("logoFile", "mcplogo.png");
//mods.set("credits", "Mojang, deobfuscated by MCP");
//mods.set("authors", "MCP: Searge,ProfMobius,IngisKahn,Fesh0r,ZeuX,R4wk,LexManos,Bspkrs");
mods.set("description", "The base Minecraft game, published by Mojang decompiled and deobfuscated by Forge");
mods.set("logoFile", "mcplogo.png");
mods.set("credits", "Mojang, deobfuscated by MCP");
mods.set("authors", "MCP: Searge,ProfMobius,IngisKahn,Fesh0r,ZeuX,R4wk,LexManos,Bspkrs");
mods.set("description", "Minecraft, decompiled and deobfuscated with MCP technology");
conf.set("mods", List.of(mods));
var configWrapper = new NightConfigWrapper(conf);
@@ -39,18 +39,18 @@ import java.util.jar.Manifest;
public class ModFile implements IModFile {
private static final Logger LOGGER = LogUtils.getLogger();
private final String jarVersion;
private final ModFileFactory.ModFileInfoParser parser;
private Map<String, Object> fileProperties;
private List<IModLanguageProvider> loaders;
private Throwable scanError;
private final SecureJar jar;
private final Type modFileType;
private final IModProvider provider;
private final IModFileInfo modFileInfo;
private IModFileInfo modFileInfo;
private ModFileScanData fileModFileScanData;
private CompletableFuture<ModFileScanData> futureScanResult;
private List<CoreModFile> coreMods;
private Path accessTransformer;
private List<Path> accessTransformers = Collections.emptyList();
static final Attributes.Name TYPE = new Attributes.Name("FMLModType");
private SecureJar.Status securityStatus;
@@ -62,11 +62,12 @@ public class ModFile implements IModFile {
public ModFile(final SecureJar jar, final IModProvider provider, final ModFileFactory.ModFileInfoParser parser, String type) {
this.provider = provider;
this.jar = jar;
this.parser = parser;
var manifest = this.jar.moduleDataProvider().getManifest();
modFileType = Type.valueOf(type);
jarVersion = Optional.ofNullable(manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION)).orElse("0.0NONE");
this.modFileInfo = ModFileParser.readModList(this, parser);
this.modFileInfo = ModFileParser.readModList(this, this.parser);
}
@Override
@@ -93,46 +94,17 @@ public class ModFile implements IModFile {
return modFileInfo.getMods();
}
/** @deprecated Use {@link #getAccessTransformers()} instead*/
@Deprecated(forRemoval=true, since="1.21.11")
public Optional<Path> getAccessTransformer() {
return Optional.ofNullable(accessTransformer);
}
public List<Path> getAccessTransformers() {
return accessTransformers;
return Optional.ofNullable(Files.exists(accessTransformer) ? accessTransformer : null);
}
public boolean identifyMods() {
this.modFileInfo = ModFileParser.readModList(this, this.parser);
if (this.modFileInfo == null) return this.getType() != Type.MOD;
LOGGER.debug(LogMarkers.LOADING,"Loading mod file {} with languages {}", this.getFilePath(), this.modFileInfo.requiredLanguageLoaders());
this.coreMods = ModFileParser.getCoreMods(this);
if (!this.coreMods.isEmpty())
LOGGER.warn("Mod file {} contains javascript coremods! JS CoreMods are deprecated and will be removed in a future release. Consider using Mixin or ModLauncher transformers.", this.getFileName());
for (var mi : this.coreMods)
LOGGER.debug(LogMarkers.LOADING, "Found coremod {}", mi.getPath());
List<String> cfg;
// Note: Some mods may have invalid tomls copied from other projects.
// Unfortunately we must protect against those landmines.
try {
cfg = this.modFileInfo.getConfig().<List<String>>getConfigElement("accessTransformers").orElse(null);
} catch (Exception e) {
cfg = null;
LOGGER.warn("{} contains an invalid 'accessTransformers' TOML entry. Should be e.g. accessTransformers = [\"META-INF/accesstransformer.cfg\", \"META-INF/extra_at.cfg\"] or accessTransformers = [] for no ATs. Falling back to default.", this.getFileName());
}
if (cfg == null) {
var path = findResource("META-INF", "accesstransformer.cfg");
if (Files.exists(path)) {
this.accessTransformer = path;
this.accessTransformers = List.of(path);
}
} else if (!cfg.isEmpty()) {
var paths = new ArrayList<Path>(cfg.size());
for (var path : cfg) {
paths.add(getSecureJar().getPath(path.replace("\\","/")));
}
this.accessTransformers = List.copyOf(paths);
}
this.coreMods.forEach(mi-> LOGGER.debug(LogMarkers.LOADING,"Found coremod {}", mi.getPath()));
this.accessTransformer = findResource("META-INF", "accesstransformer.cfg");
return true;
}
@@ -17,6 +17,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
@@ -81,10 +81,6 @@ class ArgumentList {
.toArray(String[]::new);
}
public boolean has(String key) {
return this.values.containsKey(key);
}
public boolean hasValue(String key) {
return getOrDefault(key, null) != null;
}
@@ -22,10 +22,6 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
super(type, prefix);
}
protected CommonDevLaunchHandler(String name) {
super(name);
}
@Override public String getNaming() { return "mcp"; }
@Override public boolean isProduction() { return false; }
@@ -33,35 +29,13 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
protected String[] preLaunch(String[] arguments, ModuleLayer layer) {
super.preLaunch(arguments, layer);
var args = ArgumentList.from(arguments);
if (this.module == null) {
var entry = args.get("launchEntry");
if (entry == null)
throw new IllegalArgumentException("When using " + this.name() + " launch target you must specify a --launchEntry argument");
args.remove("launchEntry");
int idx = entry.indexOf('/');
if (idx == -1) {
this.module = "minecraft";
this.main = entry;
} else {
this.module = entry.substring(0, idx);
this.main = entry.substring(idx + 1);
}
if (args.has("launchData")) {
args.remove("launchData");
this.isData = true;
}
}
if (getDist().isDedicatedServer())
return args.getArguments();
return arguments;
if (isData())
return args.getArguments();
return arguments;
var args = ArgumentList.from(arguments);
String username = args.get("username");
if (username != null) { // Replace '#' placeholders with random numbers
@@ -29,27 +29,17 @@ import java.util.List;
public abstract class CommonLaunchHandler implements ILaunchHandlerService {
protected static final Logger LOGGER = LogUtils.getLogger();
private final String name;
protected Dist dist = Dist.CLIENT;
protected boolean isData = false;
protected String module;
protected String main;
protected final LaunchType type;
private final String prefix;
protected CommonLaunchHandler(LaunchType type, String prefix) {
this(prefix + type.name());
this.dist = type.dist();
this.isData = type.data();
this.module = type.module();
this.main = type.main();
this.type = type;
this.prefix = prefix;
}
protected CommonLaunchHandler(String name) {
this.name = name;
}
@Override public String name() { return this.name; }
public Dist getDist() { return this.dist; }
public boolean isData() { return this.isData; }
@Override public String name() { return this.prefix + this.type.name(); }
public Dist getDist() { return this.type.dist(); }
public boolean isData() { return this.type.data(); }
public boolean isProduction() { return false; }
public abstract String getNaming();
@@ -76,15 +66,14 @@ public abstract class CommonLaunchHandler implements ILaunchHandlerService {
}
protected ServiceRunner makeService(final String[] arguments, final ModuleLayer gameLayer) {
return () -> runTarget(this.module, this.main, arguments, gameLayer);
return () -> runTarget(this.type.module(), this.type.main(), arguments, gameLayer);
}
protected record LaunchType(String name, String module, String main, Dist dist, boolean data) {};
protected static final LaunchType CLIENT = new LaunchType("client", "minecraft", "net.minecraft.client.main.Main", Dist.CLIENT, false);
protected static final LaunchType CLIENT_DATA = new LaunchType("client_data", "minecraft", "net.minecraft.client.data.Main", Dist.CLIENT, true);
protected static final LaunchType DATA = new LaunchType("data", "minecraft", "net.minecraft.data.Main", Dist.CLIENT, true);
protected static final LaunchType SERVER = new LaunchType("server", "minecraft", "net.minecraft.server.Main", Dist.DEDICATED_SERVER, false);
protected static final LaunchType SERVER_GAMETEST = new LaunchType("server_gametest", "minecraft", "net.minecraft.gametest.Main", Dist.DEDICATED_SERVER, false);
protected static final LaunchType SERVER_GAMETEST = new LaunchType("server_gametest", "net.minecraftforge.forge", "net.minecraftforge.gametest.GameTestMain", Dist.DEDICATED_SERVER, false);
protected void runTarget(String module, String target, final String[] arguments, final ModuleLayer layer) throws Throwable {
var mod = layer.findModule(module).orElse(null);
@@ -14,14 +14,12 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
super(type, "forge_dev_");
}
private ForgeDevLaunchHandler(String name) {
super(name);
}
@Override
public List<Path> getMinecraftPaths() {
// The client extra jar is on the classpath we can try locating it using the .mcassetsroot which vanilla uses for loading data
var extra = getPathFromResource("assets/.mcassetsroot");
// The extra jar is on the classpath, so try and pull it out of the legacy classpath
var legacyCP = findClassPath();
var extra = findJarOnClasspath(legacyCP, "client-extra");
// Minecraft is an exploded directory, so find it.
var minecraft = getPathFromResource("net/minecraft/client/Minecraft.class");
var forge = getPathFromResource("net/minecraftforge/common/MinecraftForge.class");
@@ -41,12 +39,6 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
}
}
public static final class ClientData extends ForgeDevLaunchHandler {
public ClientData() {
super(CLIENT_DATA);
}
}
public static final class Data extends ForgeDevLaunchHandler {
public Data() {
super(DATA);
@@ -64,10 +56,4 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
super(SERVER_GAMETEST);
}
}
public static final class Custom extends ForgeDevLaunchHandler {
public Custom() {
super("forge_dev");
}
}
}
@@ -96,14 +96,14 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
// Find resource directories for every mod in this group
var paths = new LinkedHashSet<Path>();
for (var modid : modids.stream().sorted().toList()) {
for (var modid : modids) {
var rsc = path.resolve(modid);
if (Files.exists(rsc))
paths.add(rsc);
}
var root = memory.getPath(modids.iterator().next()); // use the first modid as our root
buildModsToml(paths, modids, root, pkg.startsWith("net/minecraftforge/debug/client/"));
buildModsToml(paths, modids, root);
buildPackMeta(paths, root);
moveModuleInfo(paths, root);
@@ -187,7 +187,7 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
}
// Builds or update the mods.toml file for all @Mods in this package
private static void buildModsToml(Set<Path> resources, Set<String> modids, Path root, boolean clientOnly) {
private static void buildModsToml(Set<Path> resources, Set<String> modids, Path root) {
var toml = resources.stream()
.map(p -> p.resolve(MODS_TOML))
.filter(Files::exists)
@@ -205,8 +205,7 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
var defaults = Map.of(
"modLoader", "javafml",
"loaderVersion", "[0,)",
"license", "Doesnt fucking matter",
"clientSideOnly", clientOnly
"license", "Doesnt fucking matter"
);
for (var key : defaults.keySet()) {
@@ -8,18 +8,17 @@ package net.minecraftforge.fml.loading.targets;
import net.minecraftforge.fml.loading.FMLLoader;
import java.nio.file.Path;
import java.util.List;
import java.util.function.BiPredicate;
import org.jetbrains.annotations.ApiStatus;
import cpw.mods.jarhandling.SecureJar;
@ApiStatus.Internal
sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
private ForgeUserdevLaunchHandler(LaunchType type) {
super(type, "forge_userdev_");
}
private ForgeUserdevLaunchHandler(String name) {
super(name);
}
@Override
public List<Path> getMinecraftPaths() {
var legacyCP = findClassPath();
@@ -27,7 +26,7 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
// Minecraft is extra jar {resources} + forge jar {patches}
// The MC extra and forge jars are on the classpath, so try and pull them out
var extra = findJarOnClasspath(legacyCP, "client-extra"); // This should be "client-" + vers.mcAndMCPVersion() + "-extra" but FG6 qwerks
var extra = findJarOnClasspath(legacyCP, "client-extra");
var forge = findJarOnClasspath(legacyCP, "forge-" + vers.mcAndForgeVersion());
// We need to filter the forge jar to just MC code
var minecraft = CommonDevLaunchHandler.getMinecraftOnly(extra, forge);
@@ -40,12 +39,6 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
}
}
public static final class ClientData extends ForgeUserdevLaunchHandler {
public ClientData() {
super(CLIENT_DATA);
}
}
public static final class Data extends ForgeUserdevLaunchHandler {
public Data() {
super(DATA);
@@ -63,10 +56,4 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
super(SERVER_GAMETEST);
}
}
public static final class Custom extends ForgeUserdevLaunchHandler {
public Custom() {
super("forge_userdev");
}
}
}
@@ -4,16 +4,12 @@ net.minecraftforge.fml.loading.targets.ForgeProdLaunchHandler$Server
# Mod Developers
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Client
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$ClientData
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Custom
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Data
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Server
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$ServerGameTest
#Working on Forge itself
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Client
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$ClientData
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Custom
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Data
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Server
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$ServerGameTest
+1 -1
View File
@@ -4,7 +4,7 @@
SPDX-License-Identifier: LGPL-2.1-only
-->
<Configuration status="warn" shutdownHook="disable">
<Configuration status="warn" packages="net.minecrell.terminalconsole,net.minecrell.terminalconsole.util,com.mojang.util,cpw.mods.modlauncher.log,net.minecraftforge.fml.loading.log4j" shutdownHook="disable">
<filters>
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<MarkerFilter marker="NETWORK_PACKETS" onMatch="${sys:forge.logging.marker.networking:-DENY}" onMismatch="NEUTRAL"/>
-73
View File
@@ -1,73 +0,0 @@
import net.minecraftforge.gradleutils.PomUtils
plugins {
id 'java-library'
id 'maven-publish'
id 'net.minecraftforge.licenser'
id 'net.minecraftforge.gradleutils'
alias(libs.plugins.apt)
}
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) // Used for ASMAPI (for now)
testCompileOnly(libs.jetbrains.annotations)
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION)
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
}
}
repositories {
maven gradleutils.publishingForgeMaven
}
}
@@ -1,78 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.forge.transformers;
import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.ITransformerVotingContext;
import cpw.mods.modlauncher.api.TransformerVoteResult;
import net.minecraftforge.coremod.api.ASMAPI;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.tree.ClassNode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
record FieldToMethodTransformer(String className, Map<String, String> fields) implements ITransformer<ClassNode> {
// TODO [Forge][Transformer] Make this properly data driven or configurable.
// It was hard-coded like this before when using JS CoreMods, though.
static final Map<String, Map<String, String>> TARGETS = Map.of(
"net.minecraft.world.level.biome.Biome",
Map.of(
"climateSettings", "getModifiedClimateSettings",
"specialEffects", "getModifiedSpecialEffects"
),
"net.minecraft.world.effect.MobEffectInstance",
Map.of(
"effect", "getEffect"
),
"net.minecraft.world.level.block.LiquidBlock",
Map.of(
"fluid", "getFluid"
),
"net.minecraft.world.item.BucketItem",
Map.of(
"content", "getFluid"
),
"net.minecraft.world.level.block.FlowerPotBlock",
Map.of(
"potted", "getPotted"
)
);
@SuppressWarnings("rawtypes")
static List<ITransformer> getAll() {
var ret = new ArrayList<ITransformer>(TARGETS.size());
for (var entry : TARGETS.entrySet()) {
ret.add(new FieldToMethodTransformer(entry.getKey(), entry.getValue()));
}
return ret;
}
@Override
public @NotNull ClassNode transform(ClassNode input, ITransformerVotingContext context) {
for (var entry : this.fields.entrySet()) {
ASMAPI.redirectFieldToMethod(input, entry.getKey(), entry.getValue());
}
return input;
}
@Override
public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) {
return TransformerVoteResult.YES;
}
@Override
public @NotNull Set<Target> targets() {
return Set.of(Target.targetClass(this.className));
}
}
@@ -1,35 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.forge.transformers;
import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.ITransformationService;
import cpw.mods.modlauncher.api.ITransformer;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public record ForgeModTransformers(String name) implements ITransformationService {
public ForgeModTransformers() {
this("forge");
}
@Override
public void initialize(IEnvironment environment) { }
@Override
public void onLoad(IEnvironment env, Set<String> otherServices) { }
@Override
@SuppressWarnings("rawtypes")
public @NotNull List<ITransformer> transformers() {
List<ITransformer> transformers = FieldToMethodTransformer.getAll();
transformers.add(new MethodRedirector());
return transformers;
}
}
@@ -1,142 +0,0 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.forge.transformers;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.ITransformerVotingContext;
import cpw.mods.modlauncher.api.TransformerVoteResult;
import net.minecraftforge.coremod.api.ASMAPI;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodInsnNode;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
// NOTE: THIS IS A SINGLETON!
record MethodRedirector() implements ITransformer<ClassNode> {
private static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = new Gson();
private static final Replacement[] REPLACEMENTS = {
new Replacement(
// finalizeSpawn redirection to ForgeEventFactory.onFinalizeSpawn
ASMAPI.MethodType.VIRTUAL,
"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 -> ASMAPI.buildMethodCall(
ASMAPI.MethodType.STATIC,
"net/minecraftforge/event/ForgeEventFactory",
"onFinalizeSpawn",
"(Lnet/minecraft/world/entity/Mob;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;"
)
)
};
private static <T> T sneak(Callable<T> callable) {
try {
return callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
record Replacement(
ASMAPI.MethodType type,
String name,
String desc,
Target[] targets,
UnaryOperator<MethodInsnNode> factory
) { }
record Target(
@SerializedName("class") String className,
String[] methods
) { }
@Override
public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) {
return TransformerVoteResult.YES;
}
@Override
public @NotNull Set<ITransformer.Target> targets() {
return Arrays
.stream(REPLACEMENTS)
.map(Replacement::targets)
.flatMap(Arrays::stream)
.map(Target::className)
.map(ITransformer.Target::targetClass)
.collect(Collectors.toUnmodifiableSet());
}
@Override
public @NotNull ClassNode transform(ClassNode clazz, ITransformerVotingContext context) {
for (var replacement : REPLACEMENTS) {
for (var methodString : getClassTargetMethods(clazz, replacement)) {
// cut up the string since we've put both the name and desc as the target
var splitPos = methodString.indexOf('(');
var methodName = methodString.substring(0, splitPos);
var methodDesc = methodString.substring(splitPos);
var method = ASMAPI.findMethodNode(clazz, methodName, methodDesc);
if (method == null) {
LOGGER.error("Failed to redirect method call for {}! Method {} not found in class {}! This is a Forge bug, and is likely due to a Minecraft update changing something.", replacement.name, methodString, clazz.name);
continue;
}
for (var insn : method.instructions) {
if (!shouldReplace(insn, replacement)) continue;
var methodInsn = (MethodInsnNode) insn;
var redirection = replacement.factory.apply(methodInsn);
LOGGER.debug("Redirecting method call {}{} to {}{} inside of {}.{}", methodInsn.name, methodInsn.desc, redirection.name, redirection.desc, clazz.name, method.name);
ASMAPI.insertInsn(method, methodInsn, redirection, ASMAPI.InsertMode.REMOVE_ORIGINAL);
}
}
}
return clazz;
}
private static boolean shouldReplace(AbstractInsnNode insn, Replacement replacement) {
return insn.getOpcode() == replacement.type.toOpcode()
&& replacement.name.equals(((MethodInsnNode) insn).name)
&& replacement.desc.equals(((MethodInsnNode) insn).desc);
}
private static List<String> getClassTargetMethods(ClassNode clazz, Replacement replacement) {
for (var t : replacement.targets) {
if (!t.className.equals(clazz.name)) continue;
// declared methods
var targets = new ArrayList<>(Arrays.asList(t.methods));
// synthetic methods
for (var method : clazz.methods) {
if ((method.access & Opcodes.ACC_SYNTHETIC) != 0)
targets.add(method.name + method.desc);
}
return targets;
}
return List.of();
}
}
@@ -1 +0,0 @@
net.minecraftforge.forge.transformers.ForgeModTransformers
+7 -7
View File
@@ -1,17 +1,17 @@
# 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.jvmargs=-Xmx3G
org.gradle.daemon=false
org.gradle.parallel=true
JAVA_VERSION=21
MC_VERSION=1.21.8
MC_VERSION=1.21.3
MC_NEXT_VERSION=1.22
MCP_VERSION=20250717.105350
MCP_VERSION=20241025.112443
MAPPING_CHANNEL=official
MAPPING_VERSION=1.21.8
MAPPING_VERSION=1.21.3
# Set to true before the first build of a new MC version, so we don't do compatibility checks
// 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
// Set to true to allow for fuzzy patching. Useful during updateing
UPDATING=false
+1 -1
View File
@@ -10,7 +10,7 @@ plugins {
apply from: rootProject.file('build_shared.gradle')
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
implementation(project(':fmlloader'))
implementation(project(':fmlcore'))
implementation(libs.unsafe)
@@ -12,10 +12,9 @@ import java.lang.annotation.Target;
import java.util.function.Supplier;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.Bindings;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.jspecify.annotations.Nullable;
/**
* This defines a Mod to FML.
@@ -25,11 +24,12 @@ import org.jspecify.annotations.Nullable;
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Mod {
public @interface Mod
{
/**
* The unique mod identifier for this mod.
* <b>Required to be lowercased in the English locale for compatibility. Will be truncated to 64 characters long.</b>
* <br>
* <b>Required to be lowercased in the english locale for compatibility. Will be truncated to 64 characters long.</b>
*
* This will be used to identify your mod for third parties (other mods), it will be used to identify your mod for registries such as block and item registries.
* By default, you will have a resource domain that matches the modid. All these uses require that constraints are imposed on the format of the modid.
*/
@@ -61,40 +61,32 @@ public @interface Mod {
String modid() default "";
/**
* Specify an alternative bus to listen to.
* <br>
* If you know all listeners in this class are for a specific bus, you can set it here to speed up registration.
* Specify an alternative bus to listen to
*
* @return the bus you wish to listen to
*/
Bus bus() default Bus.BOTH;
Bus bus() default Bus.FORGE;
enum Bus {
/**
* The main BusGroup that most game events are fired on.
* The main Forge Event Bus.
*
* <p>See {@code MinecraftForge#EVENT_BUS}</p>
*/
FORGE(Bindings.getForgeBus()),
/**
* The mod-specific event BusGroup, usually for mod lifecycle events.
* @see FMLJavaModLoadingContext#getModBusGroup()
* The mod specific Event bus.
* @see FMLJavaModLoadingContext#getModEventBus()
*/
MOD(()-> FMLJavaModLoadingContext.get().getModBusGroup()),
MOD(()-> FMLJavaModLoadingContext.get().getModEventBus());
/**
* Both the {@link #FORGE} and {@link #MOD} buses. This is slower to register events in your class but
* allows you to listen to events from different BusGroup types without needing separate classes annotated
* with {@link EventBusSubscriber}.
*/
BOTH(() -> null);
private final Supplier<IEventBus> busSupplier;
private final Supplier<@Nullable BusGroup> busSupplier;
Bus(Supplier<@Nullable BusGroup> eventBusSupplier) {
Bus(final Supplier<IEventBus> eventBusSupplier) {
this.busSupplier = eventBusSupplier;
}
public Supplier<@Nullable BusGroup> bus() {
public Supplier<IEventBus> bus() {
return busSupplier;
}
}
@@ -7,40 +7,22 @@ package net.minecraftforge.fml.javafmlmod;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.bus.CancellableEventBus;
import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.api.event.characteristic.Cancellable;
import net.minecraftforge.eventbus.api.listener.EventListener;
import net.minecraftforge.eventbus.api.listener.ObjBooleanBiConsumer;
import net.minecraftforge.eventbus.api.listener.Priority;
import net.minecraftforge.eventbus.api.listener.SubscribeEvent;
import net.minecraftforge.eventbus.internal.Event;
import net.minecraftforge.fml.Logging;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.forgespi.language.ModFileScanData;
import net.minecraftforge.forgespi.language.ModFileScanData.AnnotationData;
import net.minecraftforge.forgespi.language.ModFileScanData.EnumData;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.unsafe.UnsafeHacks;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jspecify.annotations.Nullable;
import org.objectweb.asm.Type;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -53,8 +35,6 @@ public class AutomaticEventSubscriber {
private static final Type AUTO_SUBSCRIBER = Type.getType(EventBusSubscriber.class);
private static final Type MOD_TYPE = Type.getType(Mod.class);
private static final Type ONLY_IN_TYPE = Type.getType(OnlyIn.class);
private static final List<EnumData> DEFAULT_SIDES = List.of(new EnumData(null, "CLIENT"), new EnumData(null, "DEDICATED_SERVER"));
private static final EnumData DEFAULT_BUS = new EnumData(null, "BOTH");
public static void inject(ModContainer mod, ModFileScanData scanData, ClassLoader loader) {
if (scanData == null) return;
@@ -73,6 +53,9 @@ public class AutomaticEventSubscriber {
.filter(data -> MOD_TYPE.equals(data.annotationType()))
.collect(Collectors.toMap(a -> a.clazz().getClassName(), a -> (String)a.annotationData().get("value")));
var defaultSides = List.of(new EnumData(null, "CLIENT"), new EnumData(null, "DEDICATED_SERVER"));
var defaultBus = new EnumData(null, "FORGE");
for (var data : targets) {
if (!FMLEnvironment.production && onlyIns.contains(data.clazz().getClassName())) {
throw new RuntimeException("Found @OnlyIn on @EventBusSubscriber class " + data.clazz().getClassName() + " - this is not allowed as it causes crashes. Remove the OnlyIn and set value=Dist.CLIENT in the EventBusSubscriber annotation instead");
@@ -81,18 +64,18 @@ public class AutomaticEventSubscriber {
var modId = modids.getOrDefault(data.clazz().getClassName(), mod.getModId());
modId = value(data, "modid", modId);
var sidesValue = value(data, "value", DEFAULT_SIDES);
var sidesValue = value(data, "value", defaultSides);
var sides = sidesValue.stream()
.map(EnumData::value)
.map(Dist::valueOf)
.collect(Collectors.toSet());
var busName = value(data, "bus", DEFAULT_BUS).value();
var busName = value(data, "bus", defaultBus).value();
var busTarget = Bus.valueOf(busName);
if (Objects.equals(mod.getModId(), modId) && sides.contains(FMLEnvironment.dist)) {
try {
LOGGER.debug(Logging.LOADING, "Auto-subscribing {} to {}", data.clazz().getClassName(), busTarget);
EventBusSubscriberLogic.register(busTarget.bus().get(), Class.forName(data.clazz().getClassName(), true, loader));
busTarget.bus().get().register(Class.forName(data.clazz().getClassName(), true, loader));
} catch (ClassNotFoundException e) {
LOGGER.fatal(Logging.LOADING, "Failed to load mod class {} for @EventBusSubscriber annotation", data.clazz(), e);
throw new RuntimeException(e);
@@ -105,333 +88,4 @@ public class AutomaticEventSubscriber {
private static <R> R value(AnnotationData data, String key, R value) {
return (R)data.annotationData().getOrDefault(key, value);
}
/**
* This is mostly a carbon copy of EventBus 7's internal EventListenerFactory, with some changes to support adding
* to different BusGroups based on the event type, among other things.
*/
private static final class EventBusSubscriberLogic {
private EventBusSubscriberLogic() {}
private static final boolean STRICT_RUNTIME_CHECKS = Boolean.getBoolean("eventbus.api.strictRuntimeChecks");
/**
* If true, performs exhaustive validation on bulk registration to aid debugging.
*/
private static final boolean STRICT_REGISTRATION_CHECKS = STRICT_RUNTIME_CHECKS || Boolean.getBoolean("eventbus.api.strictRegistrationChecks");
private static final MethodType RETURNS_CONSUMER = MethodType.methodType(Consumer.class);
private static final MethodType RETURNS_PREDICATE = MethodType.methodType(Predicate.class);
private static final MethodType RETURNS_MONITOR = MethodType.methodType(ObjBooleanBiConsumer.class);
/** The method type of the {@link Consumer} functional interface ({@code void accept(Object)}) */
private static final MethodType CONSUMER_FI_TYPE = MethodType.methodType(void.class, Object.class);
/** The method type of the {@link Predicate} functional interface ({@code boolean test(Object)}) */
private static final MethodType PREDICATE_FI_TYPE = CONSUMER_FI_TYPE.changeReturnType(boolean.class);
/** The method type of the {@link ObjBooleanBiConsumer} functional interface ({@code void accept(Object, boolean)}) */
private static final MethodType MONITOR_FI_TYPE = MethodType.methodType(void.class, Object.class, boolean.class);
public static void register(@Nullable BusGroup busGroup, Class<?> listenerClass) {
if (STRICT_REGISTRATION_CHECKS) registerStrict(busGroup, listenerClass);
else registerLenient(busGroup, listenerClass);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static void registerLenient(@Nullable BusGroup busGroup, Class<?> listenerClass) {
Method[] declaredMethods = listenerClass.getDeclaredMethods();
if (declaredMethods.length == 0)
throw new IllegalArgumentException("No declared methods found in " + listenerClass);
Class<?> firstValidListenerEventType = null;
int listenersCount = 0;
for (var method : declaredMethods) {
if (!Modifier.isStatic(method.getModifiers()))
continue;
if (method.isSynthetic())
continue; // EventBus#89
int paramCount = method.getParameterCount();
if (paramCount == 0 || paramCount > 2)
continue;
Class<?> returnType = method.getReturnType();
if (returnType != void.class && returnType != boolean.class)
continue;
if (!method.isAnnotationPresent(SubscribeEvent.class))
continue;
Class<?>[] parameterTypes = method.getParameterTypes();
if (!Event.class.isAssignableFrom(parameterTypes[0]))
throw new IllegalArgumentException("First parameter of a @SubscribeEvent method must be an event");
Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
var subscribeEventAnnotation = method.getAnnotation(SubscribeEvent.class);
registerListener(busGroup, paramCount, returnType, eventType, subscribeEventAnnotation, method, false);
listenersCount++;
if (firstValidListenerEventType == null)
firstValidListenerEventType = eventType;
}
if (listenersCount == 0)
throw new IllegalArgumentException("No listeners found in " + listenerClass);
else if (firstValidListenerEventType == null)
throw new IllegalArgumentException("No valid listeners found in " + listenerClass);
}
@SuppressWarnings({"unchecked"})
public static void registerStrict(BusGroup busGroup, Class<?> listenerClass) {
Class<? extends Event> firstValidListenerEventType = null;
List<Method> declaredMethods = Arrays.stream(listenerClass.getDeclaredMethods())
.filter(Predicate.not(Method::isSynthetic)) // EventBus#89
.toList();
if (declaredMethods.isEmpty()) {
var errMsg = "No declared methods found in " + listenerClass.getName();
var superClass = listenerClass.getSuperclass();
if (superClass != null && superClass != Record.class && superClass != Enum.class) {
errMsg += ". Note that listener inheritance is not supported. " +
"If you are trying to inherit listeners, please use @Override and @SubscribeEvent on the method in the subclass.";
}
throw fail(listenerClass, errMsg);
}
int listenersCount = 0;
for (var method : declaredMethods) {
var hasSubscribeEvent = method.isAnnotationPresent(SubscribeEvent.class);
int paramCount = method.getParameterCount();
if (hasSubscribeEvent && (paramCount == 0 || paramCount > 2))
throw fail(method, "Invalid number of parameters: " + paramCount + " (expected 1 or 2)");
if (paramCount == 0)
continue;
Class<?> returnType = method.getReturnType();
Class<?>[] parameterTypes = method.getParameterTypes();
var firstParamExtendsEvent = Event.class.isAssignableFrom(parameterTypes[0]);
if (!hasSubscribeEvent && firstParamExtendsEvent)
throw fail(method, "Missing @SubscribeEvent annotation");
if (hasSubscribeEvent) {
var firstParamExtendsCancellable = Cancellable.class.isAssignableFrom(parameterTypes[0]);
var subscribeEventAnnotation = method.getAnnotation(SubscribeEvent.class);
var isMonitoringPriority = subscribeEventAnnotation.priority() == Priority.MONITOR;
if (!firstParamExtendsEvent)
throw fail(method, "First parameter of a @SubscribeEvent method must be an event");
var eventType = (Class<? extends Event>) parameterTypes[0];
if (returnType != void.class && returnType != boolean.class)
throw fail(method, "Invalid return type: " + returnType.getName() + " (expected void or boolean)");
if (!Modifier.isStatic(method.getModifiers()))
throw fail(method, "Listener method needs to be static");
if (isMonitoringPriority && (returnType == boolean.class || subscribeEventAnnotation.alwaysCancelling()))
throw fail(method, "Monitoring listeners cannot cancel events");
if (paramCount == 2) {
if (!firstParamExtendsCancellable)
throw fail(method, "Cancellation-aware monitoring listeners are only valid for cancellable events");
if (!boolean.class.isAssignableFrom(parameterTypes[1]))
throw fail(method, "Second parameter of a cancellation-aware monitoring listener must be a boolean");
if (!isMonitoringPriority)
throw fail(method, "Cancellation-aware monitoring listeners must have a priority of MONITOR");
}
if (!firstParamExtendsCancellable) {
if (subscribeEventAnnotation.alwaysCancelling())
throw fail(method, "Always cancelling listeners are only valid for cancellable events");
if (returnType == boolean.class)
throw fail(method, "Return type boolean is only valid for cancellable events");
}
registerListener(busGroup, paramCount, returnType, eventType, subscribeEventAnnotation, method, true);
listenersCount++;
if (firstValidListenerEventType == null)
firstValidListenerEventType = eventType;
}
}
if (listenersCount == 0)
throw fail(listenerClass, "No listeners found");
else if (firstValidListenerEventType == null)
throw fail(listenerClass, "No valid listeners found");
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static EventListener registerListener(@Nullable BusGroup busGroup,
int paramCount, Class<?> returnType, Class<? extends Event> eventType,
SubscribeEvent subscribeEventAnnotation, Method method, boolean strict) {
if (busGroup == null) {
busGroup = IModBusEvent.class.isAssignableFrom(eventType)
? FMLJavaModLoadingContext.get().getModBusGroup()
: BusGroup.DEFAULT;
} else if (strict) {
String solution = "To fix this, remove the bus param from your @EventBusSubscriber annotation or move this event listener to another class.";
var isDefaultBusGroup = busGroup == BusGroup.DEFAULT;
var isModBusEvent = IModBusEvent.class.isAssignableFrom(eventType);
if (isDefaultBusGroup && isModBusEvent) { // requested forge bus and has IModBusEvent
throw fail(method, "Event type " + eventType.getName()
+ " is on the mod BusGroup but you are asking to register it on the default BusGroup (BusGroup.DEFAULT/EventBusSubscriber.Bus.FORGE). "
+ solution);
} else if (!isDefaultBusGroup && !isModBusEvent) { // requested mod bus and does not have IModBusEvent
throw fail(method, "Event type " + eventType.getName()
+ " is on the default BusGroup but you are asking to register it on the mod BusGroup (context.getModBusGroup()/EventBusSubscriber.Bus.MOD). "
+ solution);
}
}
// determine the listener type from its parameters and return type
if (paramCount == 1) {
var priority = subscribeEventAnnotation.priority();
if (returnType == void.class) {
if (Cancellable.class.isAssignableFrom(eventType)) {
// Consumer<Event & Cancellable>
var eventBus = CancellableEventBus.create(busGroup, (Class) eventType);
if (subscribeEventAnnotation.alwaysCancelling()) {
return eventBus.addListener(priority, true, createConsumer(method));
} else {
return eventBus.addListener(priority, createConsumer(method));
}
} else {
// Consumer<Event>
return EventBus.create(busGroup, eventType)
.addListener(priority, createConsumer(method));
}
} else {
// Predicate<Event & EventCharacteristic.Cancellable>
if (!Cancellable.class.isAssignableFrom(eventType))
throw fail(method, "Return type boolean is only valid for cancellable events");
if (subscribeEventAnnotation.alwaysCancelling())
throw new IllegalArgumentException("Always cancelling listeners must have a void return type");
return CancellableEventBus.create(busGroup, (Class) eventType)
.addListener(priority, createPredicate(method));
}
} else {
// ObjBooleanBiConsumer<Event & Cancellable>
if (returnType != void.class)
throw new IllegalArgumentException("Cancellation-aware monitoring listeners must have a void return type");
if (subscribeEventAnnotation.alwaysCancelling())
throw new IllegalArgumentException("Monitoring listeners cannot cancel events");
return CancellableEventBus.create(busGroup, (Class) eventType).addListener(createMonitor(method));
}
}
private static IllegalArgumentException fail(Class<?> listenerClass, String reason) {
return new IllegalArgumentException("Failed to register " + listenerClass.getName() + ": " + reason);
}
private static IllegalArgumentException fail(Method mtd, String reason) {
return new IllegalArgumentException("Failed to register " + mtd.getDeclaringClass().getName() + "." + mtd.getName() + ": " + reason);
}
@SuppressWarnings("unchecked")
private static <T extends Event> Consumer<T> createConsumer(Method callback) {
var factoryMH = getOrMakeFactory(callback, RETURNS_CONSUMER, CONSUMER_FI_TYPE, "accept");
try {
return (Consumer<T>) factoryMH.invokeExact();
} catch (Exception e) {
throw makeRuntimeException(callback, e);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
@SuppressWarnings("unchecked")
private static <T extends Event> Predicate<T> createPredicate(Method callback) {
var factoryMH = getOrMakeFactory(callback, RETURNS_PREDICATE, PREDICATE_FI_TYPE, "test");
try {
return (Predicate<T>) factoryMH.invokeExact();
} catch (Exception e) {
throw makeRuntimeException(callback, e);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
@SuppressWarnings("unchecked")
private static <T extends Event> ObjBooleanBiConsumer<T> createMonitor(Method callback) {
var factoryMH = getOrMakeFactory(callback, RETURNS_MONITOR, MONITOR_FI_TYPE, "accept");
try {
return (ObjBooleanBiConsumer<T>) factoryMH.invokeExact();
} catch (Exception e) {
throw makeRuntimeException(callback, e);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
private static MethodHandle getOrMakeFactory(Method callback, MethodType factoryReturnType,
MethodType fiMethodType, String fiMethodName) {
return makeFactory(callback, factoryReturnType, fiMethodType, fiMethodName);
}
private static MethodHandle makeFactory(Method callback,
MethodType factoryReturnType,
MethodType fiMethodType, String fiMethodName) {
final class DodgyLookup {
private DodgyLookup() {}
private static final MethodHandles.Lookup INSTANCE;
static {
try {
var lookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
UnsafeHacks.setAccessible(lookupField);
INSTANCE = (MethodHandles.Lookup) lookupField.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
try {
var callbackDeclaredClass = callback.getDeclaringClass();
var lookup = DodgyLookup.INSTANCE.in(callbackDeclaredClass);
var mh = lookup.unreflect(callback);
return LambdaMetafactory.metafactory(
lookup, fiMethodName, factoryReturnType, fiMethodType, mh, mh.type()
).getTarget();
} catch (Exception e) {
throw makeRuntimeException(callback, e);
}
}
private static RuntimeException makeRuntimeException(Method callback, Exception e) {
return switch (e) {
case IllegalAccessException iae -> {
var errMsg = "Failed to create listener";
if (!Modifier.isPublic(callback.getModifiers()))
errMsg += " - is it public?";
yield new RuntimeException(errMsg, iae);
}
case NullPointerException npe -> new RuntimeException(
"Failed to create listener - was given a non-static method without an instance to invoke it with",
npe
);
default -> new RuntimeException("Failed to create listener", e);
};
}
}
}
@@ -5,13 +5,14 @@
package net.minecraftforge.fml.javafmlmod;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ModLoadingContext;
/**
* Use the context provided by your language loader in your mod's constructor
*/
public class FMLJavaModLoadingContext extends ModLoadingContext {
public class FMLJavaModLoadingContext extends ModLoadingContext
{
private final FMLModContainer container;
FMLJavaModLoadingContext(FMLModContainer container) {
@@ -19,10 +20,11 @@ public class FMLJavaModLoadingContext extends ModLoadingContext {
}
/**
* @return The mod's event bus group, to allow subscription to Mod specific events
* @return The mod's event bus, to allow subscription to Mod specific events
*/
public BusGroup getModBusGroup() {
return container.getModBusGroup();
public IEventBus getModEventBus()
{
return container.getEventBus();
}
/**
@@ -37,15 +39,9 @@ public class FMLJavaModLoadingContext extends ModLoadingContext {
* Helper to get the right instance from the {@link ModLoadingContext} correctly.
* @return The FMLJavaMod language specific extension from the ModLoadingContext
*
* @deprecated use {@link FMLJavaModLoadingContext} in your mod constructor. For example: {@snippet :
* @Mod("examplemod")
* public final class ExampleMod {
* public ExampleMod(FMLJavaModLoadingContext context) {
* // Use context from the param instead of FMLJavaModLoadingContext.get() or ModLoadingContext.get()
* }
* }}
* @deprecated use {@link FMLJavaModLoadingContext} in your mod constructor
*/
@Deprecated(forRemoval = true, since = "1.21.1")
@Deprecated(forRemoval = true, since="1.21.1")
public static FMLJavaModLoadingContext get() {
return ModLoadingContext.get().extension();
}
@@ -5,8 +5,11 @@
package net.minecraftforge.fml.javafmlmod;
import net.minecraftforge.eventbus.api.bus.BusGroup;
import net.minecraftforge.eventbus.api.bus.EventBus;
import net.minecraftforge.eventbus.EventBusErrorMessage;
import net.minecraftforge.eventbus.api.BusBuilder;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.IEventListener;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModLoadingException;
import net.minecraftforge.fml.ModLoadingStage;
@@ -33,7 +36,7 @@ public class FMLModContainer extends ModContainer {
private static final Logger LOGGER = LogManager.getLogger();
private static final Marker LOADING = MarkerManager.getMarker("LOADING");
private final ModFileScanData scanResults;
private final BusGroup eventBusGroup;
private final IEventBus eventBus;
private Object modInstance;
private final Class<?> modClass;
private final FMLJavaModLoadingContext context = new FMLJavaModLoadingContext(this);
@@ -43,7 +46,7 @@ public class FMLModContainer extends ModContainer {
LOGGER.debug(LOADING,"Creating FMLModContainer instance for {}", className);
this.scanResults = modFileScanResults;
activityMap.put(ModLoadingStage.CONSTRUCT, this::constructMod);
this.eventBusGroup = BusGroup.create("modBusFor" + info.getModId());
this.eventBus = BusBuilder.builder().setExceptionHandler(FMLModContainer::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
this.contextExtension = () -> context;
try {
var moduleName = info.getOwningFile().moduleName();
@@ -125,6 +128,10 @@ public class FMLModContainer extends ModContainer {
implAddExportsOrOpens.invoke(target, pkg, reader, open, /*syncVM*/true);
}
private static void onEventFailed(IEventBus iEventBus, Event event, IEventListener[] iEventListeners, int i, Throwable throwable) {
LOGGER.error(new EventBusErrorMessage(event, i, iEventListeners, throwable));
}
private void constructMod() {
try {
LOGGER.trace(LOADING, "Loading mod instance {} of type {}", getModId(), modClass.getName());
@@ -166,17 +173,15 @@ public class FMLModContainer extends ModContainer {
return modInstance;
}
public BusGroup getModBusGroup() {
return this.eventBusGroup;
public IEventBus getEventBus() {
return this.eventBus;
}
@Override
protected <T extends IModBusEvent> void acceptEvent(final T e) {
protected <T extends Event & IModBusEvent> void acceptEvent(final T e) {
try {
LOGGER.trace(LOADING, "Firing event for modid {} : {}", this.getModId(), e);
@SuppressWarnings("unchecked")
var eventBus = (EventBus<T>) IModBusEvent.getBus(eventBusGroup, e.getClass());
eventBus.post(e);
this.eventBus.post(e);
LOGGER.trace(LOADING, "Fired event for modid {} : {}", this.getModId(), e);
} catch (Throwable t) {
LOGGER.error(LOADING,"Caught exception during event {} dispatch for modid {}", e, this.getModId(), t);
@@ -185,14 +190,12 @@ public class FMLModContainer extends ModContainer {
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public void dispatchConfigEvent(IConfigEvent event) {
var eventBus = (EventBus) EventBus.create(eventBusGroup, event.self().getClass());
eventBus.post(event.self());
this.eventBus.post(event.self());
}
@Override
public String toString() {
return "FMLModContainer[" + this.getModInfo().getModId() + ", " + this.getClass().getName() + ']';
return "FMLModContainer[" + this.getModInfo().getModId() + ", " + this.getClass().getName() + "]";
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ java {
}
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
implementation(project(':fmlloader'))
implementation(project(':fmlcore'))
@@ -6,32 +6,41 @@
package net.minecraftforge.fml.lowcodemod;
import com.mojang.logging.LogUtils;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.IExtensionPoint;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.loading.LogMarkers;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.slf4j.Logger;
public class LowCodeModContainer extends ModContainer {
import java.util.Objects;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class LowCodeModContainer extends ModContainer
{
private static final Logger LOGGER = LogUtils.getLogger();
private final Object modInstance;
public LowCodeModContainer(IModInfo info, ModFileScanData modFileScanResults, ModuleLayer gameLayer) {
public LowCodeModContainer(IModInfo info, ModFileScanData modFileScanResults, ModuleLayer gameLayer)
{
super(info);
LOGGER.debug(LogMarkers.LOADING, "Creating LowCodeModContainer for {}", info.getModId());
LOGGER.debug(LOADING, "Creating LowCodeModContainer for {}", info.getModId());
this.modInstance = new Object();
this.contextExtension = () -> null;
this.extensionPoints.remove(IExtensionPoint.DisplayTest.class);
}
@Override
public boolean matches(Object mod) {
public boolean matches(Object mod)
{
return mod == modInstance;
}
@Override
public Object getMod() {
public Object getMod()
{
return modInstance;
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ plugins {
apply from: rootProject.file('build_shared.gradle')
dependencies {
compileOnly(libs.jetbrains.annotations)
compileOnly(libs.nulls)
implementation(project(':fmlloader'))
implementation(project(':fmlcore'))
}
@@ -8,6 +8,8 @@ package net.minecraftforge.fml.mclanguageprovider;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.Objects;
public class MinecraftModContainer extends ModContainer {
private static final String MCMODINSTANCE = "minecraft, the mod";
@@ -18,7 +20,7 @@ public class MinecraftModContainer extends ModContainer {
@Override
public boolean matches(final Object mod) {
return MCMODINSTANCE.equals(mod);
return Objects.equals(mod, MCMODINSTANCE);
}
@Override
@@ -10,6 +10,7 @@ import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.IModLanguageProvider;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
@@ -19,7 +20,7 @@ import java.util.function.Supplier;
import static net.minecraftforge.fml.Logging.LOADING;
public class MinecraftModLanguageProvider implements IModLanguageProvider {
private static final Logger LOGGER = LogManager.getLogger();
@Override
public String name() {
return "minecraft";
@@ -44,7 +45,7 @@ public class MinecraftModLanguageProvider implements IModLanguageProvider {
final Class<?> mcModClass = Class.forName(getClass().getModule(), "net.minecraftforge.fml.mclanguageprovider.MinecraftModContainer");
return (T)mcModClass.getConstructor(IModInfo.class).newInstance(info);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
LogManager.getLogger().fatal(LOADING, "Unable to load MinecraftModContainer, wut?", e);
LOGGER.fatal(LOADING,"Unable to load MinecraftModContainer, wut?", e);
throw new RuntimeException(e);
}
}
-2
View File
@@ -25,7 +25,6 @@ minecraft {
configureEach {
workingDir = layout.projectDirectory.dir('run')
systemProperty 'eventbus.api.strictRuntimeChecks', 'true'
systemProperty 'forge.enabledGameTestNamespaces', 'examplemod'
}
@@ -54,7 +53,6 @@ repositories {
dependencies {
implementation minecraft.dependency('net.minecraftforge:forge:@MC_VERSION@-@FORGE_VERSION@')
annotationProcessor 'net.minecraftforge:eventbus-validator:@EVENTBUS_VERSION@'
}
tasks.withType(JavaCompile).configureEach {
@@ -19,12 +19,6 @@ displayName="Example Mod"
authors="YourNameHere, OtherNameHere" #optional
#displayTest="MATCH_VERSION" #optional, default=MATCH_VERSION when not clientSideOnly, else IGNORE_ALL_VERSION
# Access Transformers
# Optional, if not specified Forge will attempt to find the default META-INF/accesstransformer.cfg and silently continue if not found. May default to an empty list in a future MC.
# If you specify AT path strings in this list, Forge will attempt to load each of them and throw errors for any that aren't found.
# Specifying an empty list when your mod has no ATs is recommended to opt-out of the default for slightly better loading performance.
#accessTransformers = []
description='''Example mod description.
Newline characters can be used like this, and rendered on the mods screen properly.'''
@@ -1,12 +0,0 @@
--- a/com/mojang/blaze3d/opengl/GlCommandEncoder.java
+++ b/com/mojang/blaze3d/opengl/GlCommandEncoder.java
@@ -132,6 +_,9 @@
GlStateManager._colorMask(true, true, true, true);
GlStateManager._clear(16384);
GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, 0, 0);
+ // Forge: if using stencil, clear it as well (3553 = GlConst.GL_TEXTURE_2D)
+ if (p_394273_.isStencilEnabled())
+ GlStateManager._glFramebufferTexture2D(GlConst.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_STENCIL_ATTACHMENT, GlConst.GL_TEXTURE_2D, 0, 0);
GlStateManager._glBindFramebuffer(36160, 0);
}
}
@@ -1,34 +0,0 @@
--- a/com/mojang/blaze3d/opengl/GlDebug.java
+++ b/com/mojang/blaze3d/opengl/GlDebug.java
@@ -23,6 +_,14 @@
@OnlyIn(Dist.CLIENT)
public class GlDebug {
+ /**
+ * TODO: [Forge][Rendering][VEN] Expose this in the configs
+ * <p>
+ * Will enable synchronous OpenGL debug logging, which means the message will be sent from the call that
+ * would have caused the error. Additionally, enables printing a stacktrace when and where this occurs.
+ */
+ private static final boolean PRINT_STACKTRACE_ON_ERROR = Boolean.getBoolean("forge.printGLStackOnError");
+
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);
@@ -105,6 +_,8 @@
}
LOGGER.info("OpenGL debug message: {}", gldebug$logentry);
+ // TODO: [VEN] Trim the stack trace
+ if (PRINT_STACKTRACE_ON_ERROR) LOGGER.info("Trace: ", new Throwable("GlDebug"));
}
public List<String> getLastOpenGlDebugMessages() {
@@ -121,6 +_,7 @@
@Nullable
public static GlDebug enableDebugCallback(int p_394351_, boolean p_393026_, Set<String> p_393339_) {
+ p_393026_ |= PRINT_STACKTRACE_ON_ERROR;
if (p_394351_ <= 0) {
return null;
} else {
@@ -1,74 +0,0 @@
--- a/com/mojang/blaze3d/opengl/GlDevice.java
+++ b/com/mojang/blaze3d/opengl/GlDevice.java
@@ -89,8 +_,15 @@
public GpuTexture createTexture(
@Nullable Supplier<String> p_397830_, int p_394481_, TextureFormat p_394839_, int p_391831_, int p_395609_, int p_407582_, int p_408928_
) {
+ return createTexture(p_397830_, p_394481_, p_394839_, p_391831_, p_395609_, p_407582_, p_408928_, false);
+ }
+
+ @Override
+ public GpuTexture createTexture(
+ @Nullable Supplier<String> p_397830_, int p_394481_, TextureFormat p_394839_, int p_391831_, int p_395609_, int p_407582_, int p_408928_, boolean stencil
+ ) {
return this.createTexture(
- this.debugLabels.exists() && p_397830_ != null ? p_397830_.get() : null, p_394481_, p_394839_, p_391831_, p_395609_, p_407582_, p_408928_
+ this.debugLabels.exists() && p_397830_ != null ? p_397830_.get() : null, p_394481_, p_394839_, p_391831_, p_395609_, p_407582_, p_408928_, stencil
);
}
@@ -98,6 +_,15 @@
public GpuTexture createTexture(
@Nullable String p_394142_, int p_395535_, TextureFormat p_394951_, int p_393944_, int p_392329_, int p_408015_, int p_406483_
) {
+ return createTexture(p_394142_, p_395535_, p_394951_, p_393944_, p_392329_, p_408015_, p_406483_, false);
+ }
+
+ @Override
+ public GpuTexture createTexture(
+ @Nullable String p_394142_, int p_395535_, TextureFormat p_394951_, int p_393944_, int p_392329_, int p_408015_, int p_406483_, boolean stencil
+ ) {
+ // Forge: stencil rendering is only for depth
+ stencil &= p_394951_.hasDepthAspect();
if (p_406483_ < 1) {
throw new IllegalArgumentException("mipLevels must be at least 1");
} else if (p_408015_ < 1) {
@@ -148,11 +_,14 @@
GlStateManager._texImage2D(
k,
l,
+ stencil ? org.lwjgl.opengl.GL30.GL_DEPTH32F_STENCIL8 :
GlConst.toGlInternalId(p_394951_),
p_393944_ >> l,
p_392329_ >> l,
0,
+ stencil ? org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL :
GlConst.toGlExternalId(p_394951_),
+ stencil ? org.lwjgl.opengl.GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV :
GlConst.toGlType(p_394951_),
null
);
@@ -163,11 +_,14 @@
GlStateManager._texImage2D(
j,
i1,
+ stencil ? org.lwjgl.opengl.GL30.GL_DEPTH32F_STENCIL8 :
GlConst.toGlInternalId(p_394951_),
p_393944_ >> i1,
p_392329_ >> i1,
0,
+ stencil ? org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL :
GlConst.toGlExternalId(p_394951_),
+ stencil ? org.lwjgl.opengl.GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV :
GlConst.toGlType(p_394951_),
null
);
@@ -180,7 +_,7 @@
} else if (j1 != 0) {
throw new IllegalStateException("OpenGL error " + j1);
} else {
- GlTexture gltexture = new GlTexture(p_395535_, p_394142_, p_394951_, p_393944_, p_392329_, p_408015_, p_406483_, i);
+ GlTexture gltexture = new GlTexture(p_395535_, p_394142_, p_394951_, p_393944_, p_392329_, p_408015_, p_406483_, i, stencil);
this.debugLabels.applyLabel(gltexture);
return gltexture;
}
@@ -1,32 +0,0 @@
--- a/com/mojang/blaze3d/opengl/GlStateManager.java
+++ b/com/mojang/blaze3d/opengl/GlStateManager.java
@@ -89,6 +_,11 @@
}
}
+ public static boolean _isBlendEnabled() {
+ RenderSystem.assertOnRenderThread();
+ return BLEND.mode.enabled;
+ }
+
public static void _disableBlend() {
RenderSystem.assertOnRenderThread();
BLEND.mode.disable();
@@ -404,9 +_,17 @@
}
}
+ /* Stores the last values sent into glMultiTexCoord2f */
+ public static float lastBrightnessX = 0.0f;
+ public static float lastBrightnessY = 0.0f;
+
public static void _texParameter(int p_393876_, int p_397998_, int p_396741_) {
RenderSystem.assertOnRenderThread();
GL11.glTexParameteri(p_393876_, p_397998_, p_396741_);
+ if (p_393876_ == GL13.GL_TEXTURE1) {
+ lastBrightnessX = p_397998_;
+ lastBrightnessY = p_396741_;
+ }
}
public static int _getTexLevelParameter(int p_393352_, int p_397204_, int p_396319_) {
@@ -1,33 +0,0 @@
--- a/com/mojang/blaze3d/opengl/GlTexture.java
+++ b/com/mojang/blaze3d/opengl/GlTexture.java
@@ -19,8 +_,13 @@
private int views;
protected GlTexture(int p_394590_, String p_393950_, TextureFormat p_392837_, int p_391379_, int p_391947_, int p_396659_, int p_408255_, int p_408889_) {
+ this(p_394590_, p_393950_, p_392837_, p_391379_, p_391947_, p_396659_, p_408255_, p_408889_, false);
+ }
+
+ protected GlTexture(int p_394590_, String p_393950_, TextureFormat p_392837_, int p_391379_, int p_391947_, int p_396659_, int p_408255_, int p_408889_, boolean stencil) {
super(p_394590_, p_393950_, p_392837_, p_391379_, p_391947_, p_396659_, p_408255_);
this.id = p_408889_;
+ this.stencilEnabled = stencil;
}
@Override
@@ -93,6 +_,16 @@
public void setTextureFilter(FilterMode p_394977_, FilterMode p_397175_, boolean p_393558_) {
super.setTextureFilter(p_394977_, p_397175_, p_393558_);
this.modesDirty = true;
+ }
+
+
+ /* FORGE START */
+
+ private final boolean stencilEnabled;
+
+ @Override
+ public boolean isStencilEnabled() {
+ return this.stencilEnabled;
}
@Override
@@ -1,18 +1,28 @@
--- a/com/mojang/blaze3d/pipeline/RenderTarget.java
+++ b/com/mojang/blaze3d/pipeline/RenderTarget.java
@@ -92,7 +_,7 @@
this.width = p_83951_;
this.height = p_83952_;
@@ -96,7 +_,10 @@
GlStateManager._texParameter(3553, 34892, 0);
GlStateManager._texParameter(3553, 10242, 33071);
GlStateManager._texParameter(3553, 10243, 33071);
+ if (!stencilEnabled)
GlStateManager._texImage2D(3553, 0, 6402, this.width, this.height, 0, 6402, 5126, null);
+ else
+ GlStateManager._texImage2D(3553, 0, org.lwjgl.opengl.GL30.GL_DEPTH32F_STENCIL8, this.width, this.height, 0, org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL, org.lwjgl.opengl.GL30.GL_FLOAT_32_UNSIGNED_INT_24_8_REV, null);
}
this.setFilterMode(9728, true);
@@ -108,6 +_,7 @@
GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, this.colorTextureId, 0);
if (this.useDepth) {
- this.depthTexture = gpudevice.createTexture(() -> this.label + " / Depth", 15, TextureFormat.DEPTH32, p_83951_, p_83952_, 1, 1);
+ this.depthTexture = gpudevice.createTexture(() -> this.label + " / Depth", 15, TextureFormat.DEPTH32, p_83951_, p_83952_, 1, 1, this.stencilEnabled);
this.depthTextureView = gpudevice.createTextureView(this.depthTexture);
this.depthTexture.setTextureFilter(FilterMode.NEAREST, false);
this.depthTexture.setAddressMode(AddressMode.CLAMP_TO_EDGE);
@@ -166,5 +_,26 @@
@Nullable
public GpuTextureView getDepthTextureView() {
return this.depthTextureView;
GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0);
+ if (stencilEnabled) GlStateManager._glFramebufferTexture2D(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_STENCIL_ATTACHMENT, 3553, this.depthBufferId, 0);
}
this.checkStatus();
@@ -229,5 +_,26 @@
public int getDepthTextureId() {
return this.depthBufferId;
+ }
+
+ private boolean stencilEnabled = false;
@@ -0,0 +1,32 @@
--- a/com/mojang/blaze3d/platform/GlStateManager.java
+++ b/com/mojang/blaze3d/platform/GlStateManager.java
@@ -94,6 +_,11 @@
}
}
+ public static boolean _isBlendEnabled() {
+ RenderSystem.assertOnRenderThread();
+ return BLEND.mode.enabled;
+ }
+
public static void _disableBlend() {
RenderSystem.assertOnRenderThread();
BLEND.mode.disable();
@@ -519,9 +_,17 @@
}
}
+ /* Stores the last values sent into glMultiTexCoord2f */
+ public static float lastBrightnessX = 0.0f;
+ public static float lastBrightnessY = 0.0f;
+
public static void _texParameter(int p_84161_, int p_84162_, float p_84163_) {
RenderSystem.assertOnRenderThreadOrInit();
GL11.glTexParameterf(p_84161_, p_84162_, p_84163_);
+ if (p_84161_ == GL13.GL_TEXTURE1) {
+ lastBrightnessX = p_84162_;
+ lastBrightnessY = p_84163_;
+ }
}
public static void _texParameter(int p_84332_, int p_84333_, int p_84334_) {
@@ -16,9 +16,9 @@
}
+ }
this.setMode();
this.refreshFramebufferSize();
@@ -266,6 +_,9 @@
GLFW.glfwMakeContextCurrent(this.window);
GL.createCapabilities();
@@ -267,6 +_,9 @@
GLFW.glfwGetFramebufferSize(this.window, aint, aint1);
this.framebufferWidth = aint[0] > 0 ? aint[0] : 1;
this.framebufferHeight = aint1[0] > 0 ? aint1[0] : 1;
@@ -1,20 +0,0 @@
--- a/com/mojang/blaze3d/systems/GpuDevice.java
+++ b/com/mojang/blaze3d/systems/GpuDevice.java
@@ -26,7 +_,17 @@
@Nullable Supplier<String> p_394357_, int p_395623_, TextureFormat p_395807_, int p_395802_, int p_396157_, int p_408810_, int p_407070_
);
+ /** Forge: same as {@link #createTexture(Supplier, int, TextureFormat, int, int, int)} but with stencil support */
+ default GpuTexture createTexture(@Nullable Supplier<String> p_394357_, int p_395623_, TextureFormat p_395807_, int p_395802_, int p_396157_, int p_408810_, int p_407070_, boolean stencil) {
+ return this.createTexture(p_394357_, p_395623_, p_395807_, p_395802_, p_396157_, p_408810_, p_407070_);
+ }
+
GpuTexture createTexture(@Nullable String p_391798_, int p_391800_, TextureFormat p_393333_, int p_395600_, int p_394065_, int p_408732_, int p_407125_);
+
+ /** Forge: same as {@link #createTexture(String, int, TextureFormat, int, int, int)} but with stencil support */
+ default GpuTexture createTexture(@Nullable String p_391798_, int p_391800_, TextureFormat p_393333_, int p_395600_, int p_394065_, int p_408732_, int p_407125_, boolean stencil) {
+ return this.createTexture(p_391798_, p_391800_, p_393333_, p_395600_, p_394065_, p_408732_, p_407125_);
+ }
GpuTextureView createTextureView(GpuTexture p_409045_);
@@ -0,0 +1,14 @@
--- a/com/mojang/blaze3d/systems/RenderSystem.java
+++ b/com/mojang/blaze3d/systems/RenderSystem.java
@@ -196,6 +_,11 @@
GlStateManager._depthMask(p_69459_);
}
+ public static boolean isBlendEnabled() {
+ assertOnRenderThread();
+ return GlStateManager._isBlendEnabled();
+ }
+
public static void enableBlend() {
assertOnRenderThread();
GlStateManager._enableBlend();
@@ -1,11 +0,0 @@
--- a/com/mojang/blaze3d/textures/GpuTexture.java
+++ b/com/mojang/blaze3d/textures/GpuTexture.java
@@ -6,7 +_,7 @@
@OnlyIn(Dist.CLIENT)
@DontObfuscate
-public abstract class GpuTexture implements AutoCloseable {
+public abstract class GpuTexture implements AutoCloseable, net.minecraftforge.client.extensions.IForgeGpuTexture {
public static final int USAGE_COPY_DST = 1;
public static final int USAGE_COPY_SRC = 2;
public static final int USAGE_TEXTURE_BINDING = 4;
@@ -1,11 +1,11 @@
--- a/com/mojang/blaze3d/vertex/PoseStack.java
+++ b/com/mojang/blaze3d/vertex/PoseStack.java
@@ -15,7 +_,7 @@
import org.joml.Vector3fc;
@@ -14,7 +_,7 @@
import org.joml.Vector3f;
@OnlyIn(Dist.CLIENT)
-public class PoseStack {
+public class PoseStack implements net.minecraftforge.client.extensions.IForgePoseStack {
private final List<PoseStack.Pose> poses = new ArrayList<>(16);
private int lastIndex;
private final Deque<PoseStack.Pose> poseStack = Util.make(Queues.newArrayDeque(), p_85848_ -> {
Matrix4f matrix4f = new Matrix4f();
Matrix3f matrix3f = new Matrix3f();
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/vertex/VertexConsumer.java
+++ b/com/mojang/blaze3d/vertex/VertexConsumer.java
@@ -15,7 +_,7 @@
@@ -13,7 +_,7 @@
import org.lwjgl.system.MemoryStack;
@OnlyIn(Dist.CLIENT)
@@ -9,7 +9,7 @@
VertexConsumer addVertex(float p_344294_, float p_342213_, float p_344859_);
VertexConsumer setColor(int p_342749_, int p_344324_, int p_343336_, int p_342831_);
@@ -135,9 +_,11 @@
@@ -133,9 +_,11 @@
int j1 = ARGB.color(k, (int)f3, (int)f4, (int)f5);
int k1 = LightTexture.lightCoordsWithEmission(p_331444_[i1], l);
@@ -1,23 +1,23 @@
--- a/com/mojang/blaze3d/vertex/VertexFormat.java
+++ b/com/mojang/blaze3d/vertex/VertexFormat.java
@@ -21,7 +_,7 @@
@@ -14,7 +_,7 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@DontObfuscate
-public class VertexFormat {
+public class VertexFormat implements net.minecraftforge.client.extensions.IForgeVertexFormat {
public static final int UNKNOWN_ELEMENT = -1;
private static final boolean USE_STAGING_BUFFER_WORKAROUND = Util.getPlatform() == Util.OS.WINDOWS && Util.isAarch64();
private final List<VertexFormatElement> elements;
private final List<String> names;
@@ -23,6 +_,7 @@
private final int[] offsetsByElement = new int[32];
@Nullable
@@ -35,6 +_,7 @@
private GpuBuffer immediateDrawVertexBuffer;
@Nullable
private GpuBuffer immediateDrawIndexBuffer;
private VertexBuffer immediateDrawVertexBuffer;
+ private final com.google.common.collect.ImmutableMap<String, VertexFormatElement> elementMapping;
VertexFormat(List<VertexFormatElement> p_343616_, List<String> p_345241_, IntList p_345522_, int p_344162_) {
this.elements = p_343616_;
@@ -47,6 +_,11 @@
@@ -35,6 +_,11 @@
int j = vertexformatelement != null ? p_343616_.indexOf(vertexformatelement) : -1;
this.offsetsByElement[i] = j != -1 ? p_345522_.getInt(j) : -1;
}
@@ -29,13 +29,13 @@
}
public static VertexFormat.Builder builder() {
@@ -169,6 +_,9 @@
);
return this.immediateDrawIndexBuffer;
@@ -141,6 +_,9 @@
return vertexbuffer;
}
+
+ public ImmutableMap<String, VertexFormatElement> getElementMapping() { return elementMapping; }
+ public int getOffset(int index) { return offsetsByElement[index]; }
@OnlyIn(Dist.CLIENT)
@DontObfuscate
public static class Builder {
@@ -1,15 +1,15 @@
--- a/com/mojang/math/Transformation.java
+++ b/com/mojang/math/Transformation.java
@@ -14,7 +_,7 @@
@@ -13,7 +_,7 @@
import org.joml.Quaternionf;
import org.joml.Vector3f;
-public final class Transformation {
+public final class Transformation implements net.minecraftforge.common.extensions.IForgeTransformation {
private final Matrix4fc matrix;
private final Matrix4f matrix;
public static final Codec<Transformation> CODEC = RecordCodecBuilder.create(
p_269604_ -> p_269604_.group(
@@ -174,5 +_,19 @@
@@ -169,5 +_,19 @@
vector3f1.lerp(p_175938_.getScale(), p_175939_);
quaternionf1.slerp(p_175938_.getRightRotation(), p_175939_);
return new Transformation(vector3f, quaternionf, vector3f1, quaternionf1);
@@ -34,4 +34,4 @@
+ this.stackTrace = t.getStackTrace();
}
public static void populateBlockDetails(CrashReportCategory p_178951_, LevelHeightAccessor p_178952_, BlockPos p_178953_, BlockState p_178954_) {
public static void populateBlockDetails(CrashReportCategory p_178951_, LevelHeightAccessor p_178952_, BlockPos p_178953_, @Nullable BlockState p_178954_) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/SharedConstants.java
+++ b/net/minecraft/SharedConstants.java
@@ -175,6 +_,7 @@
@@ -170,6 +_,7 @@
}
static {
@@ -1,7 +1,7 @@
--- a/net/minecraft/Util.java
+++ b/net/minecraft/Util.java
@@ -268,7 +_,7 @@
.getSchema(DataFixUtils.makeKey(SharedConstants.getCurrentVersion().dataVersion().version()))
@@ -264,7 +_,7 @@
.getSchema(DataFixUtils.makeKey(SharedConstants.getCurrentVersion().getDataVersion().getVersion()))
.getChoiceType(p_137552_, p_137553_);
} catch (IllegalArgumentException illegalargumentexception) {
- LOGGER.error("No data fixer registered for {}", p_137553_);
@@ -1,6 +1,6 @@
--- a/net/minecraft/advancements/Advancement.java
+++ b/net/minecraft/advancements/Advancement.java
@@ -226,7 +_,11 @@
@@ -214,7 +_,11 @@
}
public AdvancementHolder save(Consumer<AdvancementHolder> p_138390_, String p_138391_) {
@@ -1,7 +1,7 @@
--- a/net/minecraft/advancements/AdvancementRewards.java
+++ b/net/minecraft/advancements/AdvancementRewards.java
@@ -43,6 +_,7 @@
LootParams lootparams = new LootParams.Builder(serverlevel)
@@ -41,6 +_,7 @@
LootParams lootparams = new LootParams.Builder(p_9990_.serverLevel())
.withParameter(LootContextParams.THIS_ENTITY, p_9990_)
.withParameter(LootContextParams.ORIGIN, p_9990_.position())
+ .withLuck(p_9990_.getLuck())
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/Camera.java
+++ b/net/minecraft/client/Camera.java
@@ -133,9 +_,13 @@
@@ -120,9 +_,13 @@
}
protected void setRotation(float p_90573_, float p_90574_) {
@@ -15,7 +15,7 @@
FORWARDS.rotate(this.rotation, this.forwards);
UP.rotate(this.rotation, this.up);
LEFT.rotate(this.rotation, this.left);
@@ -251,6 +_,13 @@
@@ -238,6 +_,13 @@
public float getPartialTickTime() {
return this.partialTickTime;
@@ -28,4 +28,4 @@
+ return this.level.getBlockState(this.blockPosition).getStateAtViewpoint(this.level, this.blockPosition, this.position);
}
@Override
@OnlyIn(Dist.CLIENT)
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/KeyMapping.java
+++ b/net/minecraft/client/KeyMapping.java
@@ -15,9 +_,9 @@
@@ -14,9 +_,9 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@@ -12,7 +12,7 @@
private static final Set<String> CATEGORIES = Sets.newHashSet();
public static final String CATEGORY_MOVEMENT = "key.categories.movement";
public static final String CATEGORY_MISC = "key.categories.misc";
@@ -43,14 +_,14 @@
@@ -42,14 +_,14 @@
private int clickCount;
public static void click(InputConstants.Key p_90836_) {
@@ -29,7 +29,7 @@
if (keymapping != null) {
keymapping.setDown(p_90839_);
}
@@ -101,7 +_,7 @@
@@ -100,7 +_,7 @@
}
public boolean isDown() {
@@ -38,7 +38,7 @@
}
public String getCategory() {
@@ -137,7 +_,16 @@
@@ -136,7 +_,16 @@
public int compareTo(KeyMapping p_90841_) {
return this.category.equals(p_90841_.category)
? I18n.get(this.name).compareTo(I18n.get(p_90841_.name))
@@ -56,7 +56,7 @@
}
public static Supplier<Component> createNameSupplier(String p_90843_) {
@@ -146,6 +_,20 @@
@@ -145,6 +_,20 @@
}
public boolean same(KeyMapping p_90851_) {
@@ -77,7 +77,7 @@
return this.key.equals(p_90851_.key);
}
@@ -164,11 +_,13 @@
@@ -163,11 +_,13 @@
}
public Component getTranslatedKeyMessage() {
@@ -92,10 +92,10 @@
}
public String saveString() {
@@ -182,5 +_,88 @@
@Nullable
public static KeyMapping get(String p_378660_) {
return ALL.get(p_378660_);
@@ -176,5 +_,88 @@
public void setDown(boolean p_90846_) {
this.isDown = p_90846_;
+ }
+
+ private net.minecraftforge.client.settings.KeyModifier keyModifierDefault = net.minecraftforge.client.settings.KeyModifier.NONE;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/KeyboardHandler.java
+++ b/net/minecraft/client/KeyboardHandler.java
@@ -440,12 +_,12 @@
@@ -424,12 +_,12 @@
if (screen != null) {
try {
if (p_90897_ != 1 && p_90897_ != 2) {
@@ -15,7 +15,7 @@
return;
}
}
@@ -504,6 +_,7 @@
@@ -505,6 +_,7 @@
}
}
}
@@ -23,7 +23,7 @@
}
}
@@ -513,10 +_,10 @@
@@ -514,10 +_,10 @@
if (screen != null && this.minecraft.getOverlay() == null) {
try {
if (Character.isBmpCodePoint(p_90891_)) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/Minecraft.java
+++ b/net/minecraft/client/Minecraft.java
@@ -256,7 +_,7 @@
@@ -253,7 +_,7 @@
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
@@ -9,7 +9,7 @@
static Minecraft instance;
private static final Logger LOGGER = LogUtils.getLogger();
public static final boolean ON_OSX = Util.getPlatform() == Util.OS.OSX;
@@ -435,7 +_,6 @@
@@ -433,7 +_,6 @@
}
}, Util.nonCriticalIoPool());
LOGGER.info("Setting user: {}", this.user.getName());
@@ -17,7 +17,7 @@
this.demo = p_91084_.game.demo;
this.allowsMultiplayer = !p_91084_.game.disableMultiplayer;
this.allowsChat = !p_91084_.game.disableChat;
@@ -486,10 +_,9 @@
@@ -480,15 +_,15 @@
LOGGER.error("Couldn't set icon", (Throwable)ioexception);
}
@@ -26,26 +26,24 @@
- this.mouseHandler.setup(this.window.getWindow());
this.keyboardHandler = new KeyboardHandler(this);
- this.keyboardHandler.setup(this.window.getWindow());
RenderSystem.initRenderer(
this.window.getWindow(),
this.options.glDebugVerbosity,
@@ -500,6 +_,7 @@
LOGGER.info("Using optional rendering extensions: {}", String.join(", ", RenderSystem.getDevice().getEnabledExtensions()));
RenderSystem.initRenderer(this.options.glDebugVerbosity, false);
this.mainRenderTarget = new MainTarget(this.window.getWidth(), this.window.getHeight());
this.mainRenderTarget.setClearColor(0.0F, 0.0F, 0.0F, 0.0F);
this.mainRenderTarget.clear();
this.resourceManager = new ReloadableResourceManager(PackType.CLIENT_RESOURCES);
+ net.minecraftforge.client.loading.ClientModLoader.begin(this, this.resourcePackRepository, this.resourceManager);
this.resourcePackRepository.reload();
this.options.loadSelectedResourcePacks(this.resourcePackRepository);
this.languageManager = new LanguageManager(this.options.languageCode, p_340763_ -> {
@@ -578,6 +_,7 @@
this.blockEntityRenderDispatcher = new BlockEntityRenderDispatcher(this.font, this.modelManager.entityModels(), this.blockRenderer, this.itemModelResolver, this.itemRenderer, this.entityRenderDispatcher);
this.resourceManager.registerReloadListener(this.blockEntityRenderDispatcher);
@@ -562,6 +_,7 @@
);
this.resourceManager.registerReloadListener(this.entityRenderDispatcher);
this.particleEngine = new ParticleEngine(this.level, this.textureManager);
+ net.minecraftforge.client.ForgeHooksClient.onRegisterParticleProviders(this.particleEngine);
this.resourceManager.registerReloadListener(this.particleEngine);
this.paintingTextures = new PaintingTextureManager(this.textureManager);
this.resourceManager.registerReloadListener(this.paintingTextures);
@@ -593,6 +_,9 @@
@@ -577,6 +_,9 @@
this.resourceManager.registerReloadListener(this.gpuWarnlistManager);
this.resourceManager.registerReloadListener(this.regionalCompliancies);
this.gui = new Gui(this);
@@ -53,17 +51,17 @@
+ this.mouseHandler.setup(this.window.getWindow());
+ this.keyboardHandler.setup(this.window.getWindow());
this.debugRenderer = new DebugRenderer(this);
RealmsClient realmsclient = RealmsClient.getOrCreate(this);
RealmsClient realmsclient = RealmsClient.create(this);
this.realmsDataFetcher = new RealmsDataFetcher(realmsclient);
@@ -626,6 +_,7 @@
}
@@ -600,6 +_,7 @@
this.options.fullscreen().set(this.window.isFullscreen());
}
+ net.minecraftforge.client.ForgeHooksClient.initClientHooks(this, this.resourceManager);
this.window.updateVsync(this.options.enableVsync().get());
this.window.updateRawMouseInput(this.options.rawMouseInput().get());
this.window.setDefaultErrorCallback();
@@ -648,16 +_,17 @@
@@ -620,16 +_,17 @@
GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_LOADING_OVERLAY_MS);
Minecraft.GameLoadCookie minecraft$gameloadcookie = new Minecraft.GameLoadCookie(realmsclient, p_91084_.quickPlay);
this.setOverlay(
@@ -71,20 +69,20 @@
- this, reloadinstance, p_296164_ -> Util.ifElse(p_296164_, p_296162_ -> this.rollbackResourcePacks(p_296162_, minecraft$gameloadcookie), () -> {
+ net.minecraftforge.fml.loading.ImmediateWindowHandler.<LoadingOverlay>loadingOverlay(
+ () -> this, () -> reloadinstance, p_296164_ -> Util.ifElse(p_296164_, p_296162_ -> this.rollbackResourcePacks(p_296162_, minecraft$gameloadcookie), () -> {
if (SharedConstants.IS_RUNNING_IN_IDE) {
this.selfTest();
}
if (SharedConstants.IS_RUNNING_IN_IDE) {
this.selfTest();
}
this.reloadStateTracker.finishReload();
this.onResourceLoadFinished(minecraft$gameloadcookie);
+ net.minecraftforge.client.loading.ClientModLoader.completeModLoading();
}), false
this.reloadStateTracker.finishReload();
this.onResourceLoadFinished(minecraft$gameloadcookie);
+ net.minecraftforge.client.loading.ClientModLoader.completeModLoading();
}), false
- )
+ ).get()
);
this.quickPlayLog = QuickPlayLog.of(p_91084_.quickPlay.logPath());
this.quickPlayLog = QuickPlayLog.of(p_91084_.quickPlay.path());
this.framerateLimitTracker = new FramerateLimitTracker(this.options, this);
@@ -759,6 +_,7 @@
@@ -724,6 +_,7 @@
StringBuilder stringbuilder = new StringBuilder("Minecraft");
if (checkModStatus().shouldReportAsModified()) {
stringbuilder.append("*");
@@ -92,7 +90,7 @@
}
stringbuilder.append(" ");
@@ -782,6 +_,8 @@
@@ -747,6 +_,8 @@
}
private UserApiService createUserApiService(YggdrasilAuthenticationService p_193586_, GameConfig p_193587_) {
@@ -101,7 +99,7 @@
return p_193587_.user.user.getType() != User.Type.MSA
? UserApiService.OFFLINE
: p_193586_.createUserApiService(p_193587_.user.user.getAccessToken());
@@ -792,7 +_,7 @@
@@ -757,7 +_,7 @@
}
private void rollbackResourcePacks(Throwable p_91240_, @Nullable Minecraft.GameLoadCookie p_299515_) {
@@ -110,7 +108,7 @@
this.clearResourcePacksOnError(p_91240_, null, p_299515_);
} else {
Util.throwAsRuntime(p_91240_);
@@ -1078,12 +_,6 @@
@@ -1043,12 +_,6 @@
LOGGER.error("setScreen called from non-game thread");
}
@@ -123,7 +121,7 @@
if (p_91153_ == null && this.clientLevelTeardownInProgress) {
throw new IllegalStateException("Trying to return to in-game GUI during disconnection");
} else {
@@ -1097,6 +_,23 @@
@@ -1062,6 +_,23 @@
}
}
@@ -147,15 +145,15 @@
this.screen = p_91153_;
if (this.screen != null) {
this.screen.added();
@@ -1180,6 +_,7 @@
@@ -1146,6 +_,7 @@
FreeTypeUtil.destroy();
Util.shutdownExecutors();
RenderSystem.getDevice().close();
+ net.minecraftforge.fml.config.ConfigTracker.INSTANCE.forceUnload();
} catch (Throwable throwable) {
LOGGER.error("Shutdown failure!", throwable);
throw throwable;
@@ -1248,9 +_,11 @@
@@ -1215,9 +_,11 @@
this.mouseHandler.handleAccumulatedMovement();
profilerfiller.pop();
if (!this.noRender) {
@@ -167,8 +165,8 @@
}
profilerfiller.push("blit");
@@ -1379,10 +_,12 @@
this.window.setGuiScale(i);
@@ -1339,10 +_,12 @@
this.window.setGuiScale((double)i);
if (this.screen != null) {
this.screen.resize(this, this.window.getGuiScaledWidth(), this.window.getGuiScaledHeight());
+ net.minecraftforge.client.ForgeHooksClient.resizeGuiLayers(this, this.window.getGuiScaledWidth(), this.window.getGuiScaledHeight());
@@ -180,7 +178,7 @@
this.gameRenderer.resize(this.window.getWidth(), this.window.getHeight());
this.mouseHandler.setIgnoreFirstMove();
}
@@ -1520,6 +_,7 @@
@@ -1483,6 +_,7 @@
}
public void stop() {
@@ -188,14 +186,14 @@
this.running = false;
}
@@ -1547,10 +_,18 @@
@@ -1511,10 +_,18 @@
if (p_91387_ && this.hitResult != null && this.hitResult.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockhitresult = (BlockHitResult)this.hitResult;
BlockPos blockpos = blockhitresult.getBlockPos();
- if (!this.level.getBlockState(blockpos).isAir()) {
+ if (!this.level.isEmptyBlock(blockpos)) {
+ var inputEvent = new net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered(0, this.options.keyAttack, InteractionHand.MAIN_HAND);
+ if (net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered.BUS.post(inputEvent)) {
+ var inputEvent = net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInput(0, this.options.keyAttack, InteractionHand.MAIN_HAND);
+ if (inputEvent.isCanceled()) {
+ if (inputEvent.shouldSwingHand()) {
+ this.particleEngine.addBlockHitEffects(blockpos, blockhitresult);
+ this.player.swing(InteractionHand.MAIN_HAND);
@@ -210,16 +208,16 @@
this.player.swing(InteractionHand.MAIN_HAND);
}
}
@@ -1578,6 +_,8 @@
@@ -1542,6 +_,8 @@
return false;
} else {
boolean flag = false;
+ var inputEvent = new net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered(0, this.options.keyAttack, InteractionHand.MAIN_HAND);
+ if (!net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered.BUS.post(inputEvent))
+ var inputEvent = net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInput(0, this.options.keyAttack, InteractionHand.MAIN_HAND);
+ if (!inputEvent.isCanceled())
switch (this.hitResult.getType()) {
case ENTITY:
this.gameMode.attack(this.player, ((EntityHitResult)this.hitResult).getEntity());
@@ -1585,7 +_,7 @@
@@ -1549,7 +_,7 @@
case BLOCK:
BlockHitResult blockhitresult = (BlockHitResult)this.hitResult;
BlockPos blockpos = blockhitresult.getBlockPos();
@@ -228,7 +226,7 @@
this.gameMode.startDestroyBlock(blockpos, blockhitresult.getDirection());
if (this.level.getBlockState(blockpos).isAir()) {
flag = true;
@@ -1598,8 +_,10 @@
@@ -1562,8 +_,10 @@
}
this.player.resetAttackStrengthTicker();
@@ -239,12 +237,12 @@
this.player.swing(InteractionHand.MAIN_HAND);
return flag;
}
@@ -1615,6 +_,12 @@
@@ -1579,6 +_,12 @@
}
for (InteractionHand interactionhand : InteractionHand.values()) {
+ var inputEvent = new net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered(1, this.options.keyUse, interactionhand);
+ if (net.minecraftforge.client.event.InputEvent.InteractionKeyMappingTriggered.BUS.post(inputEvent)) {
+ var inputEvent = net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInput(1, this.options.keyUse, interactionhand);
+ if (inputEvent.isCanceled()) {
+ if (inputEvent.shouldSwingHand()) this.player.swing(interactionhand);
+ return;
+ }
@@ -252,7 +250,7 @@
ItemStack itemstack = this.player.getItemInHand(interactionhand);
if (!itemstack.isItemEnabled(this.level.enabledFeatures())) {
return;
@@ -1635,7 +_,7 @@
@@ -1599,7 +_,7 @@
}
if (interactionresult instanceof InteractionResult.Success interactionresult$success2) {
@@ -261,16 +259,16 @@
this.player.swing(interactionhand);
}
@@ -1647,7 +_,7 @@
@@ -1611,7 +_,7 @@
int i = itemstack.getCount();
InteractionResult interactionresult1 = this.gameMode.useItemOn(this.player, interactionhand, blockhitresult);
if (interactionresult1 instanceof InteractionResult.Success interactionresult$success) {
- if (interactionresult$success.swingSource() == InteractionResult.SwingSource.CLIENT) {
+ if (interactionresult$success.swingSource() == InteractionResult.SwingSource.CLIENT && inputEvent.shouldSwingHand()) {
this.player.swing(interactionhand);
if (!itemstack.isEmpty() && (itemstack.getCount() != i || this.player.hasInfiniteMaterials())) {
if (!itemstack.isEmpty() && (itemstack.getCount() != i || this.gameMode.hasInfiniteItems())) {
this.gameRenderer.itemInHandRenderer.itemUsed(interactionhand);
@@ -1663,6 +_,9 @@
@@ -1627,6 +_,9 @@
}
}
@@ -280,7 +278,7 @@
if (!itemstack.isEmpty()
&& this.gameMode.useItem(this.player, interactionhand) instanceof InteractionResult.Success interactionresult$success1) {
if (interactionresult$success1.swingSource() == InteractionResult.SwingSource.CLIENT) {
@@ -1692,6 +_,8 @@
@@ -1656,6 +_,8 @@
}
ProfilerFiller profilerfiller = Profiler.get();
@@ -289,7 +287,7 @@
profilerfiller.push("gui");
this.chatListener.tick();
this.gui.tick(this.pause);
@@ -1778,6 +_,7 @@
@@ -1745,6 +_,7 @@
this.tutorial.tick();
@@ -297,7 +295,7 @@
try {
this.level.tick(() -> true);
} catch (Throwable throwable1) {
@@ -1791,6 +_,7 @@
@@ -1758,6 +_,7 @@
throw new ReportedException(crashreport1);
}
@@ -305,7 +303,7 @@
}
profilerfiller.popPush("animateTick");
@@ -1815,6 +_,7 @@
@@ -1782,6 +_,7 @@
profilerfiller.popPush("keyboard");
this.keyboardHandler.tick();
profilerfiller.pop();
@@ -313,7 +311,7 @@
}
private boolean isLevelRunningNormally() {
@@ -2031,6 +_,7 @@
@@ -1983,6 +_,7 @@
}
public void setLevel(ClientLevel p_91157_, ReceivingLevelScreen.Reason p_335893_) {
@@ -321,7 +319,7 @@
this.updateScreenAndTick(new ReceivingLevelScreen(() -> false, p_335893_));
this.level = p_91157_;
this.updateLevelInEngines(p_91157_);
@@ -2068,6 +_,7 @@
@@ -2020,6 +_,7 @@
IntegratedServer integratedserver = this.singleplayerServer;
this.singleplayerServer = null;
this.gameRenderer.resetData();
@@ -329,7 +327,7 @@
this.gameMode = null;
this.narrator.clear();
this.clientLevelTeardownInProgress = true;
@@ -2075,6 +_,7 @@
@@ -2027,6 +_,7 @@
try {
this.updateScreenAndTick(p_335030_);
if (this.level != null) {
@@ -337,7 +335,7 @@
if (integratedserver != null) {
ProfilerFiller profilerfiller = Profiler.get();
profilerfiller.push("waitForServer");
@@ -2088,6 +_,7 @@
@@ -2040,6 +_,7 @@
this.gui.onDisconnected();
this.isLocalServer = false;
@@ -345,11 +343,40 @@
}
this.level = null;
@@ -2236,6 +_,7 @@
@@ -2187,6 +_,7 @@
private void pickBlock() {
if (this.hitResult != null && this.hitResult.getType() != HitResult.Type.MISS) {
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInputPickBlock(this.options.keyPickItem)) return;
boolean flag = Screen.hasControlDown();
switch (this.hitResult) {
case BlockHitResult blockhitresult:
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInput(2, this.options.keyPickItem, InteractionHand.MAIN_HAND).isCanceled()) return;
boolean flag = this.player.getAbilities().instabuild;
BlockEntity blockentity = null;
HitResult.Type hitresult$type = this.hitResult.getType();
@@ -2199,7 +_,7 @@
}
Block block = blockstate.getBlock();
- itemstack = block.getCloneItemStack(this.level, blockpos, blockstate);
+ itemstack = blockstate.getCloneItemStack(this.hitResult, this.level, blockpos, this.player);
if (itemstack.isEmpty()) {
return;
}
@@ -2213,7 +_,7 @@
}
Entity entity = ((EntityHitResult)this.hitResult).getEntity();
- itemstack = entity.getPickResult();
+ itemstack = entity.getPickedResult(this.hitResult);
if (itemstack == null) {
return;
}
@@ -2818,6 +_,10 @@
@Nullable
public static String getLauncherBrand() {
return System.getProperty("minecraft.launcher.brand");
+ }
+
+ public ItemColors getItemColors() {
+ return this.itemColors;
}
@OnlyIn(Dist.CLIENT)
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/MouseHandler.java
+++ b/net/minecraft/client/MouseHandler.java
@@ -90,6 +_,7 @@
@@ -85,6 +_,7 @@
this.activeButton = -1;
}
@@ -8,7 +8,7 @@
if (this.minecraft.getOverlay() == null) {
if (this.minecraft.screen == null) {
if (!this.mouseGrabbed && flag) {
@@ -103,7 +_,7 @@
@@ -98,7 +_,7 @@
screen.afterMouseAction();
try {
@@ -17,7 +17,7 @@
return;
}
} catch (Throwable throwable1) {
@@ -116,7 +_,7 @@
@@ -112,7 +_,7 @@
}
} else {
try {
@@ -26,18 +26,18 @@
return;
}
} catch (Throwable throwable) {
@@ -150,6 +_,7 @@
@@ -147,6 +_,7 @@
}
}
}
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onMouseButtonPost(p_91532_, p_91533_, p_91534_);
}
public void fillMousePositionDetails(CrashReportCategory p_398230_, Window p_398216_) {
@@ -189,7 +_,9 @@
private void onScroll(long p_91527_, double p_91528_, double p_91529_) {
@@ -160,7 +_,9 @@
if (this.minecraft.screen != null) {
double d3 = this.getScaledXPos(this.minecraft.getWindow());
double d4 = this.getScaledYPos(this.minecraft.getWindow());
double d3 = this.xpos * (double)this.minecraft.getWindow().getGuiScaledWidth() / (double)this.minecraft.getWindow().getScreenWidth();
double d4 = this.ypos * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
- this.minecraft.screen.mouseScrolled(d3, d4, d1, d2);
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseScrollPre(this.minecraft.screen, d3, d4, d1, d2)) return;
+ if (this.minecraft.screen.mouseScrolled(d3, d4, d1, d2)) return;
@@ -45,7 +45,7 @@
this.minecraft.screen.afterMouseAction();
} else if (this.minecraft.player != null) {
Vector2i vector2i = this.scrollWheelHandler.onMouseScroll(d1, d2);
@@ -198,6 +_,7 @@
@@ -169,6 +_,7 @@
}
int i = vector2i.y == 0 ? -vector2i.x : vector2i.y;
@@ -53,8 +53,8 @@
if (this.minecraft.player.isSpectator()) {
if (this.minecraft.gui.getSpectatorGui().isMenuActive()) {
this.minecraft.gui.getSpectatorGui().onMouseScrolled(-i);
@@ -303,7 +_,7 @@
double d5 = getScaledYPos(window, this.accumulatedDY);
@@ -274,7 +_,7 @@
double d5 = this.accumulatedDY * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
try {
- screen.mouseDragged(d2, d3, this.activeButton, d4, d5);
@@ -62,7 +62,7 @@
} catch (Throwable throwable) {
CrashReport crashreport1 = CrashReport.forThrowable(throwable, "mouseDragged event handler");
screen.fillCrashDetails(crashreport1);
@@ -393,6 +_,14 @@
@@ -349,6 +_,14 @@
public double ypos() {
return this.ypos;
@@ -1,24 +1,16 @@
--- a/net/minecraft/client/Options.java
+++ b/net/minecraft/client/Options.java
@@ -671,7 +_,8 @@
@@ -698,7 +_,8 @@
},
new OptionInstance.LazyEnum<>(
() -> Stream.concat(Stream.of(""), Minecraft.getInstance().getSoundManager().getAvailableSoundDevices().stream()).toList(),
- p_232011_ -> Minecraft.getInstance().isRunning() && p_232011_ != "" && !Minecraft.getInstance().getSoundManager().getAvailableSoundDevices().contains(p_232011_)
+ // FORGE: fix incorrect string comparison - PR #8767
+ p_232011_ -> Minecraft.getInstance().isRunning() && (p_232011_ == null || !p_232011_.isEmpty()) && !Minecraft.getInstance().getSoundManager().getAvailableSoundDevices().contains(p_232011_)
? Optional.empty()
: Optional.of(p_232011_),
? Optional.empty()
: Optional.of(p_232011_),
Codec.STRING
@@ -705,6 +_,7 @@
);
public boolean syncWrites;
public boolean startedCleanly = true;
+ private final Map<String, String> unknownKeys = new java.util.HashMap<>();
public OptionInstance<Boolean> darkMojangStudiosBackground() {
return this.darkMojangStudiosBackground;
@@ -1088,6 +_,7 @@
@@ -1079,6 +_,7 @@
}
public Options(Minecraft p_92138_, File p_92139_) {
@@ -26,16 +18,15 @@
this.minecraft = p_92138_;
this.optionsFile = new File(p_92139_, "options.txt");
boolean flag = Runtime.getRuntime().maxMemory() >= 1000000000L;
@@ -1222,15 +_,28 @@
this.startedCleanly = p_168428_.process("startedCleanly", this.startedCleanly);
p_168428_.process("showNowPlayingToast", this.showNowPlayingToast);
p_168428_.process("musicFrequency", this.musicFrequency);
+ processOptionsKeysOnly(p_168428_);
+ processOptionsEnd(p_168428_);
@@ -1210,12 +_,22 @@
p_168428_.process("telemetryOptInExtra", this.telemetryOptInExtra);
this.onboardAccessibility = p_168428_.process("onboardAccessibility", this.onboardAccessibility);
p_168428_.process("menuBackgroundBlurriness", this.menuBackgroundBlurriness);
+ processOptionsForge(p_168428_);
+ }
+ // FORGE: split off to allow reloading keys after mod loading is done
+ private void processOptionsKeysOnly(Options.FieldAccess p_168428_) {
+ // FORGE: split off to allow reloading options after mod loading is done
+ private void processOptionsForge(Options.FieldAccess p_168428_) {
for (KeyMapping keymapping : this.keyMappings) {
- String s = keymapping.saveString();
+ String s = keymapping.saveString() + (keymapping.getKeyModifier() != net.minecraftforge.client.settings.KeyModifier.NONE ? ":" + keymapping.getKeyModifier() : "");
@@ -50,13 +41,8 @@
+ }
}
}
+ }
+ private void processOptionsEnd(Options.FieldAccess p_168428_) {
for (SoundSource soundsource : SoundSource.values()) {
p_168428_.process("soundCategory_" + soundsource.getName(), this.soundSourceVolumes.get(soundsource));
}
@@ -1245,6 +_,10 @@
@@ -1233,6 +_,10 @@
}
public void load() {
@@ -67,60 +53,17 @@
try {
if (!this.optionsFile.exists()) {
return;
@@ -1269,7 +_,8 @@
this.graphicsMode.set(isTrue(optional.get()) ? GraphicsStatus.FANCY : GraphicsStatus.FAST);
@@ -1260,7 +_,8 @@
}
}
- this.processOptions(
+ java.util.function.Consumer<FieldAccess> processor = limited ? this::processOptionsKeysOnly : this::processOptions;
+ java.util.function.Consumer<FieldAccess> processor = limited ? this::processOptionsForge : this::processOptions;
+ processor.accept(
new Options.FieldAccess() {
@Nullable
private String getValue(String p_394210_) {
@@ -1350,6 +_,17 @@
);
compoundtag1.getString("fullscreenResolution").ifPresent(p_389133_ -> this.fullscreenVideoModeString = p_389133_);
KeyMapping.resetMapping();
+
+ if (limited) {
+ this.unknownKeys.clear();
+ } else {
+ var knownKeys = Arrays.stream(this.keyMappings).map(k -> "key_" + k.getName()).collect(Collectors.toSet());
+ for (var entry : compoundtag1.entrySet()) {
+ if (entry.getKey().startsWith("key_") && entry.getValue().asString().isPresent() && !knownKeys.contains(entry.getKey()))
+ this.unknownKeys.put(entry.getKey(), entry.getValue().asString().get());
+ }
+ }
+
} catch (Exception exception) {
LOGGER.error("Failed to load options", (Throwable)exception);
}
@@ -1377,9 +_,11 @@
public void save() {
try (final PrintWriter printwriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.optionsFile), StandardCharsets.UTF_8))) {
printwriter.println("version:" + SharedConstants.getCurrentVersion().dataVersion().version());
+ var seen = new java.util.HashSet<String>();
this.processOptions(
new Options.FieldAccess() {
public void writePrefix(String p_168491_) {
+ seen.add(p_168491_);
printwriter.print(p_168491_);
printwriter.print(':');
}
@@ -1435,6 +_,12 @@
if (s != null) {
printwriter.println("fullscreenResolution:" + s);
}
+ // Forge add any unknown keys so that Mods can add keybindings between vanilla loading/saving its config.
+ for (var entry : this.unknownKeys.entrySet()) {
+ if (!seen.contains(entry.getKey()))
+ printwriter.println(entry.getKey() + ":" + entry.getValue());
+ }
+
} catch (Exception exception) {
LOGGER.error("Failed to save options", (Throwable)exception);
}
@@ -1473,6 +_,7 @@
private String getValueOrNull(String p_168459_) {
@@ -1451,6 +_,7 @@
}
public void broadcastOptions() {
@@ -128,7 +71,7 @@
if (this.minecraft.player != null) {
this.minecraft.player.connection.broadcastClientInformation(this.buildPlayerInformation());
}
@@ -1586,6 +_,23 @@
@@ -1564,6 +_,23 @@
public static Component genericValueLabel(Component p_231901_, int p_231902_) {
return genericValueLabel(p_231901_, Component.literal(Integer.toString(p_231902_)));
@@ -1,32 +1,30 @@
--- a/net/minecraft/client/Screenshot.java
+++ b/net/minecraft/client/Screenshot.java
@@ -43,6 +_,13 @@
file2 = new File(file1, p_92297_);
}
@@ -54,14 +_,24 @@
file2 = new File(file1, p_92307_);
}
+ var event = new net.minecraftforge.client.event.ScreenshotEvent(p_389141_, file2);
+ if (net.minecraftforge.client.event.ScreenshotEvent.BUS.post(event)) {
+ p_92301_.accept(event.getCancelMessage());
+ return;
+ }
+ final File target = event.getScreenshotFile();
+ var event = net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenshot(nativeimage, file2);
+ if (event.isCanceled()) {
+ p_92311_.accept(event.getCancelMessage());
+ return;
+ }
+ final File target = event.getScreenshotFile();
+
Util.ioPool()
.execute(
() -> {
@@ -50,10 +_,13 @@
NativeImage $$4x = p_389141_;
try {
- p_389141_.writeToFile(file2);
- Component component = Component.literal(file2.getName())
+ p_389141_.writeToFile(target);
+ Component component = Component.literal(target.getName())
.withStyle(ChatFormatting.UNDERLINE)
.withStyle(p_389149_ -> p_389149_.withClickEvent(new ClickEvent.OpenFile(file2.getAbsoluteFile())));
+ if (event.getResultMessage() != null)
+ p_92301_.accept(event.getResultMessage());
+ else
p_92301_.accept(Component.translatable("screenshot.success", component));
} catch (Throwable throwable1) {
if (p_389141_ != null) {
Util.ioPool()
.execute(
() -> {
try {
- nativeimage.writeToFile(file2);
- Component component = Component.literal(file2.getName())
+ nativeimage.writeToFile(target);
+ Component component = Component.literal(target.getName())
.withStyle(ChatFormatting.UNDERLINE)
- .withStyle(p_168608_ -> p_168608_.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, file2.getAbsolutePath())));
+ .withStyle(p_168608_ -> p_168608_.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, target.getAbsolutePath())));
+ if (event.getResultMessage() != null)
+ p_92311_.accept(event.getResultMessage());
+ else
p_92311_.accept(Component.translatable("screenshot.success", component));
} catch (Exception exception) {
LOGGER.warn("Couldn't save screenshot", (Throwable)exception);
@@ -1,16 +1,16 @@
--- a/net/minecraft/client/color/block/BlockColors.java
+++ b/net/minecraft/client/color/block/BlockColors.java
@@ -30,7 +_,8 @@
@@ -29,7 +_,8 @@
@OnlyIn(Dist.CLIENT)
public class BlockColors {
private static final int DEFAULT = -1;
public static final int LILY_PAD_IN_WORLD = -14647248;
public static final int LILY_PAD_DEFAULT = -9321636;
- private final IdMapper<BlockColor> blockColors = new IdMapper<>(32);
+ // Forge: Use registry delegate as non-Vanilla block ids are not constant
+ private final java.util.Map<net.minecraft.core.Holder.Reference<Block>, BlockColor> blockColors = new java.util.HashMap<>(32);
private final Map<Block, Set<Property<?>>> coloringStates = Maps.newHashMap();
public static BlockColors createDefault() {
@@ -95,11 +_,12 @@
@@ -91,11 +_,12 @@
}, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM);
blockcolors.addColoringState(StemBlock.AGE, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM);
blockcolors.register((p_92596_, p_92597_, p_92598_, p_92599_) -> p_92597_ != null && p_92598_ != null ? -14647248 : -9321636, Blocks.LILY_PAD);
@@ -24,7 +24,7 @@
if (blockcolor != null) {
return blockcolor.getColor(p_92583_, null, null, 0);
} else {
@@ -109,13 +_,15 @@
@@ -105,13 +_,15 @@
}
public int getColor(BlockState p_92578_, @Nullable BlockAndTintGetter p_92579_, @Nullable BlockPos p_92580_, int p_92581_) {
@@ -0,0 +1,35 @@
--- a/net/minecraft/client/color/item/ItemColors.java
+++ b/net/minecraft/client/color/item/ItemColors.java
@@ -26,7 +_,8 @@
@OnlyIn(Dist.CLIENT)
public class ItemColors {
private static final int DEFAULT = -1;
- private final IdMapper<ItemColor> itemColors = new IdMapper<>(32);
+ // Forge: Use registry delegate as non-Vanilla item ids are not constant
+ private final java.util.Map<net.minecraft.core.Holder.Reference<Item>, ItemColor> itemColors = new java.util.HashMap<>(32);
public static ItemColors createDefault(BlockColors p_92684_) {
ItemColors itemcolors = new ItemColors();
@@ -101,17 +_,20 @@
(p_357654_, p_357655_) -> p_357655_ == 0 ? -1 : ARGB.opaque(p_357654_.getOrDefault(DataComponents.MAP_COLOR, MapItemColor.DEFAULT).rgb()),
Items.FILLED_MAP
);
+ net.minecraftforge.client.ForgeHooksClient.onItemColorsInit(itemcolors, p_92684_);
return itemcolors;
}
public int getColor(ItemStack p_92677_, int p_92678_) {
- ItemColor itemcolor = this.itemColors.byId(BuiltInRegistries.ITEM.getId(p_92677_.getItem()));
+ ItemColor itemcolor = this.itemColors.get(net.minecraftforge.registries.ForgeRegistries.ITEMS.getDelegateOrThrow(p_92677_.getItem()));
return itemcolor == null ? -1 : itemcolor.getColor(p_92677_, p_92678_);
}
+ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterColorHandlersEvent.Item} */
+ @Deprecated
public void register(ItemColor p_92690_, ItemLike... p_92691_) {
for (ItemLike itemlike : p_92691_) {
- this.itemColors.addMapping(p_92690_, Item.getId(itemlike.asItem()));
+ this.itemColors.put(net.minecraftforge.registries.ForgeRegistries.ITEMS.getDelegateOrThrow(itemlike.asItem()), p_92690_);
}
}
}
@@ -1,22 +0,0 @@
--- a/net/minecraft/client/data/Main.java
+++ b/net/minecraft/client/data/Main.java
@@ -31,13 +_,18 @@
OptionSpec<Void> optionspec1 = optionparser.accepts("client", "Include client generators");
OptionSpec<Void> optionspec2 = optionparser.accepts("all", "Include all generators");
OptionSpec<String> optionspec3 = optionparser.accepts("output", "Output folder").withRequiredArg().defaultsTo("generated");
+ OptionSpec<String> inputSpec = optionparser.accepts("input", "Input folder").withRequiredArg();
+ var loader = net.minecraftforge.data.loading.DatagenModLoader.setup(optionparser, true);
OptionSet optionset = optionparser.parse(p_375526_);
- if (!optionset.has(optionspec) && optionset.hasOptions()) {
+ if (!optionset.has(optionspec) && optionset.hasOptions() && loader.hasArgs(optionset)) {
+ var input = optionset.valuesOf(inputSpec).stream().map(Paths::get).toList();
Path path = Paths.get(optionspec3.value(optionset));
boolean flag = optionset.has(optionspec2);
boolean flag1 = flag || optionset.has(optionspec1);
Bootstrap.bootStrap();
ClientBootstrap.bootstrap();
+ if (!loader.run(optionset, path, input, flag, flag1, flag, flag, true))
+ return;
DataGenerator datagenerator = new DataGenerator(path, SharedConstants.getCurrentVersion(), true);
addClientProviders(datagenerator, flag1);
datagenerator.run();
@@ -1,12 +0,0 @@
--- a/net/minecraft/client/data/models/ItemModelGenerators.java
+++ b/net/minecraft/client/data/models/ItemModelGenerators.java
@@ -871,6 +_,9 @@
this.declareCustomModelItem(Items.COD);
this.declareCustomModelItem(Items.FEATHER);
this.declareCustomModelItem(Items.LEAD);
+ // moved from validate to here, because it's just vanilla default blocks
+ if (this.itemModelOutput instanceof ModelProvider.ItemInfoCollector collector)
+ collector.generateDefaultBlockModels();
}
@OnlyIn(Dist.CLIENT)
@@ -1,111 +0,0 @@
--- a/net/minecraft/client/data/models/ModelProvider.java
+++ b/net/minecraft/client/data/models/ModelProvider.java
@@ -45,11 +_,11 @@
@Override
public CompletableFuture<?> run(CachedOutput p_376268_) {
- ModelProvider.ItemInfoCollector modelprovider$iteminfocollector = new ModelProvider.ItemInfoCollector();
- ModelProvider.BlockStateGeneratorCollector modelprovider$blockstategeneratorcollector = new ModelProvider.BlockStateGeneratorCollector();
+ ModelProvider.ItemInfoCollector modelprovider$iteminfocollector = new ModelProvider.ItemInfoCollector(this::getKnownItems);
+ ModelProvider.BlockStateGeneratorCollector modelprovider$blockstategeneratorcollector = new ModelProvider.BlockStateGeneratorCollector(this::getKnownBlocks);
ModelProvider.SimpleModelCollector modelprovider$simplemodelcollector = new ModelProvider.SimpleModelCollector();
- new BlockModelGenerators(modelprovider$blockstategeneratorcollector, modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
- new ItemModelGenerators(modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
+ getBlockModelGenerators(modelprovider$blockstategeneratorcollector, modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
+ getItemModelGenerators(modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
modelprovider$blockstategeneratorcollector.validate();
modelprovider$iteminfocollector.finalizeAndValidate();
return CompletableFuture.allOf(
@@ -59,6 +_,22 @@
);
}
+ protected Stream<Block> getKnownBlocks() {
+ return BuiltInRegistries.BLOCK.stream().filter(block -> "minecraft".equals(block.builtInRegistryHolder().key().location().getNamespace()));
+ }
+
+ protected Stream<Item> getKnownItems() {
+ return BuiltInRegistries.ITEM.stream().filter(item -> "minecraft".equals(item.builtInRegistryHolder().key().location().getNamespace()));
+ }
+
+ protected BlockModelGenerators getBlockModelGenerators(BlockStateGeneratorCollector blocks, ItemInfoCollector items, SimpleModelCollector models) {
+ return new BlockModelGenerators(blocks, items, models);
+ }
+
+ protected ItemModelGenerators getItemModelGenerators(ItemInfoCollector items, SimpleModelCollector models) {
+ return new ItemModelGenerators(items, models);
+ }
+
@Override
public final String getName() {
return "Model Definitions";
@@ -67,6 +_,15 @@
@OnlyIn(Dist.CLIENT)
public static class BlockStateGeneratorCollector implements Consumer<BlockModelDefinitionGenerator> {
private final Map<Block, BlockModelDefinitionGenerator> generators = new HashMap<>();
+ private final Supplier<Stream<Block>> known;
+
+ public BlockStateGeneratorCollector() {
+ this(() -> BuiltInRegistries.BLOCK.stream().filter(block -> "minecraft".equals(block.builtInRegistryHolder().key().location().getNamespace())));
+ }
+
+ public BlockStateGeneratorCollector(Supplier<Stream<Block>> known) {
+ this.known = known;
+ }
public void accept(BlockModelDefinitionGenerator p_393399_) {
Block block = p_393399_.block();
@@ -77,7 +_,7 @@
}
public void validate() {
- Stream<Holder.Reference<Block>> stream = BuiltInRegistries.BLOCK.listElements().filter(p_376480_ -> true);
+ Stream<Holder.Reference<Block>> stream = known.get().map(Block::builtInRegistryHolder);
List<ResourceLocation> list = stream.filter(p_378423_ -> !this.generators.containsKey(p_378423_.value()))
.map(p_378200_ -> p_378200_.key().location())
.toList();
@@ -97,6 +_,15 @@
public static class ItemInfoCollector implements ItemModelOutput {
private final Map<Item, ClientItem> itemInfos = new HashMap<>();
private final Map<Item, Item> copies = new HashMap<>();
+ private final Supplier<Stream<Item>> known;
+
+ public ItemInfoCollector() {
+ this(() -> BuiltInRegistries.ITEM.stream().filter(item -> "minecraft".equals(item.builtInRegistryHolder().key().location().getNamespace())));
+ }
+
+ public ItemInfoCollector(Supplier<Stream<Item>> known) {
+ this.known = known;
+ }
@Override
public void accept(Item p_376450_, ItemModel.Unbaked p_378513_) {
@@ -115,7 +_,7 @@
this.copies.put(p_376965_, p_377438_);
}
- public void finalizeAndValidate() {
+ public void generateDefaultBlockModels() {
BuiltInRegistries.ITEM.forEach(p_378629_ -> {
if (!this.copies.containsKey(p_378629_)) {
if (p_378629_ instanceof BlockItem blockitem && !this.itemInfos.containsKey(blockitem)) {
@@ -124,6 +_,8 @@
}
}
});
+ }
+ public void finalizeAndValidate() {
this.copies.forEach((p_376289_, p_375718_) -> {
ClientItem clientitem = this.itemInfos.get(p_375718_);
if (clientitem == null) {
@@ -132,8 +_,8 @@
this.register(p_376289_, clientitem);
}
});
- List<ResourceLocation> list = BuiltInRegistries.ITEM
- .listElements()
+ List<ResourceLocation> list = known.get()
+ .map(item -> item.builtInRegistryHolder())
.filter(p_377225_ -> !this.itemInfos.containsKey(p_377225_.value()))
.map(p_378591_ -> p_378591_.key().location())
.toList();
@@ -1,11 +1,11 @@
--- a/net/minecraft/client/gui/Font.java
+++ b/net/minecraft/client/gui/Font.java
@@ -32,7 +_,7 @@
import org.joml.Matrix4f;
@@ -33,7 +_,7 @@
import org.joml.Vector3f;
@OnlyIn(Dist.CLIENT)
-public class Font {
+public class Font implements net.minecraftforge.client.extensions.IForgeFont {
private static final float EFFECT_DEPTH = 0.01F;
private static final float OVER_EFFECT_DEPTH = 0.01F;
private static final float UNDER_EFFECT_DEPTH = -0.01F;
private static final Vector3f SHADOW_OFFSET = new Vector3f(0.0F, 0.0F, 0.03F);
public static final int ALPHA_CUTOFF = 8;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/Gui.java
+++ b/net/minecraft/client/gui/Gui.java
@@ -151,7 +_,7 @@
@@ -147,7 +_,7 @@
public float vignetteBrightness = 1.0F;
private int toolHighlightTimer;
private ItemStack lastToolHighlight = ItemStack.EMPTY;
@@ -9,35 +9,50 @@
private final SubtitleOverlay subtitleOverlay;
private final SpectatorGui spectatorGui;
private final PlayerTabOverlay tabList;
@@ -194,6 +_,7 @@
() -> new JumpableVehicleBarRenderer(p_330021_)
);
@@ -167,7 +_,7 @@
private int lastBubblePopSoundPlayed;
private float autosaveIndicatorValue;
private float lastAutosaveIndicatorValue;
- private final LayeredDraw layers = new LayeredDraw();
+ private final LayeredDraw layers = new net.minecraftforge.client.gui.overlay.ForgeLayeredDraw(net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.VANILLA_ROOT, net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.COMBINE_LIST);
private float scopeScale;
public Gui(Minecraft p_330021_) {
@@ -179,14 +_,14 @@
this.bossOverlay = new BossHealthOverlay(p_330021_);
this.subtitleOverlay = new SubtitleOverlay(p_330021_);
this.resetTitleTimes();
+ net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.init(this, p_330021_);
- LayeredDraw layereddraw = new LayeredDraw()
+ LayeredDraw layereddraw = new net.minecraftforge.client.gui.overlay.ForgeLayeredDraw(net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.PRE_SLEEP_STACK, net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.PRE_LIST)
.add(this::renderCameraOverlays)
.add(this::renderCrosshair)
.add(this::renderHotbarAndDecorations)
.add(this::renderExperienceLevel)
.add(this::renderEffects)
.add((p_325313_, p_342678_) -> this.bossOverlay.render(p_325313_));
- LayeredDraw layereddraw1 = new LayeredDraw()
+ LayeredDraw layereddraw1 = new net.minecraftforge.client.gui.overlay.ForgeLayeredDraw(net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.POST_SLEEP_STACK,net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.POST_LIST)
.add(this::renderDemoOverlay)
.add((p_325315_, p_344521_) -> {
if (this.debugOverlay.showDebugScreen()) {
@@ -203,6 +_,7 @@
.add(layereddraw, () -> !p_330021_.options.hideGui)
.add(this::renderSleepOverlay)
.add(layereddraw1, () -> !p_330021_.options.hideGui);
+ ((net.minecraftforge.client.gui.overlay.ForgeLayeredDraw) layers).resolveLayers();
}
public void resetTitleTimes() {
@@ -204,6 +_,10 @@
public void render(GuiGraphics p_282884_, DeltaTracker p_342095_) {
if (this.minecraft.screen == null || !(this.minecraft.screen instanceof ReceivingLevelScreen)) {
+ if (Boolean.valueOf(true)) {
+ net.minecraftforge.client.gui.overlay.ForgeLayeredDraw.beginRender(p_282884_, p_342095_);
+ return;
+ }
if (!this.minecraft.options.hideGui) {
this.renderCameraOverlays(p_282884_, p_342095_);
this.renderCrosshair(p_282884_, p_342095_);
@@ -377,7 +_,7 @@
int i = Mth.floor(this.minecraft.mouseHandler.getScaledXPos(window));
int j = Mth.floor(this.minecraft.mouseHandler.getScaledYPos(window));
p_329202_.nextStratum();
@@ -345,7 +_,7 @@
Window window = this.minecraft.getWindow();
int i = Mth.floor(this.minecraft.mouseHandler.xpos() * (double)window.getGuiScaledWidth() / (double)window.getScreenWidth());
int j = Mth.floor(this.minecraft.mouseHandler.ypos() * (double)window.getGuiScaledHeight() / (double)window.getScreenHeight());
- this.chat.render(p_329202_, this.tickCount, i, j, false);
+ net.minecraftforge.client.ForgeHooksClient.onCustomizeChatEvent(p_329202_, this.chat, window, i, j, this.tickCount);
}
}
@@ -472,6 +_,8 @@
@@ -443,6 +_,8 @@
for (MobEffectInstance mobeffectinstance : Ordering.natural().reverse().sortedCopy(collection)) {
Holder<MobEffect> holder = mobeffectinstance.getEffect();
@@ -46,18 +61,18 @@
if (mobeffectinstance.showIcon()) {
int k = p_282812_.guiWidth();
int l = 1;
@@ -502,6 +_,7 @@
@@ -473,6 +_,7 @@
}
}
+ if (renderer.renderGuiIcon(mobeffectinstance, this, p_282812_, k, l, 0, f)) continue;
p_282812_.blitSprite(RenderPipelines.GUI_TEXTURED, getMobEffectSprite(holder), k + 3, l + 3, 18, 18, ARGB.white(f));
}
}
@@ -598,6 +_,10 @@
TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.get(holder);
int l1 = k;
int k1 = l;
@@ -623,6 +_,10 @@
}
public void renderSelectedItemName(GuiGraphics p_283501_) {
private void renderSelectedItemName(GuiGraphics p_283501_) {
+ renderSelectedItemName(p_283501_, 0);
+ }
+
@@ -65,7 +80,7 @@
Profiler.get().push("selectedItemName");
if (this.toolHighlightTimer > 0 && !this.lastToolHighlight.isEmpty()) {
MutableComponent mutablecomponent = Component.empty().append(this.lastToolHighlight.getHoverName()).withStyle(this.lastToolHighlight.getRarity().color());
@@ -605,9 +_,13 @@
@@ -630,9 +_,13 @@
mutablecomponent.withStyle(ChatFormatting.ITALIC);
}
@@ -81,7 +96,7 @@
if (!this.minecraft.gameMode.canHurtPlayer()) {
k += 14;
}
@@ -618,7 +_,7 @@
@@ -643,7 +_,7 @@
}
if (l > 0) {
@@ -90,8 +105,8 @@
}
}
@@ -1146,7 +_,7 @@
ItemStack itemstack = this.minecraft.player.getInventory().getSelectedItem();
@@ -1152,7 +_,7 @@
ItemStack itemstack = this.minecraft.player.getInventory().getSelected();
if (itemstack.isEmpty()) {
this.toolHighlightTimer = 0;
- } else if (this.lastToolHighlight.isEmpty() || !itemstack.is(this.lastToolHighlight.getItem()) || !itemstack.getHoverName().equals(this.lastToolHighlight.getHoverName())) {
@@ -1,164 +1,160 @@
--- a/net/minecraft/client/gui/GuiGraphics.java
+++ b/net/minecraft/client/gui/GuiGraphics.java
@@ -72,7 +_,7 @@
import org.joml.Vector3f;
@@ -53,7 +_,7 @@
import org.joml.Vector2ic;
@OnlyIn(Dist.CLIENT)
-public class GuiGraphics {
+public class GuiGraphics implements net.minecraftforge.client.extensions.IForgeGuiGraphics {
public static final float MAX_GUI_Z = 10000.0F;
public static final float MIN_GUI_Z = -10000.0F;
private static final int EXTRA_SPACE_AFTER_FIRST_TOOLTIP_LINE = 2;
private final Minecraft minecraft;
private final Matrix3x2fStack pose;
@@ -875,6 +_,7 @@
@@ -227,6 +_,11 @@
}
public int drawString(Font p_283343_, @Nullable String p_281896_, int p_283569_, int p_283418_, int p_281560_, boolean p_282130_) {
+ return this.drawString(p_283343_, p_281896_, (float)p_283569_, (float)p_283418_, p_281560_, p_282130_);
+ }
+
+ // Forge: Add float variant for x,y coordinates
+ public int drawString(Font p_283343_, @Nullable String p_281896_, float p_283569_, float p_283418_, int p_281560_, boolean p_282130_) {
return p_281896_ == null
? 0
: p_283343_.drawInBatch(
@@ -248,6 +_,11 @@
}
public int drawString(Font p_282636_, FormattedCharSequence p_281596_, int p_281586_, int p_282816_, int p_281743_, boolean p_282394_) {
+ return this.drawString(p_282636_, p_281596_, (float)p_281586_, (float)p_282816_, p_281743_, p_282394_);
+ }
+
+ // Forge: Add float variant for x,y coordinates
+ public int drawString(Font p_282636_, FormattedCharSequence p_281596_, float p_281586_, float p_282816_, int p_281743_, boolean p_282394_) {
return p_282636_.drawInBatch(
p_281596_,
(float)p_281586_,
@@ -872,6 +_,7 @@
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering item");
CrashReportCategory crashreportcategory = crashreport.addCategory("Item being rendered");
crashreportcategory.setDetail("Item Type", () -> String.valueOf(p_283653_.getItem()));
+ crashreportcategory.setDetail("Registry Name", () -> String.valueOf(net.minecraftforge.registries.ForgeRegistries.ITEMS.getKey(p_283653_.getItem())));
crashreportcategory.setDetail("Item Components", () -> String.valueOf(p_283653_.getComponents()));
crashreportcategory.setDetail("Item Foil", () -> String.valueOf(p_283653_.hasFoil()));
crashreportcategory.setDetail("Item Type", () -> String.valueOf(p_281675_.getItem()));
+ crashreportcategory.setDetail("Registry Name", () -> String.valueOf(net.minecraftforge.registries.ForgeRegistries.ITEMS.getKey(p_281675_.getItem())));
crashreportcategory.setDetail("Item Components", () -> String.valueOf(p_281675_.getComponents()));
crashreportcategory.setDetail("Item Foil", () -> String.valueOf(p_281675_.hasFoil()));
throw new ReportedException(crashreport);
@@ -893,6 +_,7 @@
this.renderItemCooldown(p_283349_, p_282641_, p_282146_);
@@ -892,13 +_,24 @@
this.renderItemCount(p_282005_, p_283349_, p_282641_, p_282146_, p_282803_);
this.pose.popMatrix();
this.renderItemCooldown(p_283349_, p_282641_, p_282146_);
this.pose.popPose();
+ net.minecraftforge.client.ItemDecoratorHandler.of(p_283349_).render(this, p_282005_, p_283349_, p_282641_, p_282146_);
}
}
@@ -904,21 +_,30 @@
this.setTooltipForNextFrame(this.minecraft.font, p_407686_, DefaultTooltipPositioner.INSTANCE, p_410475_, p_407139_, false);
}
+ private ItemStack tooltipStack = ItemStack.EMPTY;
+
public void setTooltipForNextFrame(Font p_408152_, ItemStack p_410145_, int p_410585_, int p_408354_) {
+ this.tooltipStack = p_410145_;
this.setTooltipForNextFrame(
p_408152_, Screen.getTooltipFromItem(this.minecraft, p_410145_), p_410145_.getTooltipImage(), p_410585_, p_408354_, p_410145_.get(DataComponents.TOOLTIP_STYLE)
+ private ItemStack tooltipStack = ItemStack.EMPTY;
public void renderTooltip(Font p_282308_, ItemStack p_282781_, int p_282687_, int p_282292_) {
+ this.tooltipStack = p_282781_;
this.renderTooltip(
p_282308_, Screen.getTooltipFromItem(this.minecraft, p_282781_), p_282781_.getTooltipImage(), p_282687_, p_282292_, p_282781_.get(DataComponents.TOOLTIP_STYLE)
);
+ this.tooltipStack = ItemStack.EMPTY;
}
public void setTooltipForNextFrame(Font p_407170_, List<Component> p_407123_, Optional<TooltipComponent> p_409349_, int p_406573_, int p_409911_) {
this.setTooltipForNextFrame(p_407170_, p_407123_, p_409349_, p_406573_, p_409911_, null);
}
+ public void setTooltipForNextFrame(Font font, List<Component> textComponents, Optional<TooltipComponent> tooltipComponent, ItemStack stack, int mouseX, int mouseY) {
+ this.tooltipStack = stack;
+ this.setTooltipForNextFrame(font, textComponents, tooltipComponent, mouseX, mouseY, stack.get(DataComponents.TOOLTIP_STYLE));
+ this.tooltipStack = ItemStack.EMPTY;
+ }
+
public void setTooltipForNextFrame(
Font p_407847_, List<Component> p_408847_, Optional<TooltipComponent> p_410489_, int p_409369_, int p_407472_, @Nullable ResourceLocation p_410303_
+ public void renderTooltip(Font font, List<Component> textComponents, Optional<TooltipComponent> tooltipComponent, ItemStack stack, int mouseX, int mouseY) {
+ this.tooltipStack = stack;
+ this.renderTooltip(font, textComponents, tooltipComponent, mouseX, mouseY, stack.get(DataComponents.TOOLTIP_STYLE));
+ this.tooltipStack = ItemStack.EMPTY;
}
public void renderTooltip(Font p_283128_, List<Component> p_282716_, Optional<TooltipComponent> p_281682_, int p_283678_, int p_281696_) {
@@ -908,8 +_,7 @@
public void renderTooltip(
Font p_362491_, List<Component> p_368544_, Optional<TooltipComponent> p_362815_, int p_366300_, int p_368952_, @Nullable ResourceLocation p_368469_
) {
- List<ClientTooltipComponent> list = p_408847_.stream().map(Component::getVisualOrderText).map(ClientTooltipComponent::create).collect(Util.toMutableList());
- p_410489_.ifPresent(p_325321_ -> list.add(list.isEmpty() ? 0 : 1, ClientTooltipComponent.create(p_325321_)));
+ List<ClientTooltipComponent> list = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_408847_, p_410489_, p_409369_, guiWidth(), guiHeight(), p_407847_);
this.setTooltipForNextFrameInternal(p_407847_, list, p_409369_, p_407472_, DefaultTooltipPositioner.INSTANCE, p_410303_, false);
- List<ClientTooltipComponent> list = p_368544_.stream().map(Component::getVisualOrderText).map(ClientTooltipComponent::create).collect(Util.toMutableList());
- p_362815_.ifPresent(p_325321_ -> list.add(list.isEmpty() ? 0 : 1, ClientTooltipComponent.create(p_325321_)));
+ List<ClientTooltipComponent> list = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_368544_, p_362815_, p_366300_, guiWidth(), guiHeight(), p_362491_);
this.renderTooltipInternal(p_362491_, list, p_366300_, p_368952_, DefaultTooltipPositioner.INSTANCE, p_368469_);
}
@@ -931,7 +_,22 @@
@@ -922,7 +_,22 @@
}
public void setComponentTooltipForNextFrame(Font p_406239_, List<Component> p_410275_, int p_410594_, int p_409343_) {
- this.setComponentTooltipForNextFrame(p_406239_, p_410275_, p_410594_, p_409343_, null);
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_410275_, p_410594_, guiWidth(), guiHeight(), p_406239_);
+ this.setTooltipForNextFrameInternal(p_406239_, components, p_410594_, p_409343_, DefaultTooltipPositioner.INSTANCE, null, false);
public void renderComponentTooltip(Font p_282739_, List<Component> p_281832_, int p_282191_, int p_282446_) {
- this.renderComponentTooltip(p_282739_, p_281832_, p_282191_, p_282446_, null);
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_281832_, p_282191_, guiWidth(), guiHeight(), p_282739_);
+ this.renderTooltipInternal(p_282739_, components, p_282191_, p_282446_, DefaultTooltipPositioner.INSTANCE, null);
+ }
+
+ public void renderComponentTooltip(Font font, List<? extends net.minecraft.network.chat.FormattedText> tooltips, int mouseX, int mouseY, ItemStack stack) {
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(stack, tooltips, mouseX, guiWidth(), guiHeight(), font);
+ this.setTooltipForNextFrameInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null, false);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null);
+ this.tooltipStack = ItemStack.EMPTY;
+ }
+
+ public void renderComponentTooltipFromElements(Font font, List<com.mojang.datafixers.util.Either<FormattedText, TooltipComponent>> elements, int mouseX, int mouseY, ItemStack stack) {
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponentsFromElements(stack, elements, mouseX, guiWidth(), guiHeight(), font);
+ this.setTooltipForNextFrameInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null, false);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null);
+ this.tooltipStack = ItemStack.EMPTY;
}
public void setComponentTooltipForNextFrame(Font p_408650_, List<Component> p_407512_, int p_406019_, int p_408123_, @Nullable ResourceLocation p_409993_) {
@@ -981,9 +_,14 @@
public void renderComponentTooltip(Font p_369090_, List<Component> p_365405_, int p_368143_, int p_366244_, @Nullable ResourceLocation p_364763_) {
@@ -964,11 +_,13 @@
@Nullable ResourceLocation p_368234_
) {
if (!p_409928_.isEmpty()) {
if (this.deferredTooltip == null || p_410618_) {
- this.deferredTooltip = () -> this.renderTooltip(p_406605_, p_409928_, p_407794_, p_408784_, p_408798_, p_407676_);
+ final var stackContext = this.tooltipStack;
+ this.deferredTooltip = () -> this.renderTooltip(p_406605_, p_409928_, p_407794_, p_408784_, p_408798_, p_407676_, stackContext);
if (!p_282615_.isEmpty()) {
+ var preEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipPre(this.tooltipStack, this, p_283230_, p_283417_, guiWidth(), guiHeight(), p_282615_, p_282675_, p_282442_);
+ if (preEvent.isCanceled()) return;
int i = 0;
int j = p_282615_.size() == 1 ? -2 : 0;
for (ClientTooltipComponent clienttooltipcomponent : p_282615_) {
- int k = clienttooltipcomponent.getWidth(p_282675_);
+ int k = clienttooltipcomponent.getWidth(preEvent.getFont());
if (k > i) {
i = k;
}
@@ -978,18 +_,19 @@
int i2 = i;
int j2 = j;
- Vector2ic vector2ic = p_282442_.positionTooltip(this.guiWidth(), this.guiHeight(), p_283230_, p_283417_, i, j);
+ Vector2ic vector2ic = p_282442_.positionTooltip(this.guiWidth(), this.guiHeight(), preEvent.getX(), preEvent.getY(), i2, j2);
int l = vector2ic.x();
int i1 = vector2ic.y();
this.pose.pushPose();
int j1 = 400;
- TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, 400, p_368234_);
+ var background_event = net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTooltipBackground(this.tooltipStack, this, l, i1, preEvent.getFont(), p_282615_, p_368234_);
+ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, 400, background_event.getBackground());
this.pose.translate(0.0F, 0.0F, 400.0F);
int k1 = i1;
for (int l1 = 0; l1 < p_282615_.size(); l1++) {
ClientTooltipComponent clienttooltipcomponent1 = p_282615_.get(l1);
- clienttooltipcomponent1.renderText(p_282675_, l, k1, this.pose.last().pose(), this.bufferSource);
+ clienttooltipcomponent1.renderText(preEvent.getFont(), l, k1, this.pose.last().pose(), this.bufferSource);
k1 += clienttooltipcomponent1.getHeight(p_282675_) + (l1 == 0 ? 2 : 0);
}
@@ -997,7 +_,7 @@
for (int k2 = 0; k2 < p_282615_.size(); k2++) {
ClientTooltipComponent clienttooltipcomponent2 = p_282615_.get(k2);
- clienttooltipcomponent2.renderImage(p_282675_, l, k1, i2, j2, this);
+ clienttooltipcomponent2.renderImage(preEvent.getFont(), l, k1, i2, j2, this);
k1 += clienttooltipcomponent2.getHeight(p_282675_) + (k2 == 0 ? 2 : 0);
}
@@ -1054,6 +_,10 @@
}
}
}
+ }
+
+ public void renderTooltip(Font p_283128_, List<ClientTooltipComponent> p_282716_, int p_283678_, int p_281696_, ClientTooltipPositioner p_409451_, @Nullable ResourceLocation p_409298_) {
+ renderTooltip(p_283128_, p_282716_, p_283678_, p_281696_, p_409451_, p_409298_, ItemStack.EMPTY);
+ public MultiBufferSource.BufferSource getBufferSource() {
+ return this.bufferSource;
}
public void renderTooltip(
@@ -992,13 +_,16 @@
int p_283678_,
int p_281696_,
ClientTooltipPositioner p_409451_,
- @Nullable ResourceLocation p_409298_
+ @Nullable ResourceLocation p_409298_,
+ ItemStack itemStack
) {
+ var preEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipPre(itemStack, this, p_283678_, p_281696_, guiWidth(), guiHeight(), p_282716_, p_283128_, p_409451_, p_409298_);
+ if (preEvent == null) return;
int i = 0;
int j = p_282716_.size() == 1 ? -2 : 0;
for (ClientTooltipComponent clienttooltipcomponent : p_282716_) {
- int k = clienttooltipcomponent.getWidth(p_283128_);
+ int k = clienttooltipcomponent.getWidth(preEvent.getFont());
if (k > i) {
i = k;
}
@@ -1008,16 +_,17 @@
int l1 = i;
int i2 = j;
- Vector2ic vector2ic = p_409451_.positionTooltip(this.guiWidth(), this.guiHeight(), p_283678_, p_281696_, i, j);
+ Vector2ic vector2ic = p_409451_.positionTooltip(this.guiWidth(), this.guiHeight(), preEvent.getX(), preEvent.getY(), i, j);
int l = vector2ic.x();
int i1 = vector2ic.y();
this.pose.pushMatrix();
- TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, p_409298_);
+ var background = net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTooltipBackground(this.tooltipStack, this, l, i1, preEvent.getFont(), p_282716_, preEvent.getBackground());
+ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, background.getBackground());
int j1 = i1;
for (int k1 = 0; k1 < p_282716_.size(); k1++) {
ClientTooltipComponent clienttooltipcomponent1 = p_282716_.get(k1);
- clienttooltipcomponent1.renderText(this, p_283128_, l, j1);
+ clienttooltipcomponent1.renderText(this, preEvent.getFont(), l, j1);
j1 += clienttooltipcomponent1.getHeight(p_283128_) + (k1 == 0 ? 2 : 0);
}
@@ -1025,7 +_,7 @@
for (int j2 = 0; j2 < p_282716_.size(); j2++) {
ClientTooltipComponent clienttooltipcomponent2 = p_282716_.get(j2);
- clienttooltipcomponent2.renderImage(p_283128_, l, j1, l1, i2, this);
+ clienttooltipcomponent2.renderImage(preEvent.getFont(), l, j1, l1, i2, this);
j1 += clienttooltipcomponent2.getHeight(p_283128_) + (j2 == 0 ? 2 : 0);
}
@@ -1222,6 +_,14 @@
public void submitProfilerChartRenderState(List<ResultField> p_408565_, int p_410147_, int p_406156_, int p_407365_, int p_408180_) {
this.guiRenderState.submitPicturesInPictureState(new GuiProfilerChartRenderState(p_408565_, p_410147_, p_406156_, p_407365_, p_408180_, this.scissorStack.peek()));
+ }
+
+ public GuiRenderState getRenderState() {
+ return this.guiRenderState;
+ }
+
+ public GuiGraphics.ScissorStack getScissorStack() {
+ return this.scissorStack;
}
@OnlyIn(Dist.CLIENT)
public void drawSpecial(Consumer<MultiBufferSource> p_367429_) {
@@ -1,11 +1,11 @@
--- a/net/minecraft/client/gui/components/AbstractButton.java
+++ b/net/minecraft/client/gui/components/AbstractButton.java
@@ -38,7 +_,7 @@
@@ -39,7 +_,7 @@
this.getHeight(),
ARGB.white(this.alpha)
);
- int i = ARGB.color(this.alpha, this.active ? -1 : -6250336);
- int i = this.active ? 16777215 : 10526880;
+ int i = getFGColor();
this.renderString(p_281670_, minecraft.font, i);
this.renderString(p_281670_, minecraft.font, i | Mth.ceil(this.alpha * 255.0F) << 24);
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/components/AbstractWidget.java
+++ b/net/minecraft/client/gui/components/AbstractWidget.java
@@ -236,6 +_,25 @@
@@ -259,6 +_,25 @@
this.focused = p_93693_;
}
@@ -11,7 +11,7 @@
+
+ public int getFGColor() {
+ if (packedFGColor != UNSET_FG_COLOR) return packedFGColor;
+ return net.minecraft.util.ARGB.color(this.alpha, this.active ? -1 : -6250336); // White : Light Grey
+ return this.active ? 16777215 : 10526880; // White : Light Grey
+ }
+
+ public void setFGColor(int color) {
@@ -1,17 +1,17 @@
--- a/net/minecraft/client/gui/components/BossHealthOverlay.java
+++ b/net/minecraft/client/gui/components/BossHealthOverlay.java
@@ -67,13 +_,16 @@
@@ -66,13 +_,16 @@
for (LerpingBossEvent lerpingbossevent : this.events.values()) {
int k = i / 2 - 91;
+ var event = net.minecraftforge.client.ForgeHooksClient.onCustomizeBossEventProgress(p_283175_, this.minecraft.getWindow(), lerpingbossevent, k, j, 10 + this.minecraft.font.lineHeight);
+ if (event != null) {
+ if (!event.isCanceled()) {
this.drawBar(p_283175_, k, j, lerpingbossevent);
Component component = lerpingbossevent.getName();
int l = this.minecraft.font.width(component);
int i1 = i / 2 - l / 2;
int j1 = j - 9;
p_283175_.drawString(this.minecraft.font, component, i1, j1, -1);
p_283175_.drawString(this.minecraft.font, component, i1, j1, 16777215);
- j += 10 + 9;
+ }
+ j += event.getIncrement();
Loaded 100 of 1212 files, more files were not shown because too many files have changed in this diff. Show more