mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 01:04:24 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8255d7aed3 | ||
|
|
617ecb7ad3 | ||
|
|
dd8239c255 | ||
|
|
bdddc8c5d4 | ||
|
|
c1c619a109 | ||
|
|
f7eea35cb9 | ||
|
|
a2434e1607 | ||
|
|
b806ecd0ff | ||
|
|
8358b800e9 | ||
|
|
b25a092cf1 | ||
|
|
d812fdd0a3 | ||
|
|
2d3ee8a228 | ||
|
|
97a9ca65f1 | ||
|
|
f043fbbc51 | ||
|
|
a19ab3a8d4 | ||
|
|
bc0517a404 | ||
|
|
dc9c0d7e35 | ||
|
|
1a2207b3b2 | ||
|
|
84ab9764e3 | ||
|
|
bef68991f0 | ||
|
|
526c13d662 | ||
|
|
67ffb78c23 | ||
|
|
8f407c3a22 | ||
|
|
8980252e16 | ||
|
|
3baee80485 | ||
|
|
ca9599bb4d | ||
|
|
051db7907a | ||
|
|
bdba5ef2d3 | ||
|
|
838b9c0eda | ||
|
|
be584c54aa | ||
|
|
1b3640b42d | ||
|
|
be5dab5801 | ||
|
|
aae628cd18 | ||
|
|
e7bd08649f | ||
|
|
e1017a4c7e | ||
|
|
6f8ba9d295 | ||
|
|
ac94478ae7 | ||
|
|
515c6082e0 | ||
|
|
a753598113 | ||
|
|
bc6c4be4e4 | ||
|
|
98823a8f07 | ||
|
|
ecd8f1e54d | ||
|
|
b0caea8e20 | ||
|
|
e0477f8776 | ||
|
|
94e1e54b53 | ||
|
|
9ce72331b7 | ||
|
|
1c31f42dae | ||
|
|
0978a94358 | ||
|
|
e956a9c9f3 | ||
|
|
82026d11a4 | ||
|
|
6d233ac75c | ||
|
|
73c1934e7e | ||
|
|
bf1194ec75 | ||
|
|
22d2740725 | ||
|
|
02f26dc7a1 | ||
|
|
db14cbb0e0 | ||
|
|
a2b35cae92 | ||
|
|
aab0e4c82e | ||
|
|
6609708d14 | ||
|
|
ed198f062c | ||
|
|
4e2d656e9d | ||
|
|
2a4230868f | ||
|
|
cf778b1759 | ||
|
|
1b6daddd40 | ||
|
|
d7b137d144 | ||
|
|
b5d5855559 | ||
|
|
c0aa8dd808 | ||
|
|
4f2f5c02a0 | ||
|
|
7a6843fa4a | ||
|
|
f0ecf16c6b | ||
|
|
8998fa71b2 | ||
|
|
4e677a7558 | ||
|
|
07254b36d7 | ||
|
|
a51b8d256d | ||
|
|
75fcd9448e | ||
|
|
6b45999702 | ||
|
|
a4f52f4057 | ||
|
|
b8b3201372 | ||
|
|
41deadc1e2 | ||
|
|
82e8d06e54 | ||
|
|
51db5f2ff7 | ||
|
|
2ec9e515ff | ||
|
|
0579572148 | ||
|
|
83f4e6353c | ||
|
|
130953e519 | ||
|
|
7981093591 | ||
|
|
79112d6208 | ||
|
|
a3eb6263f4 | ||
|
|
d91bc9c73d | ||
|
|
c807665ab9 | ||
|
|
7b97c181b9 | ||
|
|
c42b0847d2 | ||
|
|
f182cb00c1 | ||
|
|
3181b5da23 | ||
|
|
983c119477 | ||
|
|
874ff1bba2 | ||
|
|
06d9d89f98 | ||
|
|
c713bad8c3 | ||
|
|
fe19491822 | ||
|
|
c80e8a1aca | ||
|
|
6845c094ab | ||
|
|
3c1126a7b4 | ||
|
|
326e0329b9 | ||
|
|
f9d0daa91c | ||
|
|
094200e687 | ||
|
|
bb4818630c | ||
|
|
7af3155b39 | ||
|
|
d988b4a811 | ||
|
|
18f5bdb7ca | ||
|
|
f41d493552 | ||
|
|
8cd2c9c63f | ||
|
|
427b335cac | ||
|
|
2049096c6f | ||
|
|
98d4fa6dc2 | ||
|
|
5306471aec | ||
|
|
aa8818b049 | ||
|
|
2d86f17363 | ||
|
|
3a36a01913 | ||
|
|
47d70a7f31 | ||
|
|
d5b5e6f4db | ||
|
|
e76d814439 | ||
|
|
b8b40e1f54 | ||
|
|
5e8c786406 | ||
|
|
5b8224f839 | ||
|
|
cd621eb081 | ||
|
|
b1113f0363 | ||
|
|
daf5933b79 | ||
|
|
47fd2e8604 | ||
|
|
05297fd72f | ||
|
|
f20cf19f94 | ||
|
|
061cd3da53 | ||
|
|
03202a8ab4 | ||
|
|
8a67be4afd | ||
|
|
4c1ab67f33 | ||
|
|
7e06a2105f | ||
|
|
4a0c8be742 | ||
|
|
0c030ee5e1 | ||
|
|
1134fac54c | ||
|
|
ac44d72530 | ||
|
|
12468bd8d2 | ||
|
|
a98eeb9d08 | ||
|
|
b558b132cd | ||
|
|
c102633566 | ||
|
|
cce002ad29 | ||
|
|
b1ed321438 | ||
|
|
c7c2478cb0 | ||
|
|
b70d99489b | ||
|
|
57f45eaca0 | ||
|
|
52fcc4d649 | ||
|
|
959ab9abc9 | ||
|
|
c3a91872fe | ||
|
|
4d074f0a1e | ||
|
|
c2225ab1da | ||
|
|
bb03b1a7d1 | ||
|
|
be7275443f | ||
|
|
dc1c973684 | ||
|
|
06d568408c | ||
|
|
2256e88fb4 | ||
|
|
9b962c8ff0 | ||
|
|
7656b75992 | ||
|
|
58a5449c2f | ||
|
|
702abe0665 | ||
|
|
2070b77fd4 | ||
|
|
fd00822015 | ||
|
|
17565c0ea2 | ||
|
|
22668ad2c2 | ||
|
|
0dcc3d700d | ||
|
|
2ab3d9b8a3 | ||
|
|
d578d8f6df | ||
|
|
fd61016a7e | ||
|
|
7f77d24f45 | ||
|
|
3ebdcb34d1 | ||
|
|
05240fecf7 | ||
|
|
d5860d7cfa | ||
|
|
7bb97dafda | ||
|
|
ca90babc4a | ||
|
|
4b813e4319 | ||
|
|
fa84c22662 | ||
|
|
2ae640b530 | ||
|
|
4f95a20c5e | ||
|
|
915d570b17 | ||
|
|
5979636ee5 | ||
|
|
5acfc6ae3c | ||
|
|
48341120fb | ||
|
|
ff45bb4c27 | ||
|
|
eabba46595 | ||
|
|
683bf99fe4 | ||
|
|
2a05c7c01d | ||
|
|
e386229b66 | ||
|
|
59b8ec5625 | ||
|
|
50ae5db357 | ||
|
|
3aa99a1250 | ||
|
|
00c8513129 | ||
|
|
9c1404fecc | ||
|
|
c11686ab6c | ||
|
|
2818984f6c | ||
|
|
db225ed04a | ||
|
|
0ec4c34a34 | ||
|
|
597ebc3267 | ||
|
|
e16f54eebe | ||
|
|
27480c15fa | ||
|
|
df0dea59f3 | ||
|
|
d7bc564512 | ||
|
|
e6a73ef36c | ||
|
|
1ba7c6aecd | ||
|
|
7c5e95222e | ||
|
|
38df3d2a15 | ||
|
|
3beaa817f3 | ||
|
|
3ebd7ba0ef | ||
|
|
1ba9c34650 | ||
|
|
2f9e726aea | ||
|
|
ade2b8cc80 | ||
|
|
9b144f4541 | ||
|
|
0c35436217 | ||
|
|
0e66b7b217 |
No files matched your search
@@ -1,16 +0,0 @@
|
||||
# Configuration for support-requests - https://github.com/dessant/support-requests
|
||||
|
||||
# Label used to mark issues as support requests
|
||||
supportLabel: Forum
|
||||
# Comment to post on issues marked as support requests. Add a link
|
||||
# to a support page, or set to `false` to disable
|
||||
supportComment: >
|
||||
👋 We use the issue tracker exclusively for final bug reports and feature requests.
|
||||
However, this issue appears to be better suited for the
|
||||
[Forge Support Forums](http://www.minecraftforge.net/forum/forum/18-support-bug-reports/).
|
||||
Please create a new topic on the support forum with this issue, and the conversation can
|
||||
continue there.
|
||||
# Whether to close issues marked as support requests
|
||||
close: true
|
||||
# Whether to lock issues marked as support requests
|
||||
lock: true
|
||||
@@ -0,0 +1,42 @@
|
||||
name: 'Spam label'
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
discussion:
|
||||
types: [labeled]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
pull-requests: write
|
||||
discussions: write
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
if: ${{ (github.event.label.name == 'spam') && (github.event.action == 'labeled') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: peter-evans/close-issue@v2
|
||||
name: Close Issue
|
||||
with:
|
||||
close-reason: 'not_planned'
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
- run: gh pr close ${{ github.event.pull_request.html_url }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: Close PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
- uses: maxkomarychev/[email protected]
|
||||
name: Lock PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
issue_number: ${{ github.event.number }}
|
||||
- uses: OSDKDev/[email protected]
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
name: Lock issue
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
@@ -0,0 +1,27 @@
|
||||
name: Support Requests
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
- reopened
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v2
|
||||
with:
|
||||
support-label: Forum
|
||||
issue-comment: >
|
||||
:wave: We use the issue tracker exclusively for final bug reports and feature requests.
|
||||
However, this issue appears to be better suited for the
|
||||
[Forge Support Forums](https://forums.minecraftforge.net/) or
|
||||
[Forge Discord](https://discord.gg/UvedJ9m). Please create a new topic on the support forum
|
||||
with this issue or ask in the `#tech-support` channel in the Discord server, and the
|
||||
conversation can continue there.
|
||||
lock-issue: true
|
||||
Vendored
+74
-2
@@ -1,5 +1,7 @@
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.githubIssues
|
||||
import jetbrains.buildServer.configs.kotlin.*
|
||||
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
|
||||
|
||||
/*
|
||||
The settings script is an entry point for defining a TeamCity
|
||||
@@ -30,11 +32,13 @@ project {
|
||||
buildType(Build)
|
||||
buildType(BuildSecondaryBranches)
|
||||
buildType(PullRequests)
|
||||
buildType(PullRequestChecks)
|
||||
buildType(PullRequestCompatibility)
|
||||
|
||||
params {
|
||||
text("docker_jdk_version", "17", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("docker_gradle_version", "7.4", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("git_main_branch", "1.18.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("docker_gradle_version", "7.5.1", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("git_main_branch", "1.19.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("git_branch_spec", """
|
||||
+:refs/heads/(main*)
|
||||
+:refs/heads/(master*)
|
||||
@@ -134,3 +138,71 @@ object PullRequests : BuildType({
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
|
||||
object PullRequestChecks : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__PullRequestChecks")
|
||||
name = "Pull Requests (Checks)"
|
||||
description = "Checks pull requests for the project"
|
||||
|
||||
steps {
|
||||
gradle {
|
||||
name = "Check"
|
||||
id = "RUNNER_10_Check"
|
||||
|
||||
tasks = "checkAll"
|
||||
gradleParams = "--continue %gradle_custom_args%"
|
||||
enableStacktrace = true
|
||||
dockerImage = "%docker_gradle_image%"
|
||||
dockerRunParameters = """
|
||||
-v "/opt/cache/agent/gradle:/home/gradle/.gradle"
|
||||
-v "/opt/cache/shared/gradle:/home/gradle/rocache:ro"
|
||||
--network=host
|
||||
-u 1000:1000
|
||||
%docker_additional_args%
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
|
||||
object PullRequestCompatibility : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__PullRequestCompatibility")
|
||||
name = "Pull Requests (Compatibility)"
|
||||
description = "Validates binary compatibility for pull requests made to the project"
|
||||
|
||||
steps {
|
||||
gradle {
|
||||
name = "Validate"
|
||||
id = "RUNNER_10_Compatibility"
|
||||
|
||||
tasks = "checkJarCompatibility"
|
||||
gradleParams = "--continue %gradle_custom_args%"
|
||||
enableStacktrace = true
|
||||
dockerImage = "%docker_gradle_image%"
|
||||
dockerRunParameters = """
|
||||
-v "/opt/cache/agent/gradle:/home/gradle/.gradle"
|
||||
-v "/opt/cache/shared/gradle:/home/gradle/rocache:ro"
|
||||
--network=host
|
||||
-u 1000:1000
|
||||
%docker_additional_args%
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
+64
-58
@@ -19,9 +19,9 @@ plugins {
|
||||
id 'com.github.ben-manes.versions' version '0.36.0'
|
||||
id 'net.minecraftforge.gradleutils' version '2.+'
|
||||
id 'eclipse'
|
||||
id 'de.undercouch.download' version '4.1.2'
|
||||
id 'net.minecraftforge.gradle.patcher' version '[5.1.39,)' apply false
|
||||
id 'net.minecraftforge.gradle.mcp' version '[5.1.39,)' apply false
|
||||
id 'de.undercouch.download' version '5.1.3'
|
||||
id 'net.minecraftforge.gradle.patcher' version '[5.1.50,5.2.0)' apply false
|
||||
id 'net.minecraftforge.gradle.mcp' version '[5.1.50,5.2.0)' apply false
|
||||
}
|
||||
|
||||
Util.init() //Init all our extension methods!
|
||||
@@ -36,16 +36,17 @@ ext {
|
||||
]
|
||||
}
|
||||
MAPPING_CHANNEL = 'official'
|
||||
MAPPING_VERSION = '1.19'
|
||||
MC_VERSION = '1.19'
|
||||
MCP_VERSION = '20220607.102129'
|
||||
SPI_VERSION = '4.0.10'
|
||||
MAPPING_VERSION = '1.19.3'
|
||||
MC_VERSION = '1.19.3'
|
||||
MC_NEXT_VERSION = '1.20'
|
||||
MCP_VERSION = '20221207.122022'
|
||||
SPI_VERSION = '6.0.0'
|
||||
ACCESSTRANSFORMERS_VERSION = '8.0.4'
|
||||
COREMODS_VERSION = '5.0.1'
|
||||
EVENTBUS_VERSION = '5.0.3'
|
||||
MODLAUNCHER_VERSION = '9.1.3'
|
||||
SECUREJARHANDLER_VERSION = '1.0.3'
|
||||
BOOTSTRAPLAUNCHER_VERSION = '1.0.0'
|
||||
EVENTBUS_VERSION = '6.0.3'
|
||||
MODLAUNCHER_VERSION = '10.0.8'
|
||||
SECUREJARHANDLER_VERSION = '2.1.4'
|
||||
BOOTSTRAPLAUNCHER_VERSION = '1.1.2'
|
||||
ASM_VERSION = '9.3'
|
||||
INSTALLER_VERSION = '2.1.+'
|
||||
MIXIN_VERSION = '0.8.5'
|
||||
@@ -55,13 +56,14 @@ ext {
|
||||
JETBRAINS_ANNOTATIONS_VERSION = '23.0.0'
|
||||
SLF4J_API_VERSION = '1.8.0-beta4'
|
||||
APACHE_MAVEN_ARTIFACT_VERSION = '3.8.5'
|
||||
JARJAR_VERSION = '0.3.18'
|
||||
|
||||
// These versions should be kept in sync with the version manifest JSON
|
||||
// To use a version newer than the version manifest JSON, the dependency must be added to the installer configuration
|
||||
MOJANG_LOGGING_VERSION = '1.0.0'
|
||||
LOG4J_VERSION = '2.17.0'
|
||||
GUAVA_VERSION = '31.0.1-jre'
|
||||
GSON_VERSION = '2.8.9'
|
||||
MOJANG_LOGGING_VERSION = '1.1.1'
|
||||
LOG4J_VERSION = '2.19.0'
|
||||
GUAVA_VERSION = '31.1-jre'
|
||||
GSON_VERSION = '2.10'
|
||||
APACHE_COMMONS_LANG3_VERSION = '3.12.0'
|
||||
JOPT_SIMPLE_VERSION = '5.0.4'
|
||||
COMMONS_IO_VERSION = '2.11.0'
|
||||
@@ -75,7 +77,7 @@ ext {
|
||||
INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.3.0'
|
||||
JAR_SPLITTER = 'net.minecraftforge:jarsplitter:1.1.4'
|
||||
FART = 'net.minecraftforge:ForgeAutoRenamingTool:0.1.22:all'
|
||||
MIN_TAG_FOR_CHANGELOG = "39.0"
|
||||
MIN_TAG_FOR_CHANGELOG = '41.0'
|
||||
}
|
||||
|
||||
println('Version: ' + VERSION +
|
||||
@@ -94,7 +96,7 @@ def extraTxts = [
|
||||
]
|
||||
|
||||
task downloadVersionManifest(type: Download) {
|
||||
src 'https://launchermeta.mojang.com/mc/game/version_manifest_v2.json'
|
||||
src 'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json'
|
||||
dest file('build/versions/version_manifest.json')
|
||||
useETag 'all'
|
||||
onlyIfModified true
|
||||
@@ -260,6 +262,7 @@ def sharedDeps = {
|
||||
moduleonly "org.ow2.asm:asm-util:${ASM_VERSION}"
|
||||
moduleonly "org.ow2.asm:asm-analysis:${ASM_VERSION}"
|
||||
moduleonly "cpw.mods:bootstraplauncher:${BOOTSTRAPLAUNCHER_VERSION}"
|
||||
moduleonly "net.minecraftforge:JarJarFileSystems:${JARJAR_VERSION}"
|
||||
|
||||
installer "cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}"
|
||||
installer "org.ow2.asm:asm:${ASM_VERSION}"
|
||||
@@ -283,6 +286,8 @@ def sharedDeps = {
|
||||
installer "org.jline:jline-terminal:${JLINE_VERSION}" // Dep of TerminalConsoleAppender
|
||||
installer "org.spongepowered:mixin:${MIXIN_VERSION}"
|
||||
installer 'org.openjdk.nashorn:nashorn-core:15.3'
|
||||
installer "net.minecraftforge:JarJarSelector:${JARJAR_VERSION}"
|
||||
installer "net.minecraftforge:JarJarMetadata:${JARJAR_VERSION}"
|
||||
|
||||
/*
|
||||
installer 'org.lwjgl:lwjgl:3.2.2'
|
||||
@@ -375,7 +380,8 @@ def sharedFmlonlyForge = { Project prj ->
|
||||
environment 'MOD_CLASSES', '{source_roots}'
|
||||
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
||||
|
||||
property 'nativesDirectory', '{natives}'
|
||||
// Natives are loaded from the classpath now in all cases
|
||||
// property 'nativesDirectory', '{natives}'
|
||||
if (prj.name == 'forge') {
|
||||
property 'forge.enableGameTest', 'true'
|
||||
}
|
||||
@@ -429,6 +435,8 @@ def sharedFmlonlyForge = { Project prj ->
|
||||
run.args '--fml.forgeGroup', prj.group
|
||||
run.args '--fml.mcpVersion', MCP_VERSION
|
||||
|
||||
run.jvmArgs '-Djava.net.preferIPv6Addresses=system'
|
||||
|
||||
if (run.name.contains('client')) {
|
||||
run.client true
|
||||
} else {
|
||||
@@ -438,7 +446,7 @@ def sharedFmlonlyForge = { Project prj ->
|
||||
// SecureJarHandler bootstrap values.
|
||||
run.property 'ignoreList', prj.configurations.moduleonly.files.collect {it.name.replaceAll(/([-_]([.\d]*\d+)|\.jar$)/, '') }.join(',') + ",client-extra,fmlcore,javafmllanguage,lowcodelanguage,mclanguage,${prj.name}-"
|
||||
// FIXME: Without this jna doesn't work at runtime. Someone figure out why please?
|
||||
run.property 'mergeModules', 'jna-5.10.0.jar,jna-platform-5.10.0.jar,java-objc-bridge-1.0.0.jar'
|
||||
run.property 'mergeModules', 'jna-5.10.0.jar,jna-platform-5.10.0.jar'
|
||||
if (userdevRuns.contains(run)) {
|
||||
run.property 'legacyClassPath.file', '{minecraft_classpath_file}'
|
||||
run.jvmArgs '-p', '{modules}'
|
||||
@@ -449,6 +457,7 @@ def sharedFmlonlyForge = { Project prj ->
|
||||
run.jvmArgs '--add-modules', 'ALL-MODULE-PATH'
|
||||
// Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript
|
||||
run.jvmArgs '--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler'
|
||||
run.jvmArgs '--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler'
|
||||
run.jvmArgs '--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler'
|
||||
run.jvmArgs '--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming'
|
||||
}
|
||||
@@ -457,7 +466,8 @@ def sharedFmlonlyForge = { Project prj ->
|
||||
run.workingDirectory prj.file('run')
|
||||
|
||||
if (run.name.contains('client') || run.name.contains('data')) {
|
||||
run.property 'nativesDirectory', prj.extractNatives.output.get().asFile
|
||||
// Natives are loaded from the classpath now in all cases
|
||||
// run.property 'nativesDirectory', prj.extractNatives.output.get().asFile
|
||||
run.args '--assetsDir', prj.downloadAssets.output
|
||||
run.args '--assetIndex', "{asset_index}"
|
||||
}
|
||||
@@ -639,6 +649,7 @@ project(':fmlonly') {
|
||||
'--add-modules', 'ALL-MODULE-PATH',
|
||||
// Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript
|
||||
'--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler',
|
||||
'--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler',
|
||||
'--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler',
|
||||
'--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming'
|
||||
]
|
||||
@@ -1059,6 +1070,7 @@ project(':forge') {
|
||||
'--mod', 'custom_transformtype_test',
|
||||
'--mod', 'data_pack_registries_test',
|
||||
'--mod', 'biome_modifiers_test',
|
||||
'--mod', 'structure_modifiers_test',
|
||||
'--output', rootProject.file('src/generated_test/resources/'),
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--existing', sourceSets.test.resources.srcDirs[0]
|
||||
@@ -1172,8 +1184,6 @@ project(':forge') {
|
||||
excs.from patcher.excs
|
||||
}
|
||||
|
||||
task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks]){}
|
||||
|
||||
task checkPatchesAndFix(type: CheckPatches, dependsOn: genPatches) {
|
||||
patchDir = file("$rootDir/patches")
|
||||
autoFix = true
|
||||
@@ -1190,57 +1200,51 @@ project(':forge') {
|
||||
lineEnding = '\n'
|
||||
}
|
||||
|
||||
def baseForgeVersion = System.getProperty("forge.compatibility_check_version")
|
||||
if (baseForgeVersion == null)
|
||||
baseForgeVersion = "${MC_VERSION}-${GIT_INFO.tag}.0"
|
||||
if (baseForgeVersion == "null")
|
||||
baseForgeVersion = null // Allow disabling from system property if not wanted
|
||||
def baseForgeUniversal = null
|
||||
if (baseForgeVersion != null)
|
||||
baseForgeUniversal = project.dependencies.create("net.minecraftforge:forge:${baseForgeVersion}:universal")
|
||||
def baseForgeVersionProperty = project.objects.property(String)
|
||||
baseForgeVersionProperty.set(project.provider { getLatestForgeVersion(MC_VERSION) }.map { MC_VERSION + '-' + it })
|
||||
baseForgeVersionProperty.finalizeValueOnRead()
|
||||
def jarCompatibilityTaskSetup = { task ->
|
||||
task.group = 'jar compatibility'
|
||||
task.onlyIf {
|
||||
baseForgeVersion != null
|
||||
baseForgeVersionProperty.getOrNull() != null
|
||||
}
|
||||
task.inputs.property 'baseForgeVersion', baseForgeVersion
|
||||
}
|
||||
|
||||
task downloadBaseCompatibilityBinPatches(type: DownloadBaseCompatibilityBinPatches) {
|
||||
inputVersion = baseForgeVersion
|
||||
tasks.register('setupCheckJarCompatibility', SetupCheckJarCompatibility) {
|
||||
inputVersion = baseForgeVersionProperty
|
||||
}
|
||||
|
||||
task applyBaseCompatibilityJarBinPatches(type: ApplyBinPatches) {
|
||||
tasks.register('applyBaseCompatibilityJarBinPatches', ApplyBinPatches) {
|
||||
jarCompatibilityTaskSetup(it)
|
||||
|
||||
clean = createJoinedSRG.output
|
||||
patch = downloadBaseCompatibilityBinPatches.output
|
||||
clean = project.tasks.createJoinedSRG.output
|
||||
patch = project.tasks.named('setupCheckJarCompatibility').flatMap { it.baseBinPatchesOutput }
|
||||
output = project.layout.buildDirectory.dir(name).map { it.file('output.jar') }
|
||||
}
|
||||
|
||||
task checkJarCompatibility(type: CheckJarCompatibility) {
|
||||
tasks.register('mergeBaseForgeJar', MergeJars) {
|
||||
jarCompatibilityTaskSetup(it)
|
||||
|
||||
if (baseForgeVersion != null) {
|
||||
def fmlLibs = project.configurations.detachedConfiguration(PACKED_DEPS.collect {
|
||||
def artifactId = it.split(':')[1]
|
||||
return project.dependencies.create("net.minecraftforge:${artifactId}:${baseForgeVersion}")
|
||||
}.toArray(Dependency[]::new))
|
||||
|
||||
baseJar = project.tasks.applyBaseCompatibilityJarBinPatches.output
|
||||
baseLibraries.from(baseForgeUniversal)
|
||||
baseLibraries.from(project.tasks.createJoinedSRG.output)
|
||||
baseLibraries.from(fmlLibs)
|
||||
|
||||
inputJar = project.tasks.reobfJar.output
|
||||
concreteLibraries.from(PACKED_DEPS.collect { rootProject.tasks.getByPath(it).archiveFile })
|
||||
|
||||
commonLibraries.from(project.configurations.minecraftImplementation)
|
||||
commonLibraries.from(project.configurations.installer)
|
||||
commonLibraries.from(project.configurations.moduleonly)
|
||||
}
|
||||
inputJars.from(project.tasks.named('applyBaseCompatibilityJarBinPatches').flatMap { it.output })
|
||||
inputJars.from(baseForgeVersionProperty.map { inputVersion ->
|
||||
def output = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-universal.jar") }.get().asFile
|
||||
project.rootProject.extensions.download.run {
|
||||
src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-universal.jar"
|
||||
dest output
|
||||
}
|
||||
return output
|
||||
})
|
||||
}
|
||||
|
||||
tasks.register('checkJarCompatibility', CheckJarCompatibility) {
|
||||
jarCompatibilityTaskSetup(it)
|
||||
dependsOn 'setupCheckJarCompatibility'
|
||||
|
||||
baseJar = project.tasks.named('mergeBaseForgeJar').flatMap { it.output }
|
||||
}
|
||||
|
||||
task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks, checkPatches, checkLicenses]){}
|
||||
|
||||
task launcherJson(type: LauncherJson) {
|
||||
packedDependencies = [':fmlloader:jar']
|
||||
doFirst {
|
||||
@@ -1260,13 +1264,15 @@ project(':forge') {
|
||||
'--fml.mcVersion', MC_VERSION,
|
||||
'--fml.forgeGroup', project.group,
|
||||
'--fml.mcpVersion', MCP_VERSION],
|
||||
jvm: ["-DignoreList=${forge_client.properties.ignoreList},\${version_name}.jar",
|
||||
jvm: ['-Djava.net.preferIPv6Addresses=system',
|
||||
"-DignoreList=${forge_client.properties.ignoreList},\${version_name}.jar",
|
||||
"-DmergeModules=${forge_client.properties.mergeModules}",
|
||||
'-DlibraryDirectory=${library_directory}',
|
||||
'-p', Util.getArtifacts(project, configurations.moduleonly, false).values().collect{'${library_directory}/' + it.downloads.artifact.path}.join('${classpath_separator}'),
|
||||
'--add-modules', 'ALL-MODULE-PATH',
|
||||
// Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript
|
||||
'--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler',
|
||||
'--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler',
|
||||
'--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler',
|
||||
'--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming'
|
||||
]
|
||||
@@ -1550,7 +1556,7 @@ project(':forge') {
|
||||
MAPPING_CHANNEL: MAPPING_CHANNEL,
|
||||
MAPPING_VERSION: MAPPING_VERSION,
|
||||
FORGE_SPEC_VERSION: SPEC_VERSION.split("\\.")[0],
|
||||
MC_NEXT_VERSION: "1."+((MC_VERSION.split("[\\.-]")[1] as int)+1)
|
||||
MC_NEXT_VERSION: MC_NEXT_VERSION
|
||||
])
|
||||
rename 'gitignore\\.txt', '.gitignore'
|
||||
rename 'gitattributes\\.txt', '.gitattributes'
|
||||
|
||||
@@ -7,4 +7,5 @@ dependencies {
|
||||
implementation 'org.ow2.asm:asm:9.3'
|
||||
implementation 'org.ow2.asm:asm-tree:9.3'
|
||||
implementation 'net.minecraftforge:srgutils:0.4.+'
|
||||
implementation 'commons-io:commons-io:2.8.0'
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.nio.file.Files
|
||||
|
||||
abstract class DownloadBaseCompatibilityBinPatches extends DefaultTask {
|
||||
DownloadBaseCompatibilityBinPatches() {
|
||||
group = 'jar compatibility'
|
||||
onlyIf {
|
||||
inputVersion.getOrNull() != null
|
||||
}
|
||||
|
||||
output.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def dep = project.dependencies.create("net.minecraftforge:forge:${inputVersion.get()}:userdev")
|
||||
def baseForgeUserdev = project.configurations.detachedConfiguration(dep).resolve().iterator().next()
|
||||
|
||||
def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile
|
||||
|
||||
Files.copy(joinedLzma.toPath(), output.get().asFile.toPath())
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
abstract Property<String> getInputVersion()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getOutput()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
abstract class MergeJars extends DefaultTask {
|
||||
MergeJars() {
|
||||
output.convention(project.layout.buildDirectory.dir(name).map { it.file('output.jar') })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def jars = inputJars.files
|
||||
|
||||
try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.get().asFile))) {
|
||||
for (def jar : jars) {
|
||||
try (ZipInputStream zin = new ZipInputStream(new FileInputStream(jar))) {
|
||||
def entry
|
||||
while ((entry = zin.getNextEntry()) != null) {
|
||||
ZipEntry _new = new ZipEntry(entry.getName())
|
||||
_new.setTime(0) //SHOULD be the same time as the main entry, but NOOOO _new.setTime(entry.getTime()) throws DateTimeException, so you get 0, screw you!
|
||||
zout.putNextEntry(_new)
|
||||
IOUtils.copy(zin, zout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
abstract ConfigurableFileCollection getInputJars()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getOutput()
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package net.minecraftforge.forge.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
abstract class SetupCheckJarCompatibility extends DefaultTask {
|
||||
SetupCheckJarCompatibility() {
|
||||
group = 'jar compatibility'
|
||||
onlyIf {
|
||||
inputVersion.getOrNull() != null
|
||||
}
|
||||
|
||||
baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void run() {
|
||||
def inputVersion = inputVersion.get()
|
||||
def fmlLibs = project.configurations.detachedConfiguration(project.PACKED_DEPS.collect {
|
||||
def artifactId = it.split(':')[1]
|
||||
return project.dependencies.create("net.minecraftforge:${artifactId}:${inputVersion}")
|
||||
}.toArray(Dependency[]::new))
|
||||
|
||||
project.tasks.named('checkJarCompatibility') {
|
||||
baseLibraries.from(project.tasks.createJoinedSRG.output)
|
||||
baseLibraries.from(project.provider {
|
||||
fmlLibs.resolvedConfiguration.lenientConfiguration.files
|
||||
})
|
||||
|
||||
inputJar = project.tasks.reobfJar.output
|
||||
concreteLibraries.from(project.PACKED_DEPS.collect { project.rootProject.tasks.getByPath(it).archiveFile })
|
||||
|
||||
commonLibraries.from(project.configurations.minecraftImplementation)
|
||||
commonLibraries.from(project.configurations.installer)
|
||||
commonLibraries.from(project.configurations.moduleonly)
|
||||
}
|
||||
|
||||
def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile
|
||||
project.rootProject.extensions.download.run {
|
||||
src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-userdev.jar"
|
||||
dest baseForgeUserdev
|
||||
}
|
||||
|
||||
def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile
|
||||
|
||||
Files.copy(joinedLzma.toPath(), baseBinPatchesOutput.get().asFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
abstract Property<String> getInputVersion()
|
||||
|
||||
@OutputFile
|
||||
abstract RegularFileProperty getBaseBinPatchesOutput()
|
||||
}
|
||||
@@ -18,17 +18,17 @@ public class Util {
|
||||
return md.digest().collect {String.format "%02x", it}.join()
|
||||
}
|
||||
File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() }
|
||||
|
||||
|
||||
File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) }
|
||||
File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] }
|
||||
File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() }
|
||||
|
||||
|
||||
Date.metaClass.iso8601 = { ->
|
||||
def format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
def result = format.format(delegate)
|
||||
return result[0..21] + ':' + result[22..-1]
|
||||
}
|
||||
|
||||
|
||||
String.metaClass.rsplit = { String del, int limit = -1 ->
|
||||
def lst = new ArrayList()
|
||||
def x = 0, idx
|
||||
@@ -41,7 +41,7 @@ public class Util {
|
||||
return lst
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String[] getClasspath(project, libs, artifact) {
|
||||
def ret = []
|
||||
artifactTree(project, artifact).each { key, lib ->
|
||||
@@ -51,7 +51,7 @@ public class Util {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
public static def getArtifacts(project, config, classifiers) {
|
||||
def ret = [:]
|
||||
config.resolvedConfiguration.resolvedArtifacts.each {
|
||||
@@ -75,7 +75,7 @@ public class Util {
|
||||
url = "https://maven.minecraftforge.net/${path}"
|
||||
}
|
||||
//TODO remove when Mojang launcher is updated
|
||||
if (!classifiers && art.classifier != null) {
|
||||
if (!classifiers && art.classifier != null) {
|
||||
//Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
|
||||
// However, keep the path normal so that our mirror system works.
|
||||
art.version = "${art.version}-${art.classifier}"
|
||||
@@ -96,14 +96,14 @@ public class Util {
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
public static def getMavenPath(task) {
|
||||
|
||||
public static def getMavenPath(task) {
|
||||
def classifier = task.archiveClassifier.get()
|
||||
def dep = "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
|
||||
return "${task.project.group.replace('.', '/')}/${task.project.name}/${task.project.version}/${task.project.name}-${task.project.version}".toString() + (classifier == '' ? '' : '-' + classifier) + '.jar'
|
||||
}
|
||||
|
||||
public static def getMavenDep(task) {
|
||||
|
||||
public static def getMavenDep(task) {
|
||||
def classifier = task.archiveClassifier.get()
|
||||
return "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
|
||||
}
|
||||
@@ -127,7 +127,7 @@ public class Util {
|
||||
def files = cfg.resolve()
|
||||
return getArtifacts(project, cfg, true)
|
||||
}
|
||||
|
||||
|
||||
private static boolean checkExists(url) {
|
||||
try {
|
||||
def code = new URL(url).openConnection().with {
|
||||
@@ -142,4 +142,9 @@ public class Util {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLatestForgeVersion(mcVersion) {
|
||||
def json = new JsonSlurper().parseText(new URL("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json").getText("UTF-8"))
|
||||
return json.promos["$mcVersion-latest"]
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
MinecraftForge
|
||||
=============
|
||||
[](https://files.minecraftforge.net)
|
||||
[](https://files.minecraftforge.net)
|
||||
[](https://files.minecraftforge.net) [](https://discord.gg/UvedJ9m) [](https://www.patreon.com/LexManos)
|
||||
|
||||
Forge is a free, open-source modding API all of your favourite mods use!
|
||||
|
||||
@@ -93,5 +93,7 @@ public interface IExtensionPoint<T extends Record>
|
||||
* @see net.minecraftforge.client.ForgeHooksClient#processForgeListPingData(net.minecraft.network.protocol.status.ServerStatus, net.minecraft.client.multiplayer.ServerData)
|
||||
*/
|
||||
@SuppressWarnings("JavadocReference") // reference to NetworkConstants, ForgeHooksClient
|
||||
record DisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) implements IExtensionPoint<DisplayTest> {}
|
||||
record DisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) implements IExtensionPoint<DisplayTest> {
|
||||
public static final String IGNORESERVERONLY = "OHNOES\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31";
|
||||
}
|
||||
}
|
||||
@@ -56,9 +56,24 @@ public abstract class ModContainer
|
||||
this.namespace = this.modId;
|
||||
this.modInfo = info;
|
||||
this.modLoadingStage = ModLoadingStage.CONSTRUCT;
|
||||
// default displaytest extension checks for version string match
|
||||
registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(()->this.modInfo.getVersion().toString(),
|
||||
(incoming, isNetwork)->Objects.equals(incoming, this.modInfo.getVersion().toString())));
|
||||
|
||||
final String displayTestString = info.getConfig().<String>getConfigElement("displayTest").orElse("MATCH_VERSION"); // missing defaults to DEFAULT type
|
||||
Supplier<IExtensionPoint.DisplayTest> displayTestSupplier = switch (displayTestString) {
|
||||
case "MATCH_VERSION" -> // default displaytest checks for version string match
|
||||
() -> new IExtensionPoint.DisplayTest(() -> this.modInfo.getVersion().toString(),
|
||||
(incoming, isNetwork) -> Objects.equals(incoming, this.modInfo.getVersion().toString()));
|
||||
case "IGNORE_SERVER_VERSION" -> // Ignores any version information coming from the server - use for server only mods
|
||||
() -> new IExtensionPoint.DisplayTest(() -> IExtensionPoint.DisplayTest.IGNORESERVERONLY, (incoming, isNetwork) -> true);
|
||||
case "IGNORE_ALL_VERSION" -> // Ignores all information and provides no information
|
||||
() -> new IExtensionPoint.DisplayTest(() -> "", (incoming, isNetwork) -> true);
|
||||
case "NONE" -> null; // NO display test at all - use this if you're going to do your own display test
|
||||
default -> // any other value throws an exception
|
||||
throw new IllegalArgumentException("Invalid displayTest value supplied in mods.toml");
|
||||
};
|
||||
if (displayTestSupplier != null)
|
||||
registerExtensionPoint(IExtensionPoint.DisplayTest.class, displayTestSupplier);
|
||||
else
|
||||
extensionPoints.remove(IExtensionPoint.DisplayTest.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -53,6 +54,7 @@ public class ModList
|
||||
private List<ModContainer> mods;
|
||||
private Map<String, ModContainer> indexedMods;
|
||||
private List<ModFileScanData> modFileScanData;
|
||||
private List<ModContainer> sortedContainers;
|
||||
|
||||
private ModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
|
||||
{
|
||||
@@ -155,6 +157,7 @@ public class ModList
|
||||
void setLoadedMods(final List<ModContainer> modContainers)
|
||||
{
|
||||
this.mods = modContainers;
|
||||
this.sortedContainers = modContainers.stream().sorted(Comparator.comparingInt(c->sortedList.indexOf(c.getModInfo()))).toList();
|
||||
this.indexedMods = modContainers.stream().collect(Collectors.toMap(ModContainer::getModId, Function.identity()));
|
||||
}
|
||||
|
||||
@@ -218,6 +221,10 @@ public class ModList
|
||||
indexedMods.forEach(modContainerConsumer);
|
||||
}
|
||||
|
||||
public void forEachModInOrder(Consumer<ModContainer> containerConsumer) {
|
||||
this.sortedContainers.forEach(containerConsumer);
|
||||
}
|
||||
|
||||
public <T> Stream<T> applyForEachModContainer(Function<ModContainer, T> function) {
|
||||
return indexedMods.values().stream().map(function);
|
||||
}
|
||||
|
||||
@@ -8,26 +8,25 @@ 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;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.InvalidModIdentifier;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
import net.minecraftforge.forgespi.locating.ForgeFeature;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -96,7 +95,7 @@ public class ModLoader
|
||||
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
|
||||
.collect(Collectors.toList());
|
||||
FMLLoader.getLoadingModList().getModFiles().stream()
|
||||
.filter(ModFileInfo::missingLicense) //Search for files with missing licenses
|
||||
.filter(ModFileInfo::missingLicense)
|
||||
.filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(thisModInfo -> this.loadingExceptions.stream().map(ModLoadingException::getModInfo).anyMatch(otherInfo -> otherInfo == thisModInfo))) //Ignore files where any other mod already encountered an error
|
||||
.map(modFileInfo -> new ModLoadingException(null, ModLoadingStage.VALIDATE, "fml.modloading.missinglicense", null, modFileInfo.getFile()))
|
||||
.forEach(this.loadingExceptions::add);
|
||||
@@ -133,6 +132,7 @@ public class ModLoader
|
||||
* @param periodicTask Optional periodic task to perform on the main thread while other activities run
|
||||
*/
|
||||
public void gatherAndInitializeMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
|
||||
ForgeFeature.registerFeature("java_version", ForgeFeature.VersionFeatureTest.forVersionString(IModInfo.DependencySide.SERVER, System.getProperty("java.version")));
|
||||
loadingStateValid = true;
|
||||
statusConsumer.ifPresent(c->c.accept("Waiting for scan to complete"));
|
||||
FMLLoader.backgroundScanHandler.waitForScanToComplete(periodicTask);
|
||||
@@ -145,6 +145,22 @@ public class ModLoader
|
||||
loadingStateValid = false;
|
||||
throw new LoadingFailedException(loadingExceptions);
|
||||
}
|
||||
statusConsumer.ifPresent(c->c.accept("Validating features"));
|
||||
List<? extends ForgeFeature.Bound> failedBounds = loadingModList.getMods().stream()
|
||||
.map(ModInfo::getForgeFeatures)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(bound -> !ForgeFeature.testFeature(FMLEnvironment.dist, bound))
|
||||
.toList();
|
||||
|
||||
if (!failedBounds.isEmpty()) {
|
||||
LOGGER.fatal(CORE, "Failed to validate feature bounds for mods");
|
||||
modList.setLoadedMods(Collections.emptyList());
|
||||
loadingStateValid = false;
|
||||
throw new LoadingFailedException(failedBounds.stream()
|
||||
.map(fb -> new ModLoadingException(fb.modInfo(), ModLoadingStage.CONSTRUCT, "fml.modloading.feature.missing", null, fb.featureName(), fb.featureBound(), ForgeFeature.featureValue(fb)))
|
||||
.toList());
|
||||
}
|
||||
|
||||
statusConsumer.ifPresent(c->c.accept("Building Mod List"));
|
||||
final List<ModContainer> modContainers = loadingModList.getModFiles().stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
@@ -222,7 +238,7 @@ public class ModLoader
|
||||
}
|
||||
}
|
||||
|
||||
private List<ModContainer> buildMods(final ModFile modFile)
|
||||
private List<ModContainer> buildMods(final IModFile modFile)
|
||||
{
|
||||
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
|
||||
|
||||
@@ -234,17 +250,29 @@ public class ModLoader
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (containers.size() != modInfoMap.size()) {
|
||||
var modIds = modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList());
|
||||
var containerIds = containers.stream().map(c -> c != null ? c.getModId() : "(null)").sorted().collect(Collectors.toList());
|
||||
|
||||
LOGGER.fatal(LOADING,"File {} constructed {} mods: {}, but had {} mods specified: {}",
|
||||
modFile.getFilePath(),
|
||||
containers.size(), containers.stream().map(c -> c != null ? c.getModId() : "(null)").sorted().collect(Collectors.toList()),
|
||||
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList()));
|
||||
containers.size(), containerIds,
|
||||
modInfoMap.size(), modIds);
|
||||
|
||||
var missingClasses = new ArrayList<>(modIds);
|
||||
missingClasses.removeAll(containerIds);
|
||||
LOGGER.fatal(LOADING, "The following classes are missing, but are reported in the mods.toml: {}", missingClasses);
|
||||
|
||||
var missingMods = new ArrayList<>(containerIds);
|
||||
missingMods.removeAll(modIds);
|
||||
LOGGER.fatal(LOADING, "The following mods are missing, but have classes in the jar: {}", missingMods);
|
||||
|
||||
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
|
||||
}
|
||||
// remove errored mod containers
|
||||
return containers.stream().filter(mc -> mc.modLoadingStage != ModLoadingStage.ERROR).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ModContainer buildModContainerFromTOML(final ModFile modFile, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
|
||||
private ModContainer buildModContainerFromTOML(final IModFile modFile, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
|
||||
try {
|
||||
final String modId = idToProviderEntry.getKey();
|
||||
final IModLanguageProvider.IModLanguageLoader languageLoader = idToProviderEntry.getValue();
|
||||
@@ -273,7 +301,7 @@ public class ModLoader
|
||||
LOGGER.error("Cowardly refusing to send event generator to a broken mod state");
|
||||
return;
|
||||
}
|
||||
ModList.get().forEachModContainer((id, mc) -> mc.acceptEvent(generator.apply(mc)));
|
||||
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(generator.apply(mc)));
|
||||
}
|
||||
|
||||
public <T extends Event & IModBusEvent> void postEvent(T e) {
|
||||
@@ -281,7 +309,26 @@ public class ModLoader
|
||||
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
|
||||
return;
|
||||
}
|
||||
ModList.get().forEachModContainer((id, mc) -> mc.acceptEvent(e));
|
||||
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(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;
|
||||
}
|
||||
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(e));
|
||||
return e;
|
||||
}
|
||||
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;
|
||||
}
|
||||
ModList.get().forEachModInOrder(mc -> {
|
||||
pre.accept(mc, e);
|
||||
mc.acceptEvent(e);
|
||||
post.accept(mc, e);
|
||||
});
|
||||
}
|
||||
|
||||
public List<ModLoadingWarning> getWarnings()
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.config.IConfigSpec;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModLoadingContext
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
|
||||
private Object languageExtension;
|
||||
private ModLoadingStage stage;
|
||||
@@ -46,10 +51,24 @@ public class ModLoadingContext
|
||||
}
|
||||
|
||||
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec) {
|
||||
if (spec.isEmpty())
|
||||
{
|
||||
// This handles the case where a mod tries to register a config, without any options configured inside it.
|
||||
LOGGER.debug("Attempted to register an empty config for type {} on mod {}", type, getActiveContainer().getModId());
|
||||
return;
|
||||
}
|
||||
|
||||
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer()));
|
||||
}
|
||||
|
||||
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec, String fileName) {
|
||||
if (spec.isEmpty())
|
||||
{
|
||||
// This handles the case where a mod tries to register a config, without any options configured inside it.
|
||||
LOGGER.debug("Attempted to register an empty config for type {} on mod {} using file name {}", type, getActiveContainer().getModId(), fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer(), fileName));
|
||||
}
|
||||
|
||||
|
||||
@@ -117,14 +117,22 @@ public class VersionChecker
|
||||
/**
|
||||
* Returns the response body as a String for the given URL while following redirects
|
||||
*/
|
||||
private String openUrlString(URL url) throws IOException, URISyntaxException, InterruptedException {
|
||||
private String openUrlString(URL url, IModInfo mod) throws IOException, URISyntaxException, InterruptedException {
|
||||
URL currentUrl = url;
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Java-http-client/").append(System.getProperty("java.version")).append(' ');
|
||||
sb.append("MinecraftForge/").append(FMLLoader.versionInfo().mcAndForgeVersion()).append(' ');
|
||||
sb.append(mod.getModId()).append('/').append(mod.getVersion());
|
||||
final String userAgent = sb.toString();
|
||||
|
||||
for (int redirects = 0; redirects < MAX_HTTP_REDIRECTS; redirects++)
|
||||
{
|
||||
var request = HttpRequest.newBuilder()
|
||||
.uri(currentUrl.toURI())
|
||||
.timeout(Duration.ofSeconds(HTTP_TIMEOUT_SECS))
|
||||
.setHeader("Accept-Encoding", "gzip")
|
||||
.setHeader("User-Agent", userAgent)
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
@@ -166,7 +174,7 @@ public class VersionChecker
|
||||
URL url = mod.getUpdateURL().get();
|
||||
LOGGER.info("[{}] Starting version check at {}", mod.getModId(), url.toString());
|
||||
|
||||
String data = openUrlString(url);
|
||||
String data = openUrlString(url, mod);
|
||||
|
||||
LOGGER.debug("[{}] Received version check data:\n{}", mod.getModId(), data);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ dependencies {
|
||||
api("cpw.mods:modlauncher:${MODLAUNCHER_VERSION}")
|
||||
api("net.minecraftforge:coremods:${COREMODS_VERSION}")
|
||||
api("com.mojang:logging:${MOJANG_LOGGING_VERSION}")
|
||||
api "net.minecraftforge:JarJarSelector:${JARJAR_VERSION}"
|
||||
api "net.minecraftforge:JarJarMetadata:${JARJAR_VERSION}"
|
||||
|
||||
implementation("net.sf.jopt-simple:jopt-simple:${JOPT_SIMPLE_VERSION}")
|
||||
implementation("cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}")
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class ClasspathLocatorUtils {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static Path findJarPathFor(final String resourceName, final String jarName, final URL resource) {
|
||||
try {
|
||||
Path path;
|
||||
final URI uri = resource.toURI();
|
||||
if (uri.getScheme().equals("jar") && uri.getRawSchemeSpecificPart().contains("!/")) {
|
||||
int lastExcl = uri.getRawSchemeSpecificPart().lastIndexOf("!/");
|
||||
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().substring(0, lastExcl)));
|
||||
} else {
|
||||
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-resourceName.length())));
|
||||
}
|
||||
//LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
|
||||
return path;
|
||||
} catch (NullPointerException | URISyntaxException e) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to find JAR for class {} - {}", resourceName, jarName);
|
||||
throw new RuntimeException("Unable to locate "+resourceName+" - "+jarName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.NamedPath;
|
||||
import cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class ClasspathTransformerDiscoverer implements ITransformerDiscoveryService {
|
||||
|
||||
private final List<Path> legacyClasspath = Arrays.stream(System.getProperty("legacyClassPath", "").split(File.pathSeparator)).map(Path::of).toList();
|
||||
|
||||
@Override
|
||||
public List<NamedPath> candidates(Path gameDirectory) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NamedPath> candidates(final Path gameDirectory, final String launchTarget) {
|
||||
if (launchTarget != null && launchTarget.contains("dev")) {
|
||||
this.scan(gameDirectory);
|
||||
}
|
||||
return List.copyOf(found);
|
||||
}
|
||||
|
||||
private final static List<NamedPath> found = new ArrayList<>();
|
||||
|
||||
public static List<Path> allExcluded() {
|
||||
return found.stream().map(np->np.paths()[0]).toList();
|
||||
}
|
||||
|
||||
private void scan(final Path gameDirectory) {
|
||||
try {
|
||||
locateTransformers("META-INF/services/cpw.mods.modlauncher.api.ITransformationService");
|
||||
locateTransformers("META-INF/services/net.minecraftforge.forgespi.locating.IModLocator");
|
||||
} catch (IOException e) {
|
||||
LogManager.getLogger().error("Error during discovery of transform services from the classpath", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void locateTransformers(String resource) throws IOException {
|
||||
final Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources(resource);
|
||||
while (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
Path path = ClasspathLocatorUtils.findJarPathFor(resource, url.toString(), url);
|
||||
if (legacyClasspath.stream().anyMatch(path::equals) || !Files.exists(path) || Files.isDirectory(path))
|
||||
continue;
|
||||
found.add(new NamedPath(path.toUri().toString(), path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ public class EarlyLoadingException extends RuntimeException {
|
||||
return errorMessages;
|
||||
}
|
||||
|
||||
EarlyLoadingException(final String message, final Throwable originalException, List<ExceptionData> errorMessages) {
|
||||
public EarlyLoadingException(final String message, final Throwable originalException, List<ExceptionData> errorMessages) {
|
||||
super(message, originalException);
|
||||
this.errorMessages = errorMessages;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class FMLConfig
|
||||
configSpec.define("maxThreads", -1);
|
||||
configSpec.define("versionCheck", Boolean.TRUE);
|
||||
configSpec.define("defaultConfigPath", "defaultconfigs");
|
||||
configSpec.define("disableOptimizedDFU", Boolean.TRUE);
|
||||
}
|
||||
|
||||
private CommentedFileConfig configData;
|
||||
@@ -88,4 +89,8 @@ public class FMLConfig
|
||||
public static String defaultConfigPath() {
|
||||
return INSTANCE.configData.<String>getOptional("defaultConfigPath").orElse("defaultconfigs");
|
||||
}
|
||||
|
||||
public static boolean isOptimizedDFUDisabled() {
|
||||
return INSTANCE.configData.<Boolean>getOptional("disableOptimizedDFU").orElse(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ package net.minecraftforge.fml.loading;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
@@ -53,4 +54,16 @@ public class FileUtils
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean matchFileName(String path, String... matches) {
|
||||
// Extract file name from path
|
||||
String name = path.substring(Math.min(path.lastIndexOf(File.separatorChar) + 1, path.length()));
|
||||
// Check if it contains any of the desired keywords
|
||||
for (String match : matches) {
|
||||
if (name.contains(match)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class LanguageLoadingProvider
|
||||
}
|
||||
|
||||
public IModLanguageProvider findLanguage(ModFile mf, String modLoader, VersionRange modLoaderVersion) {
|
||||
final String languageFileName = mf.getLocator() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName();
|
||||
final String languageFileName = mf.getProvider() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName();
|
||||
final ModLanguageWrapper mlw = languageProviderMap.get(modLoader);
|
||||
if (mlw == null) {
|
||||
LOGGER.error(LOADING,"Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
|
||||
|
||||
@@ -10,11 +10,18 @@ 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 java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -28,7 +35,7 @@ public class LoadingModList
|
||||
private final List<ModInfo> sortedList;
|
||||
private final Map<String, ModFileInfo> fileById;
|
||||
private final List<EarlyLoadingException> preLoadErrors;
|
||||
private List<ModFile> brokenFiles;
|
||||
private List<IModFile> brokenFiles;
|
||||
|
||||
private LoadingModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
|
||||
{
|
||||
@@ -154,11 +161,11 @@ public class LoadingModList
|
||||
return preLoadErrors;
|
||||
}
|
||||
|
||||
public void setBrokenFiles(final List<ModFile> brokenFiles) {
|
||||
public void setBrokenFiles(final List<IModFile> brokenFiles) {
|
||||
this.brokenFiles = brokenFiles;
|
||||
}
|
||||
|
||||
public List<ModFile> getBrokenFiles() {
|
||||
public List<IModFile> getBrokenFiles() {
|
||||
return this.brokenFiles;
|
||||
}
|
||||
}
|
||||
+14
-11
@@ -6,21 +6,27 @@
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
|
||||
import cpw.mods.modlauncher.api.NamedPath;
|
||||
import cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.Set;
|
||||
|
||||
public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Set<String> SERVICES = Set.of(
|
||||
"cpw.mods.modlauncher.api.ITransformationService",
|
||||
"net.minecraftforge.forgespi.locating.IModLocator",
|
||||
"net.minecraftforge.forgespi.locating.IDependencyLocator"
|
||||
);
|
||||
|
||||
@Override
|
||||
public List<NamedPath> candidates(final Path gameDirectory) {
|
||||
@@ -51,14 +57,11 @@ public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService
|
||||
if (!Files.isRegularFile(path)) return;
|
||||
if (!path.toString().endsWith(".jar")) return;
|
||||
if (LamdbaExceptionUtils.uncheck(() -> Files.size(path)) == 0) return;
|
||||
try (ZipFile zf = new ZipFile(new File(path.toUri()))) {
|
||||
if (zf.getEntry("META-INF/services/cpw.mods.modlauncher.api.ITransformationService") != null) {
|
||||
found.add(new NamedPath(zf.getName(), path));
|
||||
} else if (zf.getEntry("META-INF/services/net.minecraftforge.forgespi.locating.IModLocator") != null) {
|
||||
found.add(new NamedPath(zf.getName(), path));
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.error("Zip Error when loading jar file {}", path, ioe);
|
||||
}
|
||||
|
||||
SecureJar jar = SecureJar.from(path);
|
||||
jar.moduleDataProvider().descriptor().provides().stream()
|
||||
.map(ModuleDescriptor.Provides::service)
|
||||
.filter(SERVICES::contains)
|
||||
.forEach(s -> found.add(new NamedPath(s, path)));
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.fml.loading.toposort.CyclePresentException;
|
||||
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -36,14 +35,15 @@ import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
public class ModSorter
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final UniqueModListBuilder uniqueModListBuilder;
|
||||
private List<ModFile> modFiles;
|
||||
private List<ModInfo> sortedList;
|
||||
private Map<String, ModInfo> modIdNameLookup;
|
||||
private Map<String, IModInfo> modIdNameLookup;
|
||||
private List<ModFile> systemMods;
|
||||
|
||||
private ModSorter(final List<ModFile> modFiles)
|
||||
{
|
||||
this.modFiles = modFiles;
|
||||
this.uniqueModListBuilder = new UniqueModListBuilder(modFiles);
|
||||
}
|
||||
|
||||
public static LoadingModList sort(List<ModFile> mods, final List<ExceptionData> errors)
|
||||
@@ -78,11 +78,12 @@ public class ModSorter
|
||||
// lambdas are identity based, so sorting them is impossible unless you hold reference to them
|
||||
final MutableGraph<ModFileInfo> graph = GraphBuilder.directed().build();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
Map<IModFileInfo, Integer> infos = modFiles.stream()
|
||||
Map<ModFileInfo, Integer> infos = modFiles.stream()
|
||||
.map(ModFile::getModFileInfo)
|
||||
.filter(ModFileInfo.class::isInstance)
|
||||
.map(ModFileInfo.class::cast)
|
||||
.collect(toMap(Function.identity(), e -> counter.incrementAndGet()));
|
||||
infos.keySet().forEach(i -> graph.addNode((ModFileInfo) i));
|
||||
infos.keySet().forEach(graph::addNode);
|
||||
modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.<IModInfo>mapMulti(Iterable::forEach)
|
||||
@@ -124,10 +125,9 @@ public class ModSorter
|
||||
private void addDependency(MutableGraph<ModFileInfo> topoGraph, IModInfo.ModVersion dep)
|
||||
{
|
||||
final ModFileInfo self = (ModFileInfo)dep.getOwner().getOwningFile();
|
||||
final ModInfo targetModInfo = modIdNameLookup.get(dep.getModId());
|
||||
final IModInfo targetModInfo = modIdNameLookup.get(dep.getModId());
|
||||
// soft dep that doesn't exist. Just return. No edge required.
|
||||
if (targetModInfo == null) return;
|
||||
final ModFileInfo target = targetModInfo.getOwningFile();
|
||||
if (targetModInfo == null || !(targetModInfo.getOwningFile() instanceof final ModFileInfo target)) return;
|
||||
if (self == target)
|
||||
return; // in case a jar has two mods that have dependencies between
|
||||
switch (dep.getOrdering()) {
|
||||
@@ -138,19 +138,32 @@ public class ModSorter
|
||||
|
||||
private void buildUniqueList()
|
||||
{
|
||||
// Collect mod files by module name. This will be used for deduping purposes
|
||||
final Map<String, List<IModFile>> modFilesByFirstId = modFiles.stream()
|
||||
.collect(groupingBy(mf -> mf.getModFileInfo().moduleName()));
|
||||
final UniqueModListBuilder.UniqueModListData uniqueModListData = uniqueModListBuilder.buildUniqueList();
|
||||
|
||||
this.modFiles = uniqueModListData.modFiles();
|
||||
|
||||
detectSystemMods(uniqueModListData.modFilesByFirstId());
|
||||
|
||||
modIdNameLookup = uniqueModListData.modFilesByFirstId().entrySet().stream()
|
||||
.filter(e -> !e.getValue().get(0).getModInfos().isEmpty())
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
e -> e.getValue().get(0).getModInfos().get(0)
|
||||
));
|
||||
}
|
||||
|
||||
private void detectSystemMods(final Map<String, List<ModFile>> modFilesByFirstId)
|
||||
{
|
||||
// Capture system mods (ex. MC, Forge) here, so we can keep them for later
|
||||
final Set<String> systemMods = new HashSet<>();
|
||||
// The minecraft mod is always a system mod
|
||||
systemMods.add("minecraft");
|
||||
// Find mod file from MinecraftLocator to define the system mods
|
||||
modFiles.stream()
|
||||
.filter(modFile -> modFile.getLocator().getClass() == MinecraftLocator.class)
|
||||
.filter(modFile -> modFile.getProvider().getClass() == MinecraftLocator.class)
|
||||
.map(ModFile::getSecureJar)
|
||||
.map(SecureJar::getManifest)
|
||||
.map(SecureJar::moduleDataProvider)
|
||||
.map(SecureJar.ModuleDataProvider::getManifest)
|
||||
.map(Manifest::getMainAttributes)
|
||||
.map(mf -> mf.getValue("FML-System-Mods"))
|
||||
.filter(Objects::nonNull)
|
||||
@@ -168,47 +181,6 @@ public class ModSorter
|
||||
throw new IllegalStateException("Failed to find system mod: " + systemMod);
|
||||
}
|
||||
}
|
||||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
this.modFiles = modFilesByFirstId.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.map(Map.Entry::getValue)
|
||||
.map(ModFile.class::cast)
|
||||
.collect(toList());
|
||||
|
||||
// Transform to the full mod id list
|
||||
final Map<String, List<ModInfo>> modIds = modFiles.stream()
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.map(ModInfo.class::cast)
|
||||
.collect(groupingBy(IModInfo::getModId));
|
||||
|
||||
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
|
||||
// We can't handle this
|
||||
final List<ModInfo> dupedMods = modIds.values().stream()
|
||||
.filter(modInfos -> modInfos.size() > 1)
|
||||
.map(modInfos -> modInfos.get(0))
|
||||
.toList();
|
||||
|
||||
if (!dupedMods.isEmpty()) {
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
|
||||
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod",
|
||||
dm, Objects.toString(dm))).toList();
|
||||
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
|
||||
}
|
||||
|
||||
modIdNameLookup = modIds.entrySet().stream()
|
||||
.collect(toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
|
||||
}
|
||||
|
||||
private Map.Entry<String, IModFile> selectNewestModInfo(Map.Entry<String, List<IModFile>> fullList) {
|
||||
List<IModFile> modInfoList = fullList.getValue();
|
||||
if (modInfoList.size() > 1) {
|
||||
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
|
||||
modInfoList.sort(Comparator.<IModFile, ArtifactVersion>comparing(mf -> mf.getModInfos().get(0).getVersion()).reversed());
|
||||
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), modInfoList.get(0).getModInfos().get(0).getVersion());
|
||||
}
|
||||
return Map.entry(fullList.getKey(), modInfoList.get(0));
|
||||
}
|
||||
|
||||
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
|
||||
@@ -238,10 +210,24 @@ public class ModSorter
|
||||
|
||||
if (!missingVersions.isEmpty()) {
|
||||
if (mandatoryMissing > 0) {
|
||||
LOGGER.error(LOADING, "Missing mandatory dependencies: {}", missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
|
||||
LOGGER.error(
|
||||
LOADING,
|
||||
"Missing or unsupported mandatory dependencies:\n{}",
|
||||
missingVersions.stream()
|
||||
.filter(IModInfo.ModVersion::isMandatory)
|
||||
.map(ver -> formatDependencyError(ver, modVersions))
|
||||
.collect(Collectors.joining("\n"))
|
||||
);
|
||||
}
|
||||
if (missingVersions.size() - mandatoryMissing > 0) {
|
||||
LOGGER.error(LOADING, "Unsupported installed optional dependencies: {}", missingVersions.stream().filter(ver -> !ver.isMandatory()).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
|
||||
LOGGER.error(
|
||||
LOADING,
|
||||
"Unsupported installed optional dependencies:\n{}",
|
||||
missingVersions.stream()
|
||||
.filter(ver -> !ver.isMandatory())
|
||||
.map(ver -> formatDependencyError(ver, modVersions))
|
||||
.collect(Collectors.joining("\n"))
|
||||
);
|
||||
}
|
||||
|
||||
return missingVersions.stream()
|
||||
@@ -253,6 +239,18 @@ public class ModSorter
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static String formatDependencyError(IModInfo.ModVersion dependency, Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
ArtifactVersion installed = modVersions.get(dependency.getModId());
|
||||
return String.format(
|
||||
"\tMod ID: '%s', Requested by: '%s', Expected range: '%s', Actual version: '%s'",
|
||||
dependency.getModId(),
|
||||
dependency.getOwner().getModId(),
|
||||
dependency.getVersionRange(),
|
||||
installed != null ? installed.toString() : "[MISSING]"
|
||||
);
|
||||
}
|
||||
|
||||
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
|
||||
{
|
||||
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
|
||||
public class UniqueModListBuilder
|
||||
{
|
||||
private final static Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private final List<ModFile> modFiles;
|
||||
|
||||
public UniqueModListBuilder(final List<ModFile> modFiles) {this.modFiles = modFiles;}
|
||||
|
||||
public UniqueModListData buildUniqueList()
|
||||
{
|
||||
List<ModFile> uniqueModList;
|
||||
List<ModFile> uniqueLibListWithVersion;
|
||||
|
||||
// Collect mod files by module name. This will be used for deduping purposes
|
||||
final Map<String, List<ModFile>> modFilesByFirstId = modFiles.stream()
|
||||
.filter(mf -> mf.getModFileInfo() != null)
|
||||
.collect(groupingBy(UniqueModListBuilder::getModId));
|
||||
|
||||
final Map<String, List<ModFile>> libFilesWithVersionByModuleName = modFiles.stream()
|
||||
.filter(mf -> mf.getModFileInfo() == null)
|
||||
.collect(groupingBy(UniqueModListBuilder::getModId));
|
||||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
uniqueModList = modFilesByFirstId.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.toList();
|
||||
|
||||
// Select the newest by artifact version sorting of non-unique files thus identified
|
||||
uniqueLibListWithVersion = libFilesWithVersionByModuleName.entrySet().stream()
|
||||
.map(this::selectNewestModInfo)
|
||||
.toList();
|
||||
|
||||
// Transform to the full mod id list
|
||||
final Map<String, List<IModInfo>> modIds = uniqueModList.stream()
|
||||
.filter(mf -> mf.getModFileInfo() != null) //Filter out non-mod files, we don't care about those for now.....
|
||||
.map(ModFile::getModInfos)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(groupingBy(IModInfo::getModId));
|
||||
|
||||
// Transform to the full lib id list
|
||||
final Map<String, List<ModFile>> versionedLibIds = uniqueLibListWithVersion.stream()
|
||||
.map(UniqueModListBuilder::getModId)
|
||||
.collect(Collectors.toMap(
|
||||
Function.identity(),
|
||||
libFilesWithVersionByModuleName::get
|
||||
));
|
||||
|
||||
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
|
||||
// We can't handle this
|
||||
final List<IModInfo> dupedMods = modIds.values().stream()
|
||||
.filter(modInfos -> modInfos.size() > 1)
|
||||
.map(modInfos -> modInfos.get(0))
|
||||
.toList();
|
||||
|
||||
if (!dupedMods.isEmpty()) {
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
|
||||
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm, Objects.toString(dm)))
|
||||
.toList();
|
||||
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
|
||||
}
|
||||
|
||||
final List<ModFile> dupedLibs = versionedLibIds.values().stream()
|
||||
.filter(modFiles -> modFiles.size() > 1)
|
||||
.map(modFiles -> modFiles.get(0))
|
||||
.toList();
|
||||
|
||||
if (!dupedLibs.isEmpty()) {
|
||||
final List<EarlyLoadingException.ExceptionData> duplicateLibErrors = dupedLibs.stream()
|
||||
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedlib.versioned", dm, Objects.toString(dm)))
|
||||
.toList();
|
||||
throw new EarlyLoadingException("Duplicate plugins or libraries found", null, duplicateLibErrors);
|
||||
}
|
||||
|
||||
// Collect unique mod files by module name. This will be used for deduping purposes
|
||||
final Map<String, List<ModFile>> uniqueModFilesByFirstId = uniqueModList.stream()
|
||||
.collect(groupingBy(UniqueModListBuilder::getModId));
|
||||
|
||||
final List<ModFile> loadedList = new ArrayList<>();
|
||||
loadedList.addAll(uniqueModList);
|
||||
loadedList.addAll(uniqueLibListWithVersion);
|
||||
|
||||
return new UniqueModListData(loadedList, uniqueModFilesByFirstId);
|
||||
}
|
||||
|
||||
private ModFile selectNewestModInfo(Map.Entry<String, List<ModFile>> fullList) {
|
||||
List<ModFile> modInfoList = fullList.getValue();
|
||||
if (modInfoList.size() > 1) {
|
||||
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
|
||||
modInfoList.sort(Comparator.comparing(this::getVersion).reversed());
|
||||
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), this.getVersion(modInfoList.get(0)));
|
||||
}
|
||||
return modInfoList.get(0);
|
||||
}
|
||||
|
||||
private ArtifactVersion getVersion(final ModFile mf)
|
||||
{
|
||||
if (mf.getModFileInfo() == null || mf.getModInfos() == null || mf.getModInfos().isEmpty()) {
|
||||
return mf.getJarVersion();
|
||||
}
|
||||
|
||||
return mf.getModInfos().get(0).getVersion();
|
||||
}
|
||||
|
||||
private static String getModId(ModFile modFile) {
|
||||
if (modFile.getModFileInfo() == null || modFile.getModFileInfo().getMods().isEmpty()) {
|
||||
return modFile.getSecureJar().name();
|
||||
}
|
||||
|
||||
return modFile.getModFileInfo().moduleName();
|
||||
}
|
||||
|
||||
public record UniqueModListData(List<ModFile> modFiles, Map<String, List<ModFile>> modFilesByFirstId) {}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
@@ -18,16 +19,12 @@ public class VersionSupportMatrix {
|
||||
private static final HashMap<String, List<ArtifactVersion>> overrideVersions = new HashMap<>();
|
||||
static {
|
||||
final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.versionInfo().mcVersion());
|
||||
// if (MavenVersionAdapter.createFromVersionSpec("[1.16.4,1.16.5]").containsVersion(version)) {
|
||||
// // 1.16.4 is Compatible with 1.16.3
|
||||
// add("languageloader.javafml", "34");
|
||||
// add("mod.minecraft", "1.16.3");
|
||||
// add("mod.forge", "34.1.42");
|
||||
// // 1.16.5 is Compatible with 1.16.4, and thus 1.16.3
|
||||
// add("languageloader.javafml", "35");
|
||||
// add("mod.minecraft", "1.16.4");
|
||||
// add("mod.forge", "35.1.37");
|
||||
// }
|
||||
if (MavenVersionAdapter.createFromVersionSpec("[1.19.2]").containsVersion(version)) {
|
||||
// 1.19.2 is Compatible with 1.19.1
|
||||
add("languageloader.javafml", "42");
|
||||
add("mod.minecraft", "1.19.1");
|
||||
add("mod.forge", "42.0.9");
|
||||
}
|
||||
}
|
||||
private static void add(String key, String value) {
|
||||
overrideVersions.computeIfAbsent(key, k -> new ArrayList<>()).add(new DefaultArtifactVersion(value));
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.forgespi.locating.IDependencyLocator;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class AbstractJarFileDependencyLocator extends AbstractJarFileModProvider implements IDependencyLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
protected Optional<InputStream> loadResourceFromModFile(final IModFile modFile, final Path path) {
|
||||
try {
|
||||
return Optional.of(Files.newInputStream(modFile.findResource(path.toString())));
|
||||
}
|
||||
catch (final FileNotFoundException e) {
|
||||
LOGGER.debug("Failed to load resource {} from {}, it does not contain dependency information.", path, modFile.getFileName());
|
||||
return Optional.empty();
|
||||
}
|
||||
catch (final Exception e) {
|
||||
LOGGER.error("Failed to load resource {} from mod {}, cause {}", path, modFile.getFileName(), e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
protected Optional<IModFile> loadModFileFrom(final IModFile file, final Path path) {
|
||||
try {
|
||||
final Path pathInModFile = file.findResource(path.toString());
|
||||
return Optional.of(createMod(pathInModFile).file());
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOGGER.error("Failed to load mod file {} from {}", path, file.getFileName());
|
||||
throw new ModFileLoadingException("Failed to load mod file "+file.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
protected String identifyMod(final IModFile modFile) {
|
||||
return modFile.getFileName();
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class AbstractJarFileModLocator extends AbstractJarFileModProvider implements IModLocator
|
||||
{
|
||||
@Override
|
||||
public List<IModLocator.ModFileOrException> scanMods()
|
||||
{
|
||||
return scanCandidates().map(this::createMod).toList();
|
||||
}
|
||||
|
||||
public abstract Stream<Path> scanCandidates();
|
||||
}
|
||||
+9
-21
@@ -7,20 +7,19 @@ package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public abstract class AbstractJarFileLocator extends AbstractModLocator {
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class AbstractJarFileModProvider extends AbstractModProvider
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Override
|
||||
@@ -34,15 +33,4 @@ public abstract class AbstractJarFileLocator extends AbstractModLocator {
|
||||
}
|
||||
LOGGER.debug(LogMarkers.SCAN,"Scan finished: {}", file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IModFile> scanMods() {
|
||||
return scanCandidates()
|
||||
.map(this::createMod)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public abstract Stream<Path> scanCandidates();
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.jarhandling.JarMetadata;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IConfigurable;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public abstract class AbstractModLocator implements IModLocator {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
protected static final String MODS_TOML = "META-INF/mods.toml";
|
||||
protected static final String MANIFEST = "META-INF/MANIFEST.MF";
|
||||
|
||||
protected Optional<IModFile> createMod(Path... path) {
|
||||
var mjm = new ModJarMetadata();
|
||||
var sj = SecureJar.from(
|
||||
Manifest::new,
|
||||
jar -> jar.findFile(MODS_TOML).isPresent() ? mjm : JarMetadata.from(jar, path),
|
||||
(root, p) -> true,
|
||||
path
|
||||
);
|
||||
|
||||
IModFile mod;
|
||||
var type = sj.getManifest().getMainAttributes().getValue(ModFile.TYPE);
|
||||
if (sj.findFile(MODS_TOML).isPresent()) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MODS_TOML, type, path);
|
||||
mod = new ModFile(sj, this, ModFileParser::modsTomlParser);
|
||||
} else if (type != null) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MANIFEST, type, path);
|
||||
mod = new ModFile(sj, this, this::manifestParser);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
mjm.setModFile(mod);
|
||||
return Optional.of(mod);
|
||||
}
|
||||
|
||||
protected IModFileInfo manifestParser(final IModFile mod) {
|
||||
Function<String, Optional<String>> cfg = name -> Optional.ofNullable(mod.getSecureJar().getManifest().getMainAttributes().getValue(name));
|
||||
var license = cfg.apply("LICENSE").orElse("");
|
||||
var dummy = new IConfigurable() {
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(String... key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@Override
|
||||
public List<? extends IConfigurable> getConfigList(String... key) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
return new IModFileInfo() {
|
||||
@Override public List<IModInfo> getMods() { return Collections.emptyList(); }
|
||||
@Override public List<LanguageSpec> requiredLanguageLoaders() { return Collections.emptyList(); }
|
||||
@Override public boolean showAsResourcePack() { return false; }
|
||||
@Override public Map<String, Object> getFileProperties() { return Collections.emptyMap(); }
|
||||
@Override public String getLicense() { return license; }
|
||||
@Override public IModFile getFile() { return mod; }
|
||||
@Override public IConfigurable getConfig() { return dummy; }
|
||||
|
||||
// These Should never be called as it's only called from ModJarMetadata.version and we bypass that
|
||||
@Override public String moduleName() { return mod.getSecureJar().name(); }
|
||||
@Override public String versionString() { return null; }
|
||||
@Override public List<String> usesServices() { return null; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IModFileInfo(" + mod.getFilePath() + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final IModFile modFile) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.jarhandling.JarMetadata;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IConfigurable;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
import net.minecraftforge.forgespi.locating.IModProvider;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public abstract class AbstractModProvider implements IModProvider
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
protected static final String MODS_TOML = "META-INF/mods.toml";
|
||||
protected static final String MANIFEST = "META-INF/MANIFEST.MF";
|
||||
|
||||
protected IModLocator.ModFileOrException createMod(Path... path) {
|
||||
var mjm = new ModJarMetadata();
|
||||
var sj = SecureJar.from(
|
||||
Manifest::new,
|
||||
jar -> jar.moduleDataProvider().findFile(MODS_TOML).isPresent() ? mjm : JarMetadata.from(jar, path),
|
||||
(root, p) -> true,
|
||||
path
|
||||
);
|
||||
|
||||
IModFile mod;
|
||||
var type = sj.moduleDataProvider().getManifest().getMainAttributes().getValue(ModFile.TYPE);
|
||||
if (type == null) {
|
||||
type = getDefaultJarModType();
|
||||
}
|
||||
if (sj.moduleDataProvider().findFile(MODS_TOML).isPresent()) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MODS_TOML, type, path);
|
||||
mod = new ModFile(sj, this, ModFileParser::modsTomlParser);
|
||||
} else if (type != null) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MANIFEST, type, path);
|
||||
mod = new ModFile(sj, this, this::manifestParser, type);
|
||||
} else {
|
||||
return new IModLocator.ModFileOrException(null, new ModFileLoadingException("Invalid mod file found "+ Arrays.toString(path)));
|
||||
}
|
||||
|
||||
mjm.setModFile(mod);
|
||||
return new IModLocator.ModFileOrException(mod, null);
|
||||
}
|
||||
|
||||
protected IModFileInfo manifestParser(final IModFile mod) {
|
||||
Function<String, Optional<String>> cfg = name -> Optional.ofNullable(mod.getSecureJar().moduleDataProvider().getManifest().getMainAttributes().getValue(name));
|
||||
var license = cfg.apply("LICENSE").orElse("");
|
||||
var dummy = new IConfigurable() {
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(String... key) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@Override
|
||||
public List<? extends IConfigurable> getConfigList(String... key) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
return new DefaultModFileInfo(mod, license, dummy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(final IModFile modFile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String getDefaultJarModType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private record DefaultModFileInfo(IModFile mod, String license, IConfigurable configurable) implements IModFileInfo, IConfigurable {
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String... strings)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IConfigurable> getConfigList(final String... strings)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public List<IModInfo> getMods() { return Collections.emptyList(); }
|
||||
@Override public List<LanguageSpec> requiredLanguageLoaders() { return Collections.emptyList(); }
|
||||
@Override public boolean showAsResourcePack() { return false; }
|
||||
@Override public Map<String, Object> getFileProperties() { return Collections.emptyMap(); }
|
||||
@Override
|
||||
public String getLicense() { return license; }
|
||||
|
||||
@Override public IModFile getFile() { return mod; }
|
||||
@Override public IConfigurable getConfig() { return configurable; }
|
||||
|
||||
// These Should never be called as it's only called from ModJarMetadata.version and we bypass that
|
||||
@Override public String moduleName() { return mod.getSecureJar().name(); }
|
||||
@Override public String versionString() { return null; }
|
||||
@Override public List<String> usesServices() { return null; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IModFileInfo(" + mod.getFilePath() + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.fml.loading.ClasspathLocatorUtils;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import org.slf4j.Logger;
|
||||
@@ -24,7 +25,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ClasspathLocator extends AbstractJarFileLocator {
|
||||
public class ClasspathLocator extends AbstractJarFileModLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final List<Path> legacyClasspath = Arrays.stream(System.getProperty("legacyClassPath", "").split(File.pathSeparator)).map(Path::of).toList();
|
||||
private boolean enabled = false;
|
||||
@@ -58,7 +60,7 @@ public class ClasspathLocator extends AbstractJarFileLocator {
|
||||
final Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources(resource);
|
||||
while (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
Path path = findJarPathFor(resource, resource, url);
|
||||
Path path = ClasspathLocatorUtils.findJarPathFor(resource, resource, url);
|
||||
if (claimed.stream().anyMatch(path::equals) || !Files.exists(path) || Files.isDirectory(path))
|
||||
continue;
|
||||
ret.add(path);
|
||||
|
||||
+3
-3
@@ -30,14 +30,14 @@ public class ExplodedDirectoryLocator implements IModLocator {
|
||||
private final Map<ExplodedMod, IModFile> mods = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public List<IModFile> scanMods() {
|
||||
public List<IModLocator.ModFileOrException> scanMods() {
|
||||
explodedMods.forEach(explodedMod ->
|
||||
ModJarMetadata.buildFile(this,
|
||||
jar->jar.findFile("/META-INF/mods.toml").isPresent(),
|
||||
jar->jar.moduleDataProvider().findFile("/META-INF/mods.toml").isPresent(),
|
||||
(a,b) -> true,
|
||||
explodedMod.paths().toArray(Path[]::new))
|
||||
.ifPresentOrElse(f->mods.put(explodedMod, f), () -> LOGGER.warn(LogMarkers.LOADING, "Failed to find exploded resource mods.toml in directory {}", explodedMod.paths().get(0).toString())));
|
||||
return List.copyOf(mods.values());
|
||||
return mods.values().stream().map(mf->new IModLocator.ModFileOrException(mf, null)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-2
@@ -6,16 +6,22 @@
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public class InvalidModFileException extends RuntimeException
|
||||
public class InvalidModFileException extends ModFileLoadingException
|
||||
{
|
||||
private final IModFileInfo modFileInfo;
|
||||
|
||||
public InvalidModFileException(String message, IModFileInfo modFileInfo)
|
||||
{
|
||||
super(String.format(Locale.ENGLISH, "%s (%s)", message, ((ModFileInfo)modFileInfo).getFile().getFileName()));
|
||||
super(String.format(Locale.ROOT, "%s (%s)", message, Optional.ofNullable(modFileInfo).map(mf->mf.getFile().getFileName()).orElse("MISSING FILE NAME")));
|
||||
this.modFileInfo = modFileInfo;
|
||||
}
|
||||
|
||||
public IModFileInfo getBrokenFile() {
|
||||
return modFileInfo;
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraftforge.fml.loading.EarlyLoadingException;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
import net.minecraftforge.jarjar.selection.JarSelector;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class JarInJarDependencyLocator extends AbstractJarFileDependencyLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "JarInJar";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IModFile> scanMods(final Iterable<IModFile> loadedMods)
|
||||
{
|
||||
final List<IModFile> sources = Lists.newArrayList();
|
||||
loadedMods.forEach(sources::add);
|
||||
|
||||
final List<IModFile> dependenciesToLoad = JarSelector.detectAndSelect(sources, this::loadResourceFromModFile, this::loadModFileFrom, this::identifyMod, this::exception);
|
||||
|
||||
if (dependenciesToLoad.isEmpty())
|
||||
{
|
||||
LOGGER.info("No dependencies to load found. Skipping!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
LOGGER.info("Found {} dependencies adding them to mods collection", dependenciesToLoad.size());
|
||||
return dependenciesToLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initArguments(final Map<String, ?> arguments)
|
||||
{
|
||||
// NO-OP, for now
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultJarModType()
|
||||
{
|
||||
return IModFile.Type.GAMELIBRARY.name();
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
protected Optional<IModFile> loadModFileFrom(final IModFile file, final Path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Path pathInModFile = file.findResource(path.toString());
|
||||
final URI filePathUri = new URI("jij:" + (pathInModFile.toAbsolutePath().toUri().getRawSchemeSpecificPart())).normalize();
|
||||
final Map<String, ?> outerFsArgs = ImmutableMap.of("packagePath", pathInModFile);
|
||||
final FileSystem zipFS = FileSystems.newFileSystem(filePathUri, outerFsArgs);
|
||||
final Path pathInFS = zipFS.getPath("/");
|
||||
return Optional.of(createMod(pathInFS).file());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Failed to load mod file {} from {}", path, file.getFileName());
|
||||
final RuntimeException exception = new ModFileLoadingException("Failed to load mod file " + file.getFileName());
|
||||
exception.initCause(e);
|
||||
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
protected EarlyLoadingException exception(Collection<JarSelector.ResolutionFailureInformation<IModFile>> failedDependencies)
|
||||
{
|
||||
|
||||
final List<EarlyLoadingException.ExceptionData> errors = failedDependencies.stream()
|
||||
.filter(entry -> !entry.sources().isEmpty()) //Should never be the case, but just to be sure
|
||||
.map(this::buildExceptionData)
|
||||
.toList();
|
||||
|
||||
return new EarlyLoadingException(failedDependencies.size() + " Dependency restrictions were not met.", null, errors);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private EarlyLoadingException.ExceptionData buildExceptionData(final JarSelector.ResolutionFailureInformation<IModFile> entry)
|
||||
{
|
||||
return new EarlyLoadingException.ExceptionData(
|
||||
getErrorTranslationKey(entry),
|
||||
entry.identifier().group() + ":" + entry.identifier().artifact(),
|
||||
entry.sources()
|
||||
.stream()
|
||||
.flatMap(this::getModWithVersionRangeStream)
|
||||
.map(this::formatError)
|
||||
.collect(Collectors.joining(", "))
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getErrorTranslationKey(final JarSelector.ResolutionFailureInformation<IModFile> entry)
|
||||
{
|
||||
return entry.failureReason() == JarSelector.FailureReason.VERSION_RESOLUTION_FAILED ?
|
||||
"fml.dependencyloading.conflictingdependencies" :
|
||||
"fml.dependencyloading.mismatchedcontaineddependencies";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Stream<ModWithVersionRange> getModWithVersionRangeStream(final JarSelector.SourceWithRequestedVersionRange<IModFile> file)
|
||||
{
|
||||
return file.sources()
|
||||
.stream()
|
||||
.map(IModFile::getModFileInfo)
|
||||
.flatMap(modFileInfo -> modFileInfo.getMods().stream())
|
||||
.map(modInfo -> new ModWithVersionRange(modInfo, file.requestedVersionRange(), file.includedVersion()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String formatError(final ModWithVersionRange modWithVersionRange)
|
||||
{
|
||||
return "\u00a7e" + modWithVersionRange.modInfo().getModId() + "\u00a7r - \u00a74" + modWithVersionRange.versionRange().toString() + "\u00a74 - \u00a72" + modWithVersionRange.artifactVersion().toString() + "\u00a72";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String identifyMod(final IModFile modFile)
|
||||
{
|
||||
if (modFile.getModFileInfo() == null || modFile.getModInfos().isEmpty())
|
||||
{
|
||||
return modFile.getFileName();
|
||||
}
|
||||
|
||||
return modFile.getModInfos().stream().map(IModInfo::getModId).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
private record ModWithVersionRange(IModInfo modInfo, VersionRange versionRange, ArtifactVersion artifactVersion)
|
||||
{}
|
||||
}
|
||||
+2
-1
@@ -15,7 +15,8 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MavenDirectoryLocator extends AbstractJarFileLocator {
|
||||
public class MavenDirectoryLocator extends AbstractJarFileModLocator
|
||||
{
|
||||
private List<Path> modCoords;
|
||||
|
||||
@Override
|
||||
|
||||
+13
-9
@@ -12,21 +12,26 @@ import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
import net.minecraftforge.forgespi.locating.ModFileFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MinecraftLocator extends AbstractModLocator {
|
||||
public class MinecraftLocator extends AbstractModProvider implements IModLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Override
|
||||
public List<IModFile> scanMods() {
|
||||
public List<IModLocator.ModFileOrException> scanMods() {
|
||||
final var launchHandler = FMLLoader.getLaunchHandler();
|
||||
var baseMC = launchHandler.getMinecraftPaths();
|
||||
var mcjar = ModJarMetadata.buildFile(j->ModFileFactory.FACTORY.build(j, this, this::buildMinecraftTOML), j->true, baseMC.minecraftFilter(), baseMC.minecraftPaths().toArray(Path[]::new)).orElseThrow();
|
||||
@@ -35,12 +40,11 @@ public class MinecraftLocator extends AbstractModLocator {
|
||||
.map(sj -> new ModFile(sj, this, ModFileParser::modsTomlParser))
|
||||
.collect(Collectors.<IModFile>toList());
|
||||
var othermods = baseMC.otherModPaths().stream()
|
||||
.map(p -> createMod(p.toArray(Path[]::new)).orElse(null))
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
.map(p -> createMod(p.toArray(Path[]::new)))
|
||||
.filter(Objects::nonNull);
|
||||
artifacts.add(mcjar);
|
||||
artifacts.addAll(othermods);
|
||||
return artifacts;
|
||||
|
||||
return Stream.concat(artifacts.stream().map(f -> new ModFileOrException(f, null)), othermods).toList();
|
||||
}
|
||||
|
||||
private IModFileInfo buildMinecraftTOML(final IModFile iModFile) {
|
||||
|
||||
+132
-27
@@ -5,13 +5,19 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import cpw.mods.modlauncher.api.IModuleLayerManager;
|
||||
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
|
||||
import net.minecraftforge.fml.loading.EarlyLoadingException;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.fml.loading.UniqueModListBuilder;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.forgespi.Environment;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IDependencyLocator;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
import org.slf4j.Logger;
|
||||
@@ -19,52 +25,151 @@ import org.slf4j.Logger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModDiscoverer {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final ServiceLoader<IModLocator> locators;
|
||||
private final List<IModLocator> locatorList;
|
||||
private final ServiceLoader<IModLocator> modLocators;
|
||||
private final ServiceLoader<IDependencyLocator> dependencyLocators;
|
||||
private final List<IModLocator> modLocatorList;
|
||||
private final List<IDependencyLocator> dependencyLocatorList;
|
||||
|
||||
public ModDiscoverer(Map<String, ?> arguments) {
|
||||
Launcher.INSTANCE.environment().computePropertyIfAbsent(Environment.Keys.MODDIRECTORYFACTORY.get(), v->ModsFolderLocator::new);
|
||||
Launcher.INSTANCE.environment().computePropertyIfAbsent(Environment.Keys.PROGRESSMESSAGE.get(), v-> StartupMessageManager.locatorConsumer().orElseGet(()-> s->{}));
|
||||
final var moduleLayerManager = Launcher.INSTANCE.environment().findModuleLayerManager().orElseThrow();
|
||||
locators = ServiceLoader.load(moduleLayerManager.getLayer(IModuleLayerManager.Layer.SERVICE).orElseThrow(), IModLocator.class);
|
||||
locatorList = ServiceLoaderUtils.streamServiceLoader(()->locators, sce->LOGGER.error("Failed to load locator list", sce)).collect(Collectors.toList());
|
||||
locatorList.forEach(l->l.initArguments(arguments));
|
||||
modLocators = ServiceLoader.load(moduleLayerManager.getLayer(IModuleLayerManager.Layer.SERVICE).orElseThrow(), IModLocator.class);
|
||||
dependencyLocators = ServiceLoader.load(moduleLayerManager.getLayer(IModuleLayerManager.Layer.SERVICE).orElseThrow(), IDependencyLocator.class);
|
||||
modLocatorList = ServiceLoaderUtils.streamServiceLoader(()-> modLocators, sce->LOGGER.error("Failed to load mod locator list", sce)).collect(Collectors.toList());
|
||||
modLocatorList.forEach(l->l.initArguments(arguments));
|
||||
dependencyLocatorList = ServiceLoaderUtils.streamServiceLoader(()-> dependencyLocators, sce->LOGGER.error("Failed to load dependency locator list", sce)).collect(Collectors.toList());
|
||||
dependencyLocatorList.forEach(l->l.initArguments(arguments));
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.CORE))
|
||||
{
|
||||
LOGGER.debug(LogMarkers.CORE, "Found Mod Locators : {}", locatorList.stream()
|
||||
.map(iModLocator -> "(" + iModLocator.name() + ":" + iModLocator.getClass().getPackage().getImplementationVersion() + ")").collect(Collectors.joining(",")));
|
||||
LOGGER.debug(LogMarkers.CORE, "Found Mod Locators : {}", modLocatorList.stream()
|
||||
.map(modLocator -> "(%s:%s)".formatted(modLocator.name(),
|
||||
modLocator.getClass().getPackage().getImplementationVersion())).collect(Collectors.joining(",")));
|
||||
}
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.CORE))
|
||||
{
|
||||
LOGGER.debug(LogMarkers.CORE, "Found Dependency Locators : {}", dependencyLocatorList.stream()
|
||||
.map(dependencyLocator -> "(%s:%s)".formatted(dependencyLocator.name(),
|
||||
dependencyLocator.getClass().getPackage().getImplementationVersion())).collect(Collectors.joining(",")));
|
||||
}
|
||||
}
|
||||
|
||||
ModDiscoverer(List<IModLocator> locatorList) {
|
||||
this.locatorList = locatorList;
|
||||
this.locators = null;
|
||||
}
|
||||
|
||||
public ModValidator discoverMods() {
|
||||
LOGGER.debug(LogMarkers.SCAN,"Scanning for mods and other resources to load. We know {} ways to find mods", locatorList.size());
|
||||
var loadedFiles = new ArrayList<>();
|
||||
for (IModLocator locator : locatorList) {
|
||||
LOGGER.debug(LogMarkers.SCAN,"Trying locator {}", locator);
|
||||
var modFiles = locator.scanMods();
|
||||
for (IModFile mf : modFiles) {
|
||||
LOGGER.info(LogMarkers.SCAN, "Found mod file {} of type {} with locator {}", mf.getFileName(), mf.getType(), mf.getLocator());
|
||||
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Found mod file "+mf.getFileName()+" of type "+mf.getType()));
|
||||
}
|
||||
loadedFiles.addAll(modFiles);
|
||||
}
|
||||
final var modFilesMap = loadedFiles.stream()
|
||||
.map(ModFile.class::cast)
|
||||
.collect(Collectors.groupingBy(IModFile::getType));
|
||||
LOGGER.debug(LogMarkers.SCAN,"Scanning for mods and other resources to load. We know {} ways to find mods", modLocatorList.size());
|
||||
List<ModFile> loadedFiles = new ArrayList<>();
|
||||
List<EarlyLoadingException.ExceptionData> discoveryErrorData = new ArrayList<>();
|
||||
boolean successfullyLoadedMods = true;
|
||||
List<IModFileInfo> brokenFiles = new ArrayList<>();
|
||||
|
||||
var validator = new ModValidator(modFilesMap);
|
||||
//Loop all mod locators to get the prime mods to load from.
|
||||
for (IModLocator locator : modLocatorList) {
|
||||
try {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Trying locator {}", locator);
|
||||
var candidates = locator.scanMods();
|
||||
LOGGER.debug(LogMarkers.SCAN, "Locator {} found {} candidates or errors", locator, candidates.size());
|
||||
var exceptions = candidates.stream().map(IModLocator.ModFileOrException::ex).filter(Objects::nonNull).toList();
|
||||
if (!exceptions.isEmpty()) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Locator {} found {} invalid mod files", locator, exceptions.size());
|
||||
brokenFiles.addAll(exceptions.stream().map(e->e instanceof InvalidModFileException ime ? ime.getBrokenFile() : null).filter(Objects::nonNull).toList());
|
||||
}
|
||||
var locatedFiles = candidates.stream().map(IModLocator.ModFileOrException::file).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
var badModFiles = locatedFiles.stream().filter(file -> !(file instanceof ModFile)).toList();
|
||||
if (!badModFiles.isEmpty()) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Locator {} returned {} files which is are not ModFile instances! They will be skipped!", locator, badModFiles.size());
|
||||
brokenFiles.addAll(badModFiles.stream().map(IModFile::getModFileInfo).toList());
|
||||
}
|
||||
locatedFiles.removeAll(badModFiles);
|
||||
LOGGER.debug(LogMarkers.SCAN, "Locator {} found {} valid mod files", locator, locatedFiles.size());
|
||||
handleLocatedFiles(loadedFiles, locatedFiles);
|
||||
} catch (InvalidModFileException imfe) {
|
||||
// We don't generally expect this exception, since it should come from the candidates stream above and be handled in the Locator, but just in case.
|
||||
LOGGER.error(LogMarkers.SCAN, "Locator {} found an invalid mod file {}", locator, imfe.getBrokenFile(), imfe);
|
||||
brokenFiles.add(imfe.getBrokenFile());
|
||||
} catch (EarlyLoadingException exception) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to load mods with locator {}", locator, exception);
|
||||
discoveryErrorData.addAll(exception.getAllData());
|
||||
}
|
||||
}
|
||||
|
||||
//First processing run of the mod list. Any duplicates will cause resolution failure and dependency loading will be skipped.
|
||||
Map<IModFile.Type, List<ModFile>> modFilesMap = Maps.newHashMap();
|
||||
try {
|
||||
final UniqueModListBuilder modsUniqueListBuilder = new UniqueModListBuilder(loadedFiles);
|
||||
final UniqueModListBuilder.UniqueModListData uniqueModsData = modsUniqueListBuilder.buildUniqueList();
|
||||
|
||||
//Grab the temporary results.
|
||||
//This allows loading to continue to a base state, in case dependency loading fails.
|
||||
modFilesMap = uniqueModsData.modFiles().stream()
|
||||
.collect(Collectors.groupingBy(IModFile::getType));
|
||||
loadedFiles = uniqueModsData.modFiles();
|
||||
}
|
||||
catch (EarlyLoadingException exception) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to build unique mod list after mod discovery.", exception);
|
||||
discoveryErrorData.addAll(exception.getAllData());
|
||||
successfullyLoadedMods = false;
|
||||
}
|
||||
|
||||
//We can continue loading if prime mods loaded successfully.
|
||||
if (successfullyLoadedMods) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Successfully Loaded {} mods. Attempting to load dependencies...", loadedFiles.size());
|
||||
for (IDependencyLocator locator : dependencyLocatorList) {
|
||||
try {
|
||||
LOGGER.debug(LogMarkers.SCAN,"Trying locator {}", locator);
|
||||
final List<IModFile> locatedMods = ImmutableList.copyOf(loadedFiles);
|
||||
|
||||
var locatedFiles = locator.scanMods(locatedMods);
|
||||
if (locatedFiles.stream().anyMatch(file -> !(file instanceof ModFile))) {
|
||||
LOGGER.error(LogMarkers.SCAN, "A dependency locator returned a file which is not a ModFile instance!. They will be skipped!");
|
||||
}
|
||||
|
||||
handleLocatedFiles(loadedFiles, locatedFiles);
|
||||
}
|
||||
catch (EarlyLoadingException exception) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to load dependencies with locator {}", locator, exception);
|
||||
discoveryErrorData.addAll(exception.getAllData());
|
||||
}
|
||||
}
|
||||
|
||||
//Second processing run of the mod list. Any duplicates will cause resolution failure and only the mods list will be loaded.
|
||||
try {
|
||||
final UniqueModListBuilder modsAndDependenciesUniqueListBuilder = new UniqueModListBuilder(loadedFiles);
|
||||
final UniqueModListBuilder.UniqueModListData uniqueModsAndDependenciesData = modsAndDependenciesUniqueListBuilder.buildUniqueList();
|
||||
|
||||
//We now only need the mod files map, not the list.
|
||||
modFilesMap = uniqueModsAndDependenciesData.modFiles().stream()
|
||||
.collect(Collectors.groupingBy(IModFile::getType));
|
||||
} catch (EarlyLoadingException exception) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Failed to build unique mod list after dependency discovery.", exception);
|
||||
discoveryErrorData.addAll(exception.getAllData());
|
||||
modFilesMap = loadedFiles.stream().collect(Collectors.groupingBy(IModFile::getType));
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Failure notify the listeners.
|
||||
LOGGER.error(LogMarkers.SCAN, "Mod Discovery failed. Skipping dependency discovery.");
|
||||
}
|
||||
|
||||
//Validate the loading. With a deduplicated list, we can now successfully process the artifacts and load
|
||||
//transformer plugins.
|
||||
var validator = new ModValidator(modFilesMap, brokenFiles, discoveryErrorData);
|
||||
validator.stage1Validation();
|
||||
return validator;
|
||||
}
|
||||
|
||||
private void handleLocatedFiles(final List<ModFile> loadedFiles, final List<IModFile> locatedFiles)
|
||||
{
|
||||
var locatedModFiles = locatedFiles.stream().filter(ModFile.class::isInstance).map(ModFile.class::cast).toList();
|
||||
for (IModFile mf : locatedModFiles) {
|
||||
LOGGER.info(LogMarkers.SCAN, "Found mod file {} of type {} with provider {}", mf.getFileName(), mf.getType(), mf.getProvider());
|
||||
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Found mod file "+mf.getFileName()+" of type "+mf.getType()));
|
||||
}
|
||||
loadedFiles.addAll(locatedModFiles);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,10 @@ import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
import net.minecraftforge.forgespi.language.ModFileScanData;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.IModLocator;
|
||||
import net.minecraftforge.forgespi.locating.IModProvider;
|
||||
import net.minecraftforge.forgespi.locating.ModFileFactory;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
@@ -51,9 +53,9 @@ public class ModFile implements IModFile {
|
||||
private Throwable scanError;
|
||||
private final SecureJar jar;
|
||||
private final Type modFileType;
|
||||
private final Manifest manifest;
|
||||
private final IModLocator locator;
|
||||
private IModFileInfo modFileInfo;
|
||||
private final Manifest manifest;
|
||||
private final IModProvider provider;
|
||||
private IModFileInfo modFileInfo;
|
||||
private ModFileScanData fileModFileScanData;
|
||||
private CompletableFuture<ModFileScanData> futureScanResult;
|
||||
private List<CoreModFile> coreMods;
|
||||
@@ -62,15 +64,19 @@ public class ModFile implements IModFile {
|
||||
static final Attributes.Name TYPE = new Attributes.Name("FMLModType");
|
||||
private SecureJar.Status securityStatus;
|
||||
|
||||
public ModFile(final SecureJar jar, final IModLocator locator, final ModFileFactory.ModFileInfoParser parser) {
|
||||
this.locator = locator;
|
||||
public ModFile(final SecureJar jar, final IModProvider provider, final ModFileFactory.ModFileInfoParser parser) {
|
||||
this(jar, provider, parser, parseType(jar));
|
||||
}
|
||||
|
||||
public ModFile(final SecureJar jar, final IModProvider provider, final ModFileFactory.ModFileInfoParser parser, String type) {
|
||||
this.provider = provider;
|
||||
this.jar = jar;
|
||||
this.parser = parser;
|
||||
|
||||
manifest = this.jar.getManifest();
|
||||
final Optional<String> value = Optional.ofNullable(manifest.getMainAttributes().getValue(TYPE));
|
||||
modFileType = Type.valueOf(value.orElse("MOD"));
|
||||
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, this.parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +129,7 @@ public class ModFile implements IModFile {
|
||||
}
|
||||
|
||||
public void scanFile(Consumer<Path> pathConsumer) {
|
||||
locator.scanFile(this, pathConsumer);
|
||||
provider.scanFile(this, pathConsumer);
|
||||
}
|
||||
|
||||
public void setFutureScanResult(CompletableFuture<ModFileScanData> future) {
|
||||
@@ -188,8 +194,8 @@ public class ModFile implements IModFile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModLocator getLocator() {
|
||||
return locator;
|
||||
public IModProvider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,4 +207,15 @@ public class ModFile implements IModFile {
|
||||
public void setSecurityStatus(final SecureJar.Status status) {
|
||||
this.securityStatus = status;
|
||||
}
|
||||
|
||||
public ArtifactVersion getJarVersion()
|
||||
{
|
||||
return new DefaultArtifactVersion(this.jarVersion);
|
||||
}
|
||||
|
||||
private static String parseType(final SecureJar jar) {
|
||||
final Manifest m = jar.moduleDataProvider().getManifest();
|
||||
final Optional<String> value = Optional.ofNullable(m.getMainAttributes().getValue(TYPE));
|
||||
return value.orElse("MOD");
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,11 @@ import net.minecraftforge.fml.loading.StringUtils;
|
||||
import net.minecraftforge.forgespi.language.IConfigurable;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
|
||||
import net.minecraftforge.forgespi.locating.ForgeFeature;
|
||||
import org.apache.maven.artifact.versioning.ArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
@@ -32,6 +31,7 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
private static final DefaultArtifactVersion DEFAULT_VERSION = new DefaultArtifactVersion("1");
|
||||
private static final Pattern VALID_MODID = Pattern.compile("^[a-z][a-z0-9_]{1,63}$");
|
||||
private static final Pattern VALID_NAMESPACE = Pattern.compile("^[a-z][a-z0-9_.-]{1,63}$");
|
||||
private static final Pattern VALID_VERSION = Pattern.compile("^\\d+.*");
|
||||
|
||||
private final ModFileInfo owningFile;
|
||||
private final String modId;
|
||||
@@ -43,8 +43,11 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
private final boolean logoBlur;
|
||||
private final Optional<URL> updateJSONURL;
|
||||
private final List<? extends IModInfo.ModVersion> dependencies;
|
||||
|
||||
private final List<ForgeFeature.Bound> features;
|
||||
private final Map<String,Object> properties;
|
||||
private final IConfigurable config;
|
||||
private final Optional<URL> modUrl;
|
||||
|
||||
public ModInfo(final ModFileInfo owningFile, final IConfigurable config)
|
||||
{
|
||||
@@ -83,9 +86,23 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
.collect(Collectors.toList()))
|
||||
.orElse(Collections.emptyList());
|
||||
|
||||
this.features = ownFile.map(mfi -> mfi.<Map<String, String>>getConfigElement("features", this.modId)
|
||||
.stream()
|
||||
.flatMap(m->m.entrySet().stream())
|
||||
.map(e->new ForgeFeature.Bound(e.getKey(), e.getValue(), this))
|
||||
.collect(Collectors.toList())).orElse(Collections.emptyList());
|
||||
|
||||
this.properties = ownFile.map(mfi -> mfi.<Map<String, Object>>getConfigElement("modproperties", this.modId)
|
||||
.orElse(Collections.emptyMap()))
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
this.modUrl = config.<String>getConfigElement("modUrl")
|
||||
.map(StringUtils::toURL);
|
||||
|
||||
// verify we have a valid mod version otherwise throw an exception
|
||||
if (!VALID_VERSION.matcher(this.version.toString()).matches()) {
|
||||
throw new InvalidModFileException("Illegal version number specified "+this.version, this.getOwningFile());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,6 +169,11 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ForgeFeature.Bound> getForgeFeatures() {
|
||||
return this.features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> getConfigElement(final String... key) {
|
||||
return this.config.getConfigElement(key);
|
||||
@@ -162,6 +184,11 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> getModURL() {
|
||||
return modUrl;
|
||||
}
|
||||
|
||||
class ModVersion implements net.minecraftforge.forgespi.language.IModInfo.ModVersion {
|
||||
private IModInfo owner;
|
||||
private final String modId;
|
||||
@@ -169,6 +196,7 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
private final boolean mandatory;
|
||||
private final Ordering ordering;
|
||||
private final DependencySide side;
|
||||
private Optional<URL> referralUrl;
|
||||
|
||||
public ModVersion(final IModInfo owner, final IConfigurable config) {
|
||||
this.owner = owner;
|
||||
@@ -185,6 +213,8 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
this.side = config.<String>getConfigElement("side")
|
||||
.map(DependencySide::valueOf)
|
||||
.orElse(DependencySide.BOTH);
|
||||
this.referralUrl = config.<String>getConfigElement("referralUrl")
|
||||
.map(StringUtils::toURL);
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +259,11 @@ public class ModInfo implements IModInfo, IConfigurable
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URL> getReferralURL() {
|
||||
return referralUrl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+23
-11
@@ -13,11 +13,16 @@ import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.fml.loading.ModSorter;
|
||||
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModValidator {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -25,14 +30,17 @@ public class ModValidator {
|
||||
private final List<ModFile> candidatePlugins;
|
||||
private final List<ModFile> candidateMods;
|
||||
private LoadingModList loadingModList;
|
||||
private List<ModFile> brokenFiles;
|
||||
private List<IModFile> brokenFiles;
|
||||
private final List<EarlyLoadingException.ExceptionData> discoveryErrorData;
|
||||
|
||||
public ModValidator(final Map<IModFile.Type, List<ModFile>> modFiles) {
|
||||
public ModValidator(final Map<IModFile.Type, List<ModFile>> modFiles, final List<IModFileInfo> brokenFiles, final List<EarlyLoadingException.ExceptionData> discoveryErrorData) {
|
||||
this.modFiles = modFiles;
|
||||
this.candidateMods = lst(modFiles.get(IModFile.Type.MOD));
|
||||
this.candidateMods.addAll(lst(modFiles.get(IModFile.Type.GAMELIBRARY)));
|
||||
this.candidatePlugins = lst(modFiles.get(IModFile.Type.LANGPROVIDER));
|
||||
this.candidatePlugins.addAll(lst(modFiles.get(IModFile.Type.LIBRARY)));
|
||||
this.discoveryErrorData = discoveryErrorData;
|
||||
this.brokenFiles = brokenFiles.stream().map(IModFileInfo::getFile).collect(Collectors.toList()); // mutable list
|
||||
}
|
||||
|
||||
private static List<ModFile> lst(List<ModFile> files) {
|
||||
@@ -40,7 +48,7 @@ public class ModValidator {
|
||||
}
|
||||
|
||||
public void stage1Validation() {
|
||||
brokenFiles = validateFiles(candidateMods);
|
||||
brokenFiles.addAll(validateFiles(candidateMods));
|
||||
if (LOGGER.isDebugEnabled(LogMarkers.SCAN)) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod files with {} mods", candidateMods.size(), candidateMods.stream().mapToInt(mf -> mf.getModInfos().size()).sum());
|
||||
}
|
||||
@@ -52,22 +60,22 @@ public class ModValidator {
|
||||
final List<ModFile> brokenFiles = new ArrayList<>();
|
||||
for (Iterator<ModFile> iterator = mods.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
ModFile mod = iterator.next();
|
||||
if (!mod.getLocator().isValid(mod) || !mod.identifyMods()) {
|
||||
LOGGER.warn(LogMarkers.SCAN, "File {} has been ignored - it is invalid", mod.getFilePath());
|
||||
ModFile modFile = iterator.next();
|
||||
if (!modFile.getProvider().isValid(modFile) || !modFile.identifyMods()) {
|
||||
LOGGER.warn(LogMarkers.SCAN, "File {} has been ignored - it is invalid", modFile.getFilePath());
|
||||
iterator.remove();
|
||||
brokenFiles.add(mod);
|
||||
brokenFiles.add(modFile);
|
||||
}
|
||||
}
|
||||
return brokenFiles;
|
||||
}
|
||||
|
||||
public ITransformationService.Resource getPluginResources() {
|
||||
return new ITransformationService.Resource(IModuleLayerManager.Layer.PLUGIN, this.candidatePlugins.stream().map(ModFile::getSecureJar).toList());
|
||||
return new ITransformationService.Resource(IModuleLayerManager.Layer.PLUGIN, this.candidatePlugins.stream().map(IModFile::getSecureJar).toList());
|
||||
}
|
||||
|
||||
public ITransformationService.Resource getModResources() {
|
||||
return new ITransformationService.Resource(IModuleLayerManager.Layer.GAME, this.candidateMods.stream().map(ModFile::getSecureJar).toList());
|
||||
return new ITransformationService.Resource(IModuleLayerManager.Layer.GAME, this.candidateMods.stream().map(IModFile::getSecureJar).toList());
|
||||
}
|
||||
|
||||
private List<EarlyLoadingException.ExceptionData> validateLanguages() {
|
||||
@@ -86,7 +94,11 @@ public class ModValidator {
|
||||
|
||||
public BackgroundScanHandler stage2Validation() {
|
||||
var errors = validateLanguages();
|
||||
loadingModList = ModSorter.sort(candidateMods, errors);
|
||||
|
||||
var allErrors = new ArrayList<>(errors);
|
||||
allErrors.addAll(this.discoveryErrorData);
|
||||
|
||||
loadingModList = ModSorter.sort(candidateMods, allErrors);
|
||||
loadingModList.addCoreMods();
|
||||
loadingModList.addAccessTransformers();
|
||||
loadingModList.setBrokenFiles(brokenFiles);
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.uncheck;
|
||||
/**
|
||||
* Support loading mods located in JAR files in the mods folder
|
||||
*/
|
||||
public class ModsFolderLocator extends AbstractJarFileLocator {
|
||||
public class ModsFolderLocator extends AbstractJarFileModLocator
|
||||
{
|
||||
private static final String SUFFIX = ".jar";
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final Path modFolder;
|
||||
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LibraryFinder;
|
||||
import net.minecraftforge.fml.loading.VersionInfo;
|
||||
@@ -21,10 +22,9 @@ public abstract class CommonClientLaunchHandler extends CommonLaunchHandler {
|
||||
@Override public boolean isProduction() { return true; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.client.main.Main").getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+10
-19
@@ -5,8 +5,8 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import net.minecraftforge.fml.loading.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
@@ -30,7 +30,7 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
|
||||
// The extra jar is on the classpath, so try and pull it out of the legacy classpath
|
||||
var legacyCP = Objects.requireNonNull(System.getProperty("legacyClassPath"), "Missing legacyClassPath, cannot find client-extra").split(File.pathSeparator);
|
||||
var extra = Paths.get(Arrays.stream(legacyCP).filter(e -> e.contains("client-extra")).findFirst().orElseThrow(() -> new IllegalStateException("Could not find client-extra in legacy classpath")));
|
||||
var extra = findJarOnClasspath(legacyCP, "client-extra");
|
||||
mcstream.add(extra);
|
||||
|
||||
// The MC code/Patcher edits are in exploded directories
|
||||
@@ -50,8 +50,6 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
if (getDist().isDedicatedServer())
|
||||
return arguments;
|
||||
|
||||
fixNatives();
|
||||
|
||||
if (isData())
|
||||
return arguments;
|
||||
|
||||
@@ -80,11 +78,18 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
protected List<Path> getFmlStuff(String[] classpath) {
|
||||
// We also want the FML things, fmlcore, javafmllanguage, mclanguage, I don't like hard coding these, but hey whatever works for now.
|
||||
return Arrays.stream(classpath)
|
||||
.filter(e -> e.contains("fmlcore") || e.contains("javafmllanguage") || e.contains("lowcodelanguage") || e.contains("mclanguage"))
|
||||
.filter(e -> FileUtils.matchFileName(e, "fmlcore", "javafmllanguage", "lowcodelanguage", "mclanguage"))
|
||||
.map(Paths::get)
|
||||
.toList();
|
||||
}
|
||||
|
||||
protected static Path findJarOnClasspath(String[] classpath, String match) {
|
||||
return Paths.get(Arrays.stream(classpath)
|
||||
.filter(e -> FileUtils.matchFileName(e, match))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Could not find " + match + " in classpath")));
|
||||
}
|
||||
|
||||
protected BiPredicate<String, String> getMcFilter(Path extra, List<Path> minecraft, Stream.Builder<List<Path>> mods) {
|
||||
final var packages = getPackages();
|
||||
final var extraPath = extra.toString().replace('\\', '/');
|
||||
@@ -119,18 +124,4 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
// Generate a time-based random number, to mimic how n.m.client.Main works
|
||||
return Long.toString(System.nanoTime() % (int) Math.pow(10, length));
|
||||
}
|
||||
|
||||
private static void fixNatives() {
|
||||
String paths = System.getProperty("java.library.path");
|
||||
String nativesDir = System.getProperty("nativesDirectory");
|
||||
if (nativesDir == null)
|
||||
return;
|
||||
|
||||
if (Strings.isNullOrEmpty(paths))
|
||||
paths = nativesDir;
|
||||
else
|
||||
paths += File.pathSeparator + nativesDir;
|
||||
|
||||
System.setProperty("java.library.path", paths);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -6,6 +6,7 @@
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import net.minecraftforge.fml.loading.LibraryFinder;
|
||||
import net.minecraftforge.fml.loading.VersionInfo;
|
||||
@@ -23,10 +24,9 @@ public abstract class CommonServerLaunchHandler extends CommonLaunchHandler {
|
||||
@Override public boolean isProduction() { return true; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.server.Main").getMethod("main", String[].class).invoke(null, (Object)arguments);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
-6
@@ -10,8 +10,6 @@ import net.minecraftforge.fml.loading.VersionInfo;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -41,8 +39,4 @@ public abstract class CommonUserdevLaunchHandler extends CommonDevLaunchHandler
|
||||
}
|
||||
|
||||
protected abstract void processStreams(String[] classpath, VersionInfo versionInfo, Stream.Builder<Path> mc, Stream.Builder<List<Path>> mods);
|
||||
|
||||
protected static Path findJarOnClasspath(String[] classpath, String match) {
|
||||
return Paths.get(Arrays.stream(classpath).filter(e -> e.contains(match)).findFirst().orElseThrow(() -> new IllegalStateException("Could not find " + match + " in classpath")));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -13,12 +14,11 @@ public class FMLClientDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.CLIENT; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.client.main.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -17,12 +18,11 @@ public class FMLClientUserdevLaunchHandler extends FMLUserdevLaunchHandler {
|
||||
public Dist getDist() { return Dist.CLIENT; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.client.main.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -20,12 +21,11 @@ public class FMLDataUserdevLaunchHandler extends FMLUserdevLaunchHandler {
|
||||
public boolean isData() { return true; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.data.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -13,12 +14,11 @@ public class FMLServerDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.server.Main").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -14,12 +15,11 @@ public class FMLServerUserdevLaunchHandler extends FMLUserdevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.server.Main").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -13,12 +14,11 @@ public class ForgeClientDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.CLIENT; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.client.main.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -17,12 +18,11 @@ public class ForgeClientUserdevLaunchHandler extends ForgeUserdevLaunchHandler {
|
||||
public Dist getDist() { return Dist.CLIENT; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.client.main.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -15,12 +16,11 @@ public class ForgeDataDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public boolean isData() { return true; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.data.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -20,12 +21,11 @@ public class ForgeDataUserdevLaunchHandler extends ForgeUserdevLaunchHandler {
|
||||
public boolean isData() { return true; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(), "net.minecraft.data.Main").getMethod("main", String[].class).invoke(null, (Object) args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -14,12 +15,11 @@ public class ForgeGametestDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("forge").orElseThrow(), "net.minecraftforge.gametest.GameTestMain").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -14,12 +15,11 @@ public class ForgeGametestUserdevLaunchHandler extends ForgeUserdevLaunchHandler
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("forge").orElseThrow(), "net.minecraftforge.gametest.GameTestMain").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -13,12 +14,11 @@ public class ForgeServerDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.server.Main").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package net.minecraftforge.fml.loading.targets;
|
||||
|
||||
import cpw.mods.modlauncher.api.ServiceRunner;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -14,12 +15,11 @@ public class ForgeServerUserdevLaunchHandler extends ForgeUserdevLaunchHandler {
|
||||
@Override public Dist getDist() { return Dist.DEDICATED_SERVER; }
|
||||
|
||||
@Override
|
||||
public Callable<Void> launchService(String[] arguments, ModuleLayer layer) {
|
||||
public ServiceRunner launchService(String[] arguments, ModuleLayer layer) {
|
||||
return () -> {
|
||||
var args = preLaunch(arguments, layer);
|
||||
|
||||
Class.forName(layer.findModule("minecraft").orElseThrow(),"net.minecraft.server.Main").getMethod("main", String[].class).invoke(null, (Object)args);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+1
@@ -19,6 +19,7 @@ public final class CyclePresentException extends IllegalArgumentException {
|
||||
* @param cycles the cycles present
|
||||
*/
|
||||
CyclePresentException(Set<Set<?>> cycles) {
|
||||
super("Cycles present in graph: " + cycles);
|
||||
this.cycles = cycles;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,3 +4,5 @@ splashscreen = true
|
||||
maxThreads = -1
|
||||
# Enable forge global version checking
|
||||
versionCheck = true
|
||||
# Disables Optimized DFU client-side.
|
||||
disableOptimizedDFU = true
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
net.minecraftforge.fml.loading.ModDirTransformerDiscoverer
|
||||
net.minecraftforge.fml.loading.ModDirTransformerDiscoverer
|
||||
net.minecraftforge.fml.loading.ClasspathTransformerDiscoverer
|
||||
+1
@@ -0,0 +1 @@
|
||||
net.minecraftforge.fml.loading.moddiscovery.JarInJarDependencyLocator
|
||||
@@ -13,6 +13,7 @@
|
||||
<MarkerFilter marker="REGISTRIES" onMatch="${sys:forge.logging.marker.registries:-DENY}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="REGISTRYDUMP" onMatch="${sys:forge.logging.marker.registrydump:-DENY}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="SPLASH" onMatch="${sys:forge.logging.marker.splash:-DENY}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="RESOURCE-CACHE" onMatch="${sys:forge.logging.marker.resource.cache:-DENY}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="FORGEMOD" onMatch="${sys:forge.logging.marker.forgemod:-ACCEPT}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="LOADING" onMatch="${sys:forge.logging.marker.loading:-ACCEPT}" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="CORE" onMatch="${sys:forge.logging.marker.core:-ACCEPT}" onMismatch="NEUTRAL"/>
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -205,6 +205,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
||||
Vendored
+8
-6
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public class FMLModContainer extends ModContainer
|
||||
LOGGER.debug(LOADING,"Creating FMLModContainer instance for {}", className);
|
||||
this.scanResults = modFileScanResults;
|
||||
activityMap.put(ModLoadingStage.CONSTRUCT, this::constructMod);
|
||||
this.eventBus = BusBuilder.builder().setExceptionHandler(this::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).build();
|
||||
this.eventBus = BusBuilder.builder().setExceptionHandler(this::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
|
||||
this.configHandler = Optional.of(ce->this.eventBus.post(ce.self()));
|
||||
final FMLJavaModLoadingContext contextExtension = new FMLJavaModLoadingContext(this);
|
||||
this.contextExtension = () -> contextExtension;
|
||||
|
||||
@@ -12,7 +12,8 @@ dependencyUpdates.rejectVersionIf { isNonStable(it.candidate.version) }
|
||||
java.withSourcesJar()
|
||||
|
||||
dependencies {
|
||||
compileOnly('org.jetbrains:annotations:21.0.1')
|
||||
compileOnly("org.jetbrains:annotations:${JETBRAINS_ANNOTATIONS_VERSION}")
|
||||
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class LowCodeModLanguageProvider implements IModLanguageProvider
|
||||
throw new ModLoadingException(info, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadmodclass", e);
|
||||
}
|
||||
} catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
||||
LOGGER.fatal(LOADING, "Unable to load FMLModContainer, wut?", e);
|
||||
LOGGER.fatal(LOADING, "Unable to load LowCodeModContainer, wut?", e);
|
||||
final Class<RuntimeException> mle = (Class<RuntimeException>) LamdbaExceptionUtils.uncheck(() -> Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
|
||||
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(() -> Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
|
||||
throw LamdbaExceptionUtils.uncheck(() -> LamdbaExceptionUtils.uncheck(() -> mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
|
||||
|
||||
Additional Resources:
|
||||
=========================
|
||||
Community Documentation: http://mcforge.readthedocs.io/en/latest/gettingstarted/
|
||||
Community Documentation: https://mcforge.readthedocs.io/en/latest/gettingstarted/
|
||||
LexManos' Install Video: https://www.youtube.com/watch?v=8VEdtQLuLO0
|
||||
Forge Forum: https://forums.minecraftforge.net/
|
||||
Forge Discord: https://discord.gg/UvedJ9m
|
||||
Forge Discord: https://discord.gg/UvedJ9m
|
||||
+1
-13
@@ -1,7 +1,7 @@
|
||||
plugins {
|
||||
id 'eclipse'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.gradle' version '5.+'
|
||||
id 'net.minecraftforge.gradle' version '5.1.+'
|
||||
}
|
||||
|
||||
version = '1.0'
|
||||
@@ -65,7 +65,6 @@ minecraft {
|
||||
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
|
||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
||||
property 'forge.enabledGameTestNamespaces', 'examplemod'
|
||||
|
||||
mods {
|
||||
@@ -81,19 +80,10 @@ minecraft {
|
||||
gameTestServer {
|
||||
workingDirectory project.file('run')
|
||||
|
||||
// Recommended logging data for a userdev environment
|
||||
// The markers can be added/remove as needed separated by commas.
|
||||
// "SCAN": For mods scan.
|
||||
// "REGISTRIES": For firing of registry events.
|
||||
// "REGISTRYDUMP": For getting the contents of all registries.
|
||||
property 'forge.logging.markers', 'REGISTRIES'
|
||||
|
||||
// Recommended logging level for the console
|
||||
// You can set various levels here.
|
||||
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
|
||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
||||
property 'forge.enabledGameTestNamespaces', 'examplemod'
|
||||
|
||||
mods {
|
||||
@@ -142,8 +132,6 @@ dependencies {
|
||||
minecraft '@FORGE_GROUP@:@FORGE_NAME@:@FORGE_VERSION@'
|
||||
|
||||
// Real mod deobf dependency examples - these get remapped to your current mappings
|
||||
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
|
||||
// runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
|
||||
// implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
|
||||
|
||||
// Examples using mod jars from ./libs
|
||||
|
||||
@@ -1,61 +1,72 @@
|
||||
package com.example.examplemod;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.CreativeModeTabs;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.material.Material;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.InterModComms;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
|
||||
import net.minecraftforge.event.CreativeModeTabEvent;
|
||||
import net.minecraftforge.event.server.ServerStartingEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// The value here should match an entry in the META-INF/mods.toml file
|
||||
@Mod("examplemod")
|
||||
@Mod(ExampleMod.MODID)
|
||||
public class ExampleMod
|
||||
{
|
||||
// Define mod id in a common place for everything to reference
|
||||
public static final String MODID = "examplemod";
|
||||
// Directly reference a slf4j logger
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
// Create a Deferred Register to hold Blocks which will all be registered under the "examplemod" namespace
|
||||
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MODID);
|
||||
// Create a Deferred Register to hold Items which will all be registered under the "examplemod" namespace
|
||||
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
|
||||
|
||||
// Creates a new Block with the id "examplemod:example_block", combining the namespace and path
|
||||
public static final RegistryObject<Block> EXAMPLE_BLOCK = BLOCKS.register("example_block", () -> new Block(BlockBehaviour.Properties.of(Material.STONE)));
|
||||
// Creates a new BlockItem with the id "examplemod:example_block", combining the namespace and path
|
||||
public static final RegistryObject<Item> EXAMPLE_BLOCK_ITEM = ITEMS.register("example_block", () -> new BlockItem(EXAMPLE_BLOCK.get(), new Item.Properties()));
|
||||
|
||||
public ExampleMod()
|
||||
{
|
||||
// Register the setup method for modloading
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
|
||||
// Register the enqueueIMC method for modloading
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
|
||||
// Register the processIMC method for modloading
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
|
||||
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
|
||||
// Register the commonSetup method for modloading
|
||||
modEventBus.addListener(this::commonSetup);
|
||||
|
||||
// Register the Deferred Register to the mod event bus so blocks get registered
|
||||
BLOCKS.register(modEventBus);
|
||||
// Register the Deferred Register to the mod event bus so items get registered
|
||||
ITEMS.register(modEventBus);
|
||||
|
||||
// Register ourselves for server and other game events we are interested in
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
|
||||
// Register the item to a creative tab
|
||||
modEventBus.addListener((CreativeModeTabEvent.BuildContents event) -> event.registerSimple(CreativeModeTabs.BUILDING_BLOCKS,
|
||||
EXAMPLE_BLOCK_ITEM.get()));
|
||||
}
|
||||
|
||||
private void setup(final FMLCommonSetupEvent event)
|
||||
private void commonSetup(final FMLCommonSetupEvent event)
|
||||
{
|
||||
// some preinit code
|
||||
LOGGER.info("HELLO FROM PREINIT");
|
||||
LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
|
||||
}
|
||||
|
||||
private void enqueueIMC(final InterModEnqueueEvent event)
|
||||
{
|
||||
// Some example code to dispatch IMC to another mod
|
||||
InterModComms.sendTo("examplemod", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";});
|
||||
}
|
||||
|
||||
private void processIMC(final InterModProcessEvent event)
|
||||
{
|
||||
// Some example code to receive and process InterModComms from other mods
|
||||
LOGGER.info("Got IMC {}", event.getIMCStream().
|
||||
map(m->m.messageSupplier().get()).
|
||||
collect(Collectors.toList()));
|
||||
// Some common setup code
|
||||
LOGGER.info("HELLO FROM COMMON SETUP");
|
||||
LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT));
|
||||
}
|
||||
|
||||
// You can use SubscribeEvent and let the Event Bus discover methods to call
|
||||
@@ -66,16 +77,16 @@ public class ExampleMod
|
||||
LOGGER.info("HELLO from server starting");
|
||||
}
|
||||
|
||||
// You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD
|
||||
// Event bus for receiving Registry Events)
|
||||
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public static class RegistryEvents
|
||||
// You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent
|
||||
@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
|
||||
public static class ClientModEvents
|
||||
{
|
||||
@SubscribeEvent
|
||||
public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent)
|
||||
public static void onClientSetup(FMLClientSetupEvent event)
|
||||
{
|
||||
// Register a new block here
|
||||
LOGGER.info("HELLO from Register Block");
|
||||
// Some client setup code
|
||||
LOGGER.info("HELLO FROM CLIENT SETUP");
|
||||
LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,14 @@ logoFile="examplemod.png" #optional
|
||||
credits="Thanks for this example mod goes to Java" #optional
|
||||
# A text field displayed in the mod UI
|
||||
authors="Love, Cheese and small house plants" #optional
|
||||
# Display Test controls the display for your mod in the server connection screen
|
||||
# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
|
||||
# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
|
||||
# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component.
|
||||
# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value.
|
||||
# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself.
|
||||
#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional)
|
||||
|
||||
# The description text for the mod (multi line!) (#mandatory)
|
||||
description='''
|
||||
This is a long form description of the mod. You can write whatever you want here
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"pack": {
|
||||
"description": "examplemod resources",
|
||||
"pack_format": 9,
|
||||
"forge:resource_pack_format": 9,
|
||||
"pack_format": 12,
|
||||
"forge:resource_pack_format": 12,
|
||||
"forge:data_pack_format": 10
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/com/mojang/blaze3d/platform/GlStateManager.java
|
||||
+++ b/com/mojang/blaze3d/platform/GlStateManager.java
|
||||
@@ -539,9 +_,16 @@
|
||||
@@ -510,9 +_,16 @@
|
||||
f_84077_[f_84076_].f_84800_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/com/mojang/blaze3d/platform/Window.java
|
||||
+++ b/com/mojang/blaze3d/platform/Window.java
|
||||
@@ -80,7 +_,7 @@
|
||||
@@ -82,7 +_,7 @@
|
||||
GLFW.glfwWindowHint(139267, 2);
|
||||
GLFW.glfwWindowHint(139272, 204801);
|
||||
GLFW.glfwWindowHint(139270, 1);
|
||||
@@ -9,7 +9,7 @@
|
||||
if (monitor != null) {
|
||||
VideoMode videomode = monitor.m_84948_(this.f_85355_ ? this.f_85354_ : Optional.empty());
|
||||
this.f_85350_ = this.f_85357_ = monitor.m_84951_() + videomode.m_85332_() / 2 - this.f_85359_ / 2;
|
||||
@@ -298,6 +_,7 @@
|
||||
@@ -263,6 +_,7 @@
|
||||
GLFW.glfwGetFramebufferSize(this.f_85349_, aint, aint1);
|
||||
this.f_85361_ = aint[0] > 0 ? aint[0] : 1;
|
||||
this.f_85362_ = aint1[0] > 0 ? aint1[0] : 1;
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
--- a/com/mojang/blaze3d/vertex/BufferBuilder.java
|
||||
+++ b/com/mojang/blaze3d/vertex/BufferBuilder.java
|
||||
@@ -486,4 +_,15 @@
|
||||
this.f_166822_ = p_166829_;
|
||||
@@ -486,4 +_,14 @@
|
||||
this.f_166822_ = p_254368_;
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Forge start
|
||||
+ public void putBulkData(ByteBuffer buffer) {
|
||||
+ m_85722_(buffer.limit() + this.f_85658_.m_86020_());
|
||||
+ this.f_85648_.position(this.f_85654_ * this.f_85658_.m_86020_());
|
||||
+ this.f_85648_.position(this.f_85652_);
|
||||
+ this.f_85648_.put(buffer);
|
||||
+ this.f_85648_.position(0);
|
||||
+ this.f_85654_ += buffer.limit() / this.f_85658_.m_86020_();
|
||||
+ this.f_85652_ += buffer.limit();
|
||||
+ }
|
||||
+
|
||||
+ public VertexFormat getVertexFormat() { return this.f_85658_; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/com/mojang/blaze3d/vertex/PoseStack.java
|
||||
+++ b/com/mojang/blaze3d/vertex/PoseStack.java
|
||||
@@ -11,7 +_,7 @@
|
||||
import org.joml.Quaternionf;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
-public class PoseStack {
|
||||
+public class PoseStack implements net.minecraftforge.client.extensions.IForgePoseStack {
|
||||
private final Deque<PoseStack.Pose> f_85834_ = Util.m_137469_(Queues.newArrayDeque(), (p_85848_) -> {
|
||||
Matrix4f matrix4f = new Matrix4f();
|
||||
Matrix3f matrix3f = new Matrix3f();
|
||||
@@ -9,7 +9,18 @@
|
||||
VertexConsumer m_5483_(double p_85945_, double p_85946_, double p_85947_);
|
||||
|
||||
VertexConsumer m_6122_(int p_85973_, int p_85974_, int p_85975_, int p_85976_);
|
||||
@@ -101,11 +_,12 @@
|
||||
@@ -64,6 +_,10 @@
|
||||
}
|
||||
|
||||
default void m_85995_(PoseStack.Pose p_85996_, BakedQuad p_85997_, float[] p_85998_, float p_85999_, float p_86000_, float p_86001_, int[] p_86002_, int p_86003_, boolean p_86004_) {
|
||||
+ putBulkData(p_85996_, p_85997_, p_85998_, p_85999_, p_86000_, p_86001_, 1, p_86002_, p_86003_, p_86004_);
|
||||
+ }
|
||||
+
|
||||
+ default void putBulkData(PoseStack.Pose p_85996_, BakedQuad p_85997_, float[] p_85998_, float p_85999_, float p_86000_, float p_86001_, float alpha, int[] p_86002_, int p_86003_, boolean p_86004_) {
|
||||
float[] afloat = new float[]{p_85998_[0], p_85998_[1], p_85998_[2], p_85998_[3]};
|
||||
int[] aint = new int[]{p_86002_[0], p_86002_[1], p_86002_[2], p_86002_[3]};
|
||||
int[] aint1 = p_85997_.m_111303_();
|
||||
@@ -99,11 +_,13 @@
|
||||
f5 = afloat[k] * p_86001_;
|
||||
}
|
||||
|
||||
@@ -17,9 +28,11 @@
|
||||
+ int l = applyBakedLighting(p_86002_[k], bytebuffer);
|
||||
float f9 = bytebuffer.getFloat(16);
|
||||
float f10 = bytebuffer.getFloat(20);
|
||||
Vector4f vector4f = new Vector4f(f, f1, f2, 1.0F);
|
||||
vector4f.m_123607_(matrix4f);
|
||||
+ applyBakedNormals(vector3f, bytebuffer, p_85996_.m_85864_());
|
||||
this.m_5954_(vector4f.m_123601_(), vector4f.m_123615_(), vector4f.m_123616_(), f3, f4, f5, 1.0F, f9, f10, p_86003_, l, vector3f.m_122239_(), vector3f.m_122260_(), vector3f.m_122269_());
|
||||
Vector4f vector4f = matrix4f.transform(new Vector4f(f, f1, f2, 1.0F));
|
||||
- this.m_5954_(vector4f.x(), vector4f.y(), vector4f.z(), f3, f4, f5, 1.0F, f9, f10, p_86003_, l, vector3f.x(), vector3f.y(), vector3f.z());
|
||||
+ applyBakedNormals(vector3f, bytebuffer, p_85996_.m_252943_());
|
||||
+ float vertexAlpha = p_86004_ ? alpha * (float) (bytebuffer.get(15) & 255) / 255.0F : alpha;
|
||||
+ this.m_5954_(vector4f.x(), vector4f.y(), vector4f.z(), f3, f4, f5, vertexAlpha, f9, f10, p_86003_, l, vector3f.x(), vector3f.y(), vector3f.z());
|
||||
}
|
||||
} catch (Throwable throwable1) {
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
--- a/com/mojang/math/Matrix3f.java
|
||||
+++ b/com/mojang/math/Matrix3f.java
|
||||
@@ -588,4 +_,10 @@
|
||||
public Matrix3f m_8183_() {
|
||||
return new Matrix3f(this);
|
||||
}
|
||||
+
|
||||
+ public void multiplyBackward(Matrix3f other) {
|
||||
+ Matrix3f copy = other.m_8183_();
|
||||
+ copy.m_8178_(this);
|
||||
+ this.m_8169_(copy);
|
||||
+ }
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
--- a/com/mojang/math/Matrix4f.java
|
||||
+++ b/com/mojang/math/Matrix4f.java
|
||||
@@ -559,4 +_,40 @@
|
||||
matrix4f.f_27614_ = p_27656_;
|
||||
return matrix4f;
|
||||
}
|
||||
+
|
||||
+ // Forge start
|
||||
+ public Matrix4f(float[] values) {
|
||||
+ f_27603_ = values[0];
|
||||
+ f_27604_ = values[1];
|
||||
+ f_27605_ = values[2];
|
||||
+ f_27606_ = values[3];
|
||||
+ f_27607_ = values[4];
|
||||
+ f_27608_ = values[5];
|
||||
+ f_27609_ = values[6];
|
||||
+ f_27610_ = values[7];
|
||||
+ f_27611_ = values[8];
|
||||
+ f_27612_ = values[9];
|
||||
+ f_27613_ = values[10];
|
||||
+ f_27614_ = values[11];
|
||||
+ f_27615_ = values[12];
|
||||
+ f_27616_ = values[13];
|
||||
+ f_27617_ = values[14];
|
||||
+ f_27618_ = values[15];
|
||||
+ }
|
||||
+
|
||||
+ public void multiplyBackward(Matrix4f other) {
|
||||
+ Matrix4f copy = other.m_27658_();
|
||||
+ copy.m_27644_(this);
|
||||
+ this.m_162210_(copy);
|
||||
+ }
|
||||
+
|
||||
+ public void setTranslation(float x, float y, float z) {
|
||||
+ this.f_27603_ = 1.0F;
|
||||
+ this.f_27608_ = 1.0F;
|
||||
+ this.f_27613_ = 1.0F;
|
||||
+ this.f_27618_ = 1.0F;
|
||||
+ this.f_27606_ = x;
|
||||
+ this.f_27610_ = y;
|
||||
+ this.f_27614_ = z;
|
||||
+ }
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
--- a/com/mojang/math/Transformation.java
|
||||
+++ b/com/mojang/math/Transformation.java
|
||||
@@ -6,7 +_,7 @@
|
||||
import net.minecraft.Util;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
@@ -12,7 +_,7 @@
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector3fc;
|
||||
|
||||
-public final class Transformation {
|
||||
+public final class Transformation implements net.minecraftforge.client.extensions.IForgeTransformation {
|
||||
private final Matrix4f f_121078_;
|
||||
private boolean f_121079_;
|
||||
@Nullable
|
||||
@@ -145,6 +_,19 @@
|
||||
@@ -139,6 +_,19 @@
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.f_121078_);
|
||||
}
|
||||
@@ -22,10 +22,10 @@
|
||||
+ private void checkNormalTransform() {
|
||||
+ if (normalTransform == null) {
|
||||
+ normalTransform = new Matrix3f(f_121078_);
|
||||
+ normalTransform.m_8187_();
|
||||
+ normalTransform.m_8155_();
|
||||
+ normalTransform.invert();
|
||||
+ normalTransform.transpose();
|
||||
+ }
|
||||
+ }
|
||||
|
||||
public Transformation m_175937_(Transformation p_175938_, float p_175939_) {
|
||||
Vector3f vector3f = this.m_175940_();
|
||||
Vector3f vector3f = this.m_252829_();
|
||||
@@ -1,28 +0,0 @@
|
||||
--- a/com/mojang/math/Vector3f.java
|
||||
+++ b/com/mojang/math/Vector3f.java
|
||||
@@ -138,7 +_,7 @@
|
||||
|
||||
public boolean m_122278_() {
|
||||
float f = this.f_122228_ * this.f_122228_ + this.f_122229_ * this.f_122229_ + this.f_122230_ * this.f_122230_;
|
||||
- if ((double)f < 1.0E-5D) {
|
||||
+ if (f < Float.MIN_NORMAL) { //Forge: Fix MC-239212
|
||||
return false;
|
||||
} else {
|
||||
float f1 = Mth.m_14195_(f);
|
||||
@@ -207,4 +_,16 @@
|
||||
public String toString() {
|
||||
return "[" + this.f_122228_ + ", " + this.f_122229_ + ", " + this.f_122230_ + "]";
|
||||
}
|
||||
+
|
||||
+ public Vector3f(float[] values) {
|
||||
+ set(values);
|
||||
+ }
|
||||
+ public void set(float[] values) {
|
||||
+ this.f_122228_ = values[0];
|
||||
+ this.f_122229_ = values[1];
|
||||
+ this.f_122230_ = values[2];
|
||||
+ }
|
||||
+ public void setX(float x) { this.f_122228_ = x; }
|
||||
+ public void setY(float y) { this.f_122229_ = y; }
|
||||
+ public void setZ(float z) { this.f_122230_ = z; }
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
--- a/com/mojang/math/Vector4f.java
|
||||
+++ b/com/mojang/math/Vector4f.java
|
||||
@@ -147,4 +_,15 @@
|
||||
public String toString() {
|
||||
return "[" + this.f_123589_ + ", " + this.f_123590_ + ", " + this.f_123591_ + ", " + this.f_123592_ + "]";
|
||||
}
|
||||
+
|
||||
+ public void set(float[] values) {
|
||||
+ this.f_123589_ = values[0];
|
||||
+ this.f_123590_ = values[1];
|
||||
+ this.f_123591_ = values[2];
|
||||
+ this.f_123592_ = values[3];
|
||||
+ }
|
||||
+ public void setX(float x) { this.f_123589_ = x; }
|
||||
+ public void setY(float y) { this.f_123590_ = y; }
|
||||
+ public void setZ(float z) { this.f_123591_ = z; }
|
||||
+ public void setW(float w) { this.f_123592_ = w; }
|
||||
}
|
||||
+1
-1
@@ -13,6 +13,6 @@
|
||||
+ return super.m_7933_(key, scanCode, modifiers);
|
||||
+ }
|
||||
+
|
||||
public void m_6305_(PoseStack p_88679_, int p_88680_, int p_88681_, float p_88682_) {
|
||||
public void m_86412_(PoseStack p_88679_, int p_88680_, int p_88681_, float p_88682_) {
|
||||
this.m_7333_(p_88679_);
|
||||
m_93215_(p_88679_, this.f_96547_, this.f_200947_.getFirst(), this.f_96543_ / 2, 80, 16777215);
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/CrashReport.java
|
||||
+++ b/net/minecraft/CrashReport.java
|
||||
@@ -55,14 +_,8 @@
|
||||
@@ -57,14 +_,8 @@
|
||||
if (this.f_127506_ != null && this.f_127506_.length > 0) {
|
||||
p_127520_.append("-- Head --\n");
|
||||
p_127520_.append("Thread: ").append(Thread.currentThread().getName()).append("\n");
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
for(CrashReportCategory crashreportcategory : this.f_127503_) {
|
||||
@@ -70,6 +_,7 @@
|
||||
@@ -72,6 +_,7 @@
|
||||
p_127520_.append("\n\n");
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
this.f_178624_.m_143525_(p_127520_);
|
||||
}
|
||||
|
||||
@@ -89,23 +_,13 @@
|
||||
@@ -91,23 +_,13 @@
|
||||
throwable.setStackTrace(this.f_127501_.getStackTrace());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/SharedConstants.java
|
||||
+++ b/net/minecraft/SharedConstants.java
|
||||
@@ -203,6 +_,7 @@
|
||||
@@ -214,6 +_,7 @@
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
--- a/net/minecraft/Util.java
|
||||
+++ b/net/minecraft/Util.java
|
||||
@@ -164,6 +_,11 @@
|
||||
@@ -170,6 +_,11 @@
|
||||
return 255;
|
||||
}
|
||||
|
||||
+ // We add these inner classes to compensate for Mojang's missing inner classes and shift the anonymous class index.
|
||||
+ // This allows us to obfuscate subsequent anonymous inner classes correctly.
|
||||
+ @SuppressWarnings("unused") private static LongSupplier INNER_CLASS_SHIFT1 = new LongSupplier() { public long getAsLong() { return 0; } };
|
||||
+ @SuppressWarnings("unused") private static LongSupplier INNER_CLASS_SHIFT2 = new LongSupplier() { public long getAsLong() { return 0; } };
|
||||
+ @SuppressWarnings("unused") private static java.util.function.LongSupplier INNER_CLASS_SHIFT1 = new java.util.function.LongSupplier() { public long getAsLong() { return 0; } };
|
||||
+ @SuppressWarnings("unused") private static java.util.function.LongSupplier INNER_CLASS_SHIFT2 = new java.util.function.LongSupplier() { public long getAsLong() { return 0; } };
|
||||
+
|
||||
public static ExecutorService m_183988_() {
|
||||
return f_137443_;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/advancements/critereon/ItemPredicate.java
|
||||
+++ b/net/minecraft/advancements/critereon/ItemPredicate.java
|
||||
@@ -28,6 +_,8 @@
|
||||
@@ -29,6 +_,8 @@
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
|
||||
public class ItemPredicate {
|
||||
@@ -9,7 +9,16 @@
|
||||
public static final ItemPredicate f_45028_ = new ItemPredicate();
|
||||
@Nullable
|
||||
private final TagKey<Item> f_45029_;
|
||||
@@ -107,6 +_,11 @@
|
||||
@@ -81,7 +_,7 @@
|
||||
return false;
|
||||
} else {
|
||||
if (this.f_45033_.length > 0) {
|
||||
- Map<Enchantment, Integer> map = EnchantmentHelper.m_44882_(p_45050_.m_41785_());
|
||||
+ Map<Enchantment, Integer> map = p_45050_.getAllEnchantments();
|
||||
|
||||
for(EnchantmentPredicate enchantmentpredicate : this.f_45033_) {
|
||||
if (!enchantmentpredicate.m_30476_(map)) {
|
||||
@@ -108,6 +_,11 @@
|
||||
public static ItemPredicate m_45051_(@Nullable JsonElement p_45052_) {
|
||||
if (p_45052_ != null && !p_45052_.isJsonNull()) {
|
||||
JsonObject jsonobject = GsonHelper.m_13918_(p_45052_, "item");
|
||||
@@ -21,7 +30,7 @@
|
||||
MinMaxBounds.Ints minmaxbounds$ints = MinMaxBounds.Ints.m_55373_(jsonobject.get("count"));
|
||||
MinMaxBounds.Ints minmaxbounds$ints1 = MinMaxBounds.Ints.m_55373_(jsonobject.get("durability"));
|
||||
if (jsonobject.has("data")) {
|
||||
@@ -214,6 +_,14 @@
|
||||
@@ -215,6 +_,14 @@
|
||||
} else {
|
||||
return new ItemPredicate[0];
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/Camera.java
|
||||
+++ b/net/minecraft/client/Camera.java
|
||||
@@ -211,6 +_,18 @@
|
||||
@@ -206,6 +_,18 @@
|
||||
this.f_90549_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
--- a/net/minecraft/client/ClientRecipeBook.java
|
||||
+++ b/net/minecraft/client/ClientRecipeBook.java
|
||||
@@ -103,6 +_,8 @@
|
||||
} else if (recipetype == RecipeType.f_44113_) {
|
||||
return RecipeBookCategories.SMITHING;
|
||||
} else {
|
||||
+ RecipeBookCategories categories = net.minecraftforge.client.RecipeBookRegistry.findCategories(recipetype, p_90647_);
|
||||
+ if (categories != null) return categories;
|
||||
f_90618_.warn("Unknown recipe category: {}/{}", LogUtils.defer(() -> {
|
||||
return Registry.f_122864_.m_7981_(p_90647_.m_6671_());
|
||||
}), LogUtils.defer(p_90647_::m_6423_));
|
||||
@@ -51,7 +_,7 @@
|
||||
for(Recipe<?> recipe : p_90643_) {
|
||||
if (!recipe.m_5598_() && !recipe.m_142505_()) {
|
||||
RecipeBookCategories recipebookcategories = m_90646_(recipe);
|
||||
- String s = recipe.m_6076_();
|
||||
+ String s = recipe.m_6076_().isEmpty() ? recipe.m_6423_().toString() : recipe.m_6076_(); // FORGE: Group value defaults to the recipe's ID if the recipe's explicit group is empty.
|
||||
if (s.isEmpty()) {
|
||||
map.computeIfAbsent(recipebookcategories, (p_90645_) -> {
|
||||
return Lists.newArrayList();
|
||||
@@ -138,6 +_,8 @@
|
||||
} else if (recipetype == RecipeType.f_44113_) {
|
||||
return RecipeBookCategories.SMITHING;
|
||||
} else {
|
||||
+ RecipeBookCategories categories = net.minecraftforge.client.RecipeBookManager.findCategories((RecipeType) recipetype, p_90647_);
|
||||
+ if (categories != null) return categories;
|
||||
f_90618_.warn("Unknown recipe category: {}/{}", LogUtils.defer(() -> {
|
||||
return BuiltInRegistries.f_256990_.m_7981_(p_90647_.m_6671_());
|
||||
}), LogUtils.defer(p_90647_::m_6423_));
|
||||
@@ -8,48 +8,20 @@
|
||||
+public class KeyMapping implements Comparable<KeyMapping>, net.minecraftforge.client.extensions.IForgeKeyMapping {
|
||||
private static final Map<String, KeyMapping> f_90809_ = Maps.newHashMap();
|
||||
- private static final Map<InputConstants.Key, KeyMapping> f_90810_ = Maps.newHashMap();
|
||||
+ private static final net.minecraftforge.client.settings.KeyBindingMap f_90810_ = new net.minecraftforge.client.settings.KeyBindingMap();
|
||||
+ private static final net.minecraftforge.client.settings.KeyMappingLookup f_90810_ = new net.minecraftforge.client.settings.KeyMappingLookup();
|
||||
private static final Set<String> f_90811_ = Sets.newHashSet();
|
||||
public static final String f_167805_ = "key.categories.movement";
|
||||
public static final String f_167806_ = "key.categories.misc";
|
||||
@@ -41,7 +_,7 @@
|
||||
private int f_90818_;
|
||||
|
||||
public static void m_90835_(InputConstants.Key p_90836_) {
|
||||
- KeyMapping keymapping = f_90810_.get(p_90836_);
|
||||
+ KeyMapping keymapping = f_90810_.lookupActive(p_90836_);
|
||||
if (keymapping != null) {
|
||||
++keymapping.f_90818_;
|
||||
}
|
||||
@@ -49,7 +_,7 @@
|
||||
}
|
||||
|
||||
public static void m_90837_(InputConstants.Key p_90838_, boolean p_90839_) {
|
||||
- KeyMapping keymapping = f_90810_.get(p_90838_);
|
||||
+ for (KeyMapping keymapping : f_90810_.lookupAll(p_90838_))
|
||||
+ for (KeyMapping keymapping : f_90810_.getAll(p_90838_))
|
||||
if (keymapping != null) {
|
||||
keymapping.m_7249_(p_90839_);
|
||||
}
|
||||
@@ -73,10 +_,10 @@
|
||||
}
|
||||
|
||||
public static void m_90854_() {
|
||||
- f_90810_.clear();
|
||||
+ f_90810_.clearMap();
|
||||
|
||||
for(KeyMapping keymapping : f_90809_.values()) {
|
||||
- f_90810_.put(keymapping.f_90816_, keymapping);
|
||||
+ f_90810_.addKey(keymapping.f_90816_, keymapping);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -91,12 +_,12 @@
|
||||
this.f_90814_ = this.f_90816_;
|
||||
this.f_90815_ = p_90828_;
|
||||
f_90809_.put(p_90825_, this);
|
||||
- f_90810_.put(this.f_90816_, this);
|
||||
+ f_90810_.addKey(this.f_90816_, this);
|
||||
f_90811_.add(p_90828_);
|
||||
@@ -96,7 +_,7 @@
|
||||
}
|
||||
|
||||
public boolean m_90857_() {
|
||||
@@ -154,7 +126,7 @@
|
||||
+ if (this.keyModifier.matches(keyCode))
|
||||
+ this.keyModifier = net.minecraftforge.client.settings.KeyModifier.NONE;
|
||||
+ f_90809_.put(description, this);
|
||||
+ f_90810_.addKey(keyCode, this);
|
||||
+ f_90810_.put(keyCode, this);
|
||||
+ f_90811_.add(category);
|
||||
+ }
|
||||
+
|
||||
@@ -188,9 +160,9 @@
|
||||
+ this.f_90816_ = keyCode;
|
||||
+ if (keyModifier.matches(keyCode))
|
||||
+ keyModifier = net.minecraftforge.client.settings.KeyModifier.NONE;
|
||||
+ f_90810_.removeKey(this);
|
||||
+ f_90810_.remove(this);
|
||||
+ this.keyModifier = keyModifier;
|
||||
+ f_90810_.addKey(keyCode, this);
|
||||
+ f_90810_.put(keyCode, this);
|
||||
+ }
|
||||
+ /****************** Forge End *****************************/
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/KeyboardHandler.java
|
||||
+++ b/net/minecraft/client/KeyboardHandler.java
|
||||
@@ -300,7 +_,9 @@
|
||||
@@ -298,7 +_,9 @@
|
||||
}
|
||||
|
||||
Screen screen = this.f_90867_.f_91080_;
|
||||
@@ -11,7 +11,7 @@
|
||||
if (this.f_90867_.f_91066_.f_92105_.m_90832_(p_90895_, p_90896_)) {
|
||||
this.f_90867_.m_91268_().m_85438_();
|
||||
this.f_90867_.f_91066_.m_231829_().m_231514_(this.f_90867_.m_91268_().m_85440_());
|
||||
@@ -318,6 +_,8 @@
|
||||
@@ -316,6 +_,8 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -19,10 +19,10 @@
|
||||
+ ((KeyBindsScreen)this.f_90867_.f_91080_).f_193975_ = null; //Forge: Unset pure modifiers.
|
||||
}
|
||||
|
||||
if (NarratorChatListener.f_93311_.m_93316_()) {
|
||||
@@ -340,11 +_,15 @@
|
||||
if (this.f_90867_.m_240477_().m_93316_()) {
|
||||
@@ -338,11 +_,15 @@
|
||||
Screen.m_96579_(() -> {
|
||||
if (p_90897_ != 1 && (p_90897_ != 2 || !this.f_90868_)) {
|
||||
if (p_90897_ != 1 && p_90897_ != 2) {
|
||||
if (p_90897_ == 0) {
|
||||
- aboolean[0] = screen.m_7920_(p_90895_, p_90896_, p_90898_);
|
||||
+ aboolean[0] = net.minecraftforge.client.ForgeHooksClient.onScreenKeyReleasedPre(screen, p_90895_, p_90896_, p_90898_);
|
||||
@@ -38,12 +38,12 @@
|
||||
}
|
||||
|
||||
}, "keyPressed event handler", screen.getClass().getCanonicalName());
|
||||
@@ -397,22 +_,26 @@
|
||||
@@ -395,22 +_,26 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
+ net.minecraftforge.client.ForgeHooksClient.fireKeyInput(p_90895_, p_90896_, p_90897_, p_90898_);
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onKeyInput(p_90895_, p_90896_, p_90897_, p_90898_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/Minecraft.java
|
||||
+++ b/net/minecraft/client/Minecraft.java
|
||||
@@ -236,7 +_,7 @@
|
||||
@@ -245,7 +_,7 @@
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@@ -9,16 +9,7 @@
|
||||
static Minecraft f_90981_;
|
||||
private static final Logger f_90982_ = LogUtils.getLogger();
|
||||
public static final boolean f_91002_ = Util.m_137581_() == Util.OS.OSX;
|
||||
@@ -385,7 +_,7 @@
|
||||
this.f_91029_ = p_91084_.f_101908_.f_101928_;
|
||||
this.f_90986_ = p_91084_.f_101905_.f_101944_;
|
||||
this.f_91037_ = new ClientPackSource(new File(this.f_91069_, "server-resource-packs"), p_91084_.f_101907_.m_101925_());
|
||||
- this.f_91038_ = new PackRepository(Minecraft::m_167933_, this.f_91037_, new FolderRepositorySource(this.f_90985_, PackSource.f_10527_));
|
||||
+ this.f_91038_ = new PackRepository(Minecraft::createClientPackAdapter, this.f_91037_, new FolderRepositorySource(this.f_90985_, PackSource.f_10527_));
|
||||
this.f_91030_ = p_91084_.f_101905_.f_101945_;
|
||||
this.f_231338_ = new YggdrasilAuthenticationService(this.f_91030_);
|
||||
this.f_91048_ = this.f_231338_.createMinecraftSessionService();
|
||||
@@ -393,7 +_,6 @@
|
||||
@@ -410,7 +_,6 @@
|
||||
this.f_231339_ = SignatureValidator.m_216358_(this.f_231338_.getServicesKey());
|
||||
this.f_90998_ = p_91084_.f_101905_.f_101942_;
|
||||
f_90982_.info("Setting user: {}", (Object)this.f_90998_.m_92546_());
|
||||
@@ -26,49 +17,50 @@
|
||||
this.f_91033_ = p_91084_.f_101908_.f_101926_;
|
||||
this.f_91034_ = !p_91084_.f_101908_.f_101929_;
|
||||
this.f_91035_ = !p_91084_.f_101908_.f_101930_;
|
||||
@@ -426,6 +_,7 @@
|
||||
}
|
||||
|
||||
Util.f_137440_ = RenderSystem.m_69576_();
|
||||
+ if (net.minecraftforge.common.ForgeConfig.CLIENT.forceSystemNanoTime.get()) Util.f_137440_ = System::nanoTime;
|
||||
this.f_90989_ = new VirtualScreen(this);
|
||||
this.f_90990_ = this.f_90989_.m_110872_(displaydata, this.f_91066_.f_92123_, this.m_91270_());
|
||||
this.m_7440_(true);
|
||||
@@ -445,7 +_,6 @@
|
||||
@@ -459,7 +_,7 @@
|
||||
|
||||
this.f_90990_.m_85380_(this.f_91066_.m_232035_().m_231551_());
|
||||
this.f_91067_ = new MouseHandler(this);
|
||||
- this.f_91067_.m_91524_(this.f_90990_.m_85439_());
|
||||
+ // FORGE: Move mouse handler setup further below
|
||||
this.f_91068_ = new KeyboardHandler(this);
|
||||
this.f_91068_.m_90887_(this.f_90990_.m_85439_());
|
||||
RenderSystem.m_69580_(this.f_91066_.f_92035_, false);
|
||||
@@ -453,6 +_,7 @@
|
||||
@@ -467,6 +_,7 @@
|
||||
this.f_91042_.m_83931_(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
this.f_91042_.m_83954_(f_91002_);
|
||||
this.f_91036_ = new ReloadableResourceManager(PackType.CLIENT_RESOURCES);
|
||||
+ net.minecraftforge.client.loading.ClientModLoader.begin(this, this.f_91038_, this.f_91036_, this.f_91037_);
|
||||
+ net.minecraftforge.client.loading.ClientModLoader.begin(this, this.f_91038_, this.f_91036_);
|
||||
this.f_91038_.m_10506_();
|
||||
this.f_91066_.m_92145_(this.f_91038_);
|
||||
this.f_91039_ = new LanguageManager(this.f_91066_.f_92075_);
|
||||
@@ -500,6 +_,7 @@
|
||||
this.m_91271_();
|
||||
@@ -511,10 +_,13 @@
|
||||
this.f_91063_ = new GameRenderer(this, this.f_90994_.m_234586_(), this.f_91036_, this.f_90993_);
|
||||
this.f_91036_.m_7217_(this.f_91063_.m_247116_());
|
||||
this.f_91060_ = new LevelRenderer(this, this.f_90994_, this.f_167845_, this.f_90993_);
|
||||
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.RenderLevelStageEvent.RegisterStageEvent());
|
||||
this.f_91036_.m_7217_(this.f_91060_);
|
||||
- this.m_91271_();
|
||||
+ // Forge: We delay this to allow registration of modded creative mode tabs
|
||||
+ // this.createSearchTrees();
|
||||
this.f_91036_.m_7217_(this.f_90997_);
|
||||
this.f_91061_ = new ParticleEngine(this.f_91073_, this.f_90987_);
|
||||
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.ParticleFactoryRegisterEvent());
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onRegisterParticleProviders(f_91061_);
|
||||
this.f_91036_.m_7217_(this.f_91061_);
|
||||
this.f_91053_ = new PaintingTextureManager(this.f_90987_);
|
||||
this.f_91036_.m_7217_(this.f_91053_);
|
||||
@@ -508,7 +_,8 @@
|
||||
@@ -523,7 +_,9 @@
|
||||
this.f_91047_ = new GpuWarnlistManager();
|
||||
this.f_91036_.m_7217_(this.f_91047_);
|
||||
this.f_91036_.m_7217_(this.f_205120_);
|
||||
- this.f_91065_ = new Gui(this, this.f_90995_);
|
||||
+ this.f_91065_ = new net.minecraftforge.client.gui.ForgeIngameGui(this);
|
||||
+ this.f_91067_.m_91524_(this.f_90990_.m_85439_()); //Forge: Moved below ingameGUI setting to prevent NPEs in handeler.
|
||||
+ this.f_91065_ = new net.minecraftforge.client.gui.overlay.ForgeGui(this);
|
||||
+ // FORGE: Moved mouse handler setup below ingame gui creation to prevent NPEs in mouse handler.
|
||||
+ this.f_91067_.m_91524_(this.f_90990_.m_85439_());
|
||||
this.f_91064_ = new DebugRenderer(this);
|
||||
this.f_238717_ = new RealmsDataFetcher(RealmsClient.m_239151_(this));
|
||||
RenderSystem.m_69900_(this::m_91113_);
|
||||
if (this.f_91042_.f_83915_ == this.f_90990_.m_85441_() && this.f_91042_.f_83916_ == this.f_90990_.m_85442_()) {
|
||||
@@ -526,6 +_,11 @@
|
||||
@@ -542,6 +_,21 @@
|
||||
TinyFileDialogs.tinyfd_messageBox("Minecraft", stringbuilder.toString(), "ok", "error", false);
|
||||
}
|
||||
|
||||
@@ -76,33 +68,62 @@
|
||||
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.RegisterClientReloadListenersEvent(this.f_91036_));
|
||||
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.EntityRenderersEvent.RegisterLayerDefinitions());
|
||||
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.EntityRenderersEvent.RegisterRenderers());
|
||||
+ net.minecraftforge.client.textures.TextureAtlasSpriteLoaderManager.init();
|
||||
+ net.minecraftforge.client.gui.ClientTooltipComponentManager.init();
|
||||
+ net.minecraftforge.client.EntitySpectatorShaderManager.init();
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onRegisterKeyMappings(f_91066_);
|
||||
+ net.minecraftforge.client.RecipeBookManager.init();
|
||||
+ net.minecraftforge.client.gui.overlay.GuiOverlayManager.init();
|
||||
+ net.minecraftforge.client.DimensionSpecialEffectsManager.init();
|
||||
+ net.minecraftforge.client.NamedRenderTypeManager.init();
|
||||
+ net.minecraftforge.client.ColorResolverManager.init();
|
||||
+ net.minecraftforge.client.ItemDecoratorHandler.init();
|
||||
+
|
||||
this.f_90990_.m_85409_(this.f_91066_.m_231817_().m_231551_());
|
||||
this.f_90990_.m_85424_(this.f_91066_.m_232123_().m_231551_());
|
||||
this.f_90990_.m_85426_();
|
||||
@@ -543,13 +_,16 @@
|
||||
@@ -565,24 +_,24 @@
|
||||
}
|
||||
|
||||
this.f_167847_.m_168556_();
|
||||
+ if (net.minecraftforge.client.loading.ClientModLoader.completeModLoading()) return; // Do not overwrite the error screen
|
||||
+ // FORGE: Move opening initial screen to after startup and events are enabled.
|
||||
+ // Also Fixes MC-145102
|
||||
+ if (s != null) {
|
||||
+ ConnectScreen.m_169267_(new TitleScreen(), this, new ServerAddress(s, i), (ServerData)null);
|
||||
+ ServerAddress serveraddress = new ServerAddress(s, i);
|
||||
+ ConnectScreen.m_169267_(new TitleScreen(), this, serveraddress, new ServerData(I18n.m_118938_("selectServer.defaultName"), serveraddress.toString(), false));
|
||||
+ } else if (this.m_239929_()) {
|
||||
+ this.m_91152_(BanNoticeScreen.m_239967_((p_238185_) -> {
|
||||
+ if (p_238185_) {
|
||||
+ Util.m_137581_().m_137646_("https://aka.ms/mcjavamoderation");
|
||||
+ }
|
||||
+
|
||||
+ this.m_91152_(new TitleScreen(true));
|
||||
+ }, this.m_239210_()));
|
||||
+ } else {
|
||||
+ this.m_91152_(new TitleScreen(true));
|
||||
+ this.m_91152_(new TitleScreen(true));
|
||||
+ }
|
||||
});
|
||||
}, false));
|
||||
- if (s != null) {
|
||||
- ConnectScreen.m_169267_(new TitleScreen(), this, new ServerAddress(s, i), (ServerData)null);
|
||||
- ServerAddress serveraddress = new ServerAddress(s, i);
|
||||
- reloadinstance.m_7237_().thenRunAsync(() -> {
|
||||
- ConnectScreen.m_169267_(new TitleScreen(), this, serveraddress, new ServerData(I18n.m_118938_("selectServer.defaultName"), serveraddress.toString(), false));
|
||||
- }, this);
|
||||
- } else if (this.m_239929_()) {
|
||||
- this.m_91152_(BanNoticeScreen.m_239967_((p_238185_) -> {
|
||||
- if (p_238185_) {
|
||||
- Util.m_137581_().m_137646_("https://aka.ms/mcjavamoderation");
|
||||
- }
|
||||
-
|
||||
- this.m_91152_(new TitleScreen(true));
|
||||
- }, this.m_239210_()));
|
||||
- } else {
|
||||
- this.m_91152_(new TitleScreen(true));
|
||||
- }
|
||||
|
||||
}
|
||||
|
||||
@@ -592,6 +_,8 @@
|
||||
@@ -634,6 +_,8 @@
|
||||
|
||||
private UserApiService m_193585_(YggdrasilAuthenticationService p_193586_, GameConfig p_193587_) {
|
||||
try {
|
||||
@@ -111,7 +132,7 @@
|
||||
return p_193586_.createUserApiService(p_193587_.f_101905_.f_101942_.m_92547_());
|
||||
} catch (AuthenticationException authenticationexception) {
|
||||
f_90982_.error("Failed to verify authentication", (Throwable)authenticationexception);
|
||||
@@ -604,7 +_,7 @@
|
||||
@@ -646,7 +_,7 @@
|
||||
}
|
||||
|
||||
private void m_91239_(Throwable p_91240_) {
|
||||
@@ -120,7 +141,45 @@
|
||||
this.m_91241_(p_91240_, (Component)null);
|
||||
} else {
|
||||
Util.m_137559_(p_91240_);
|
||||
@@ -762,13 +_,13 @@
|
||||
@@ -723,7 +_,10 @@
|
||||
}
|
||||
|
||||
public void m_91271_() {
|
||||
- this.f_90997_.m_235232_(SearchRegistry.f_119941_, (p_231451_) -> {
|
||||
+ var nameSearchKeys = net.minecraftforge.client.CreativeModeTabSearchRegistry.getNameSearchKeys();
|
||||
+ var tagSearchKeys = net.minecraftforge.client.CreativeModeTabSearchRegistry.getTagSearchKeys();
|
||||
+ for (var nameSearchKey : nameSearchKeys.values())
|
||||
+ this.f_90997_.m_235232_(nameSearchKey, (p_231451_) -> {
|
||||
return new FullTextSearchTree<>((p_210797_) -> {
|
||||
return p_210797_.m_41651_((Player)null, TooltipFlag.Default.f_256752_.m_257777_()).stream().map((p_210807_) -> {
|
||||
return ChatFormatting.m_126649_(p_210807_.getString()).trim();
|
||||
@@ -734,7 +_,8 @@
|
||||
return Stream.of(BuiltInRegistries.f_257033_.m_7981_(p_91317_.m_41720_()));
|
||||
}, p_231451_);
|
||||
});
|
||||
- this.f_90997_.m_235232_(SearchRegistry.f_119942_, (p_231430_) -> {
|
||||
+ for (var tagSearchKey : tagSearchKeys.values())
|
||||
+ this.f_90997_.m_235232_(tagSearchKey, (p_231430_) -> {
|
||||
return new IdSearchTree<>((p_231353_) -> {
|
||||
return p_231353_.m_204131_().map(TagKey::f_203868_);
|
||||
}, p_231430_);
|
||||
@@ -754,9 +_,12 @@
|
||||
});
|
||||
}, p_231389_);
|
||||
});
|
||||
- CreativeModeTabs.m_258007_().m_257882_((p_255439_) -> {
|
||||
- this.m_231374_(SearchRegistry.f_119941_, p_255439_);
|
||||
- this.m_231374_(SearchRegistry.f_119942_, p_255439_);
|
||||
+ nameSearchKeys.forEach((tab, nameSearchKey) -> {
|
||||
+ var tagSearchKey = tagSearchKeys.get(tab);
|
||||
+ tab.m_257882_(contents -> {
|
||||
+ this.m_231374_(nameSearchKey, contents);
|
||||
+ this.m_231374_(tagSearchKey, contents);
|
||||
+ });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -808,13 +_,13 @@
|
||||
Bootstrap.m_135875_(p_91333_.m_127526_());
|
||||
if (p_91333_.m_127527_() != null) {
|
||||
Bootstrap.m_135875_("#@!@# Game crashed! Crash report saved to: #@!@# " + p_91333_.m_127527_());
|
||||
@@ -137,7 +196,7 @@
|
||||
}
|
||||
|
||||
}
|
||||
@@ -892,10 +_,6 @@
|
||||
@@ -932,10 +_,6 @@
|
||||
f_90982_.error("setScreen called from non-game thread");
|
||||
}
|
||||
|
||||
@@ -148,37 +207,42 @@
|
||||
if (p_91153_ == null && this.f_91073_ == null) {
|
||||
p_91153_ = new TitleScreen();
|
||||
} else if (p_91153_ == null && this.f_91074_.m_21224_()) {
|
||||
@@ -906,6 +_,15 @@
|
||||
@@ -946,6 +_,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ net.minecraftforge.client.ForgeHooksClient.clearGuiLayers(this);
|
||||
+ Screen old = this.f_91080_;
|
||||
+ net.minecraftforge.client.event.ScreenOpenEvent event = new net.minecraftforge.client.event.ScreenOpenEvent(p_91153_);
|
||||
+ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) return;
|
||||
+ if (p_91153_ != null) {
|
||||
+ var event = new net.minecraftforge.client.event.ScreenEvent.Opening(old, p_91153_);
|
||||
+ if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) return;
|
||||
+ p_91153_ = event.getNewScreen();
|
||||
+ }
|
||||
+
|
||||
+ p_91153_ = event.getScreen();
|
||||
+ if (old != null && p_91153_ != old)
|
||||
+ if (old != null && p_91153_ != old) {
|
||||
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.client.event.ScreenEvent.Closing(old));
|
||||
+ old.m_7861_();
|
||||
+ }
|
||||
+
|
||||
this.f_91080_ = p_91153_;
|
||||
BufferUploader.m_166835_();
|
||||
if (p_91153_ != null) {
|
||||
@@ -1049,11 +_,13 @@
|
||||
@@ -1091,11 +_,14 @@
|
||||
RenderSystem.m_69481_();
|
||||
this.f_91026_.m_7238_();
|
||||
if (!this.f_91079_) {
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onRenderTickStart(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_);
|
||||
+ this.realPartialTick = this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_; // Cache this since pause is volatile
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onRenderTickStart(this.realPartialTick);
|
||||
this.f_91026_.m_6182_("gameRenderer");
|
||||
this.f_91063_.m_109093_(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_, i, p_91384_);
|
||||
this.f_91026_.m_6182_("toasts");
|
||||
this.f_91003_.m_94920_(new PoseStack());
|
||||
this.f_91026_.m_7238_();
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onRenderTickEnd(this.f_91012_ ? this.f_91013_ : this.f_90991_.f_92518_);
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onRenderTickEnd(this.realPartialTick);
|
||||
}
|
||||
|
||||
if (this.f_91056_ != null) {
|
||||
@@ -1180,10 +_,12 @@
|
||||
@@ -1223,10 +_,12 @@
|
||||
this.f_90990_.m_85378_((double)i);
|
||||
if (this.f_91080_ != null) {
|
||||
this.f_91080_.m_6574_(this, this.f_90990_.m_85445_(), this.f_90990_.m_85446_());
|
||||
@@ -191,7 +255,7 @@
|
||||
this.f_91063_.m_109097_(this.f_90990_.m_85441_(), this.f_90990_.m_85442_());
|
||||
this.f_91067_.m_91599_();
|
||||
}
|
||||
@@ -1461,6 +_,7 @@
|
||||
@@ -1499,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void m_91395_() {
|
||||
@@ -199,13 +263,13 @@
|
||||
this.f_91019_ = false;
|
||||
}
|
||||
|
||||
@@ -1490,10 +_,18 @@
|
||||
@@ -1528,10 +_,18 @@
|
||||
if (p_91387_ && this.f_91077_ != null && this.f_91077_.m_6662_() == HitResult.Type.BLOCK) {
|
||||
BlockHitResult blockhitresult = (BlockHitResult)this.f_91077_;
|
||||
BlockPos blockpos = blockhitresult.m_82425_();
|
||||
- if (!this.f_91073_.m_8055_(blockpos).m_60795_()) {
|
||||
+ if (!this.f_91073_.m_46859_(blockpos)) {
|
||||
+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND);
|
||||
+ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND);
|
||||
+ if (inputEvent.isCanceled()) {
|
||||
+ if (inputEvent.shouldSwingHand()) {
|
||||
+ this.f_91061_.addBlockHitEffects(blockpos, blockhitresult);
|
||||
@@ -221,77 +285,78 @@
|
||||
this.f_91074_.m_6674_(InteractionHand.MAIN_HAND);
|
||||
}
|
||||
}
|
||||
@@ -1518,14 +_,20 @@
|
||||
return false;
|
||||
} else {
|
||||
boolean flag = false;
|
||||
- switch (this.f_91077_.m_6662_()) {
|
||||
+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND);
|
||||
+ HitResult.Type hitType = this.f_91077_.m_6662_();
|
||||
+ if(this.f_91077_ instanceof EntityHitResult entityHit) { // Forge: Perform attack range checks here, instead of in GameRenderer#pick, so extended-reach interactions work.
|
||||
+ if(!f_91074_.canHit(entityHit.m_82443_(), 0)) hitType = HitResult.Type.MISS; // No padding in client code.
|
||||
+ }
|
||||
+ if (!inputEvent.isCanceled())
|
||||
+ switch(hitType) {
|
||||
case ENTITY:
|
||||
this.f_91072_.m_105223_(this.f_91074_, ((EntityHitResult)this.f_91077_).m_82443_());
|
||||
break;
|
||||
case BLOCK:
|
||||
BlockHitResult blockhitresult = (BlockHitResult)this.f_91077_;
|
||||
BlockPos blockpos = blockhitresult.m_82425_();
|
||||
- if (!this.f_91073_.m_8055_(blockpos).m_60795_()) {
|
||||
+ if (!this.f_91073_.m_46859_(blockpos)) {
|
||||
this.f_91072_.m_105269_(blockpos, blockhitresult.m_82434_());
|
||||
if (this.f_91073_.m_8055_(blockpos).m_60795_()) {
|
||||
flag = true;
|
||||
@@ -1538,8 +_,10 @@
|
||||
}
|
||||
@@ -1560,14 +_,20 @@
|
||||
return false;
|
||||
} else {
|
||||
boolean flag = false;
|
||||
- switch (this.f_91077_.m_6662_()) {
|
||||
+ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(0, this.f_91066_.f_92096_, InteractionHand.MAIN_HAND);
|
||||
+ HitResult.Type hitType = this.f_91077_.m_6662_();
|
||||
+ if (this.f_91077_ instanceof EntityHitResult entityHit) { // Forge: Perform attack range checks here, instead of in GameRenderer#pick, so extended-reach interactions work.
|
||||
+ if (!f_91074_.canHit(entityHit.m_82443_(), 0)) hitType = HitResult.Type.MISS; // No padding in client code.
|
||||
+ }
|
||||
+ if (!inputEvent.isCanceled())
|
||||
+ switch(hitType) {
|
||||
case ENTITY:
|
||||
this.f_91072_.m_105223_(this.f_91074_, ((EntityHitResult)this.f_91077_).m_82443_());
|
||||
break;
|
||||
case BLOCK:
|
||||
BlockHitResult blockhitresult = (BlockHitResult)this.f_91077_;
|
||||
BlockPos blockpos = blockhitresult.m_82425_();
|
||||
- if (!this.f_91073_.m_8055_(blockpos).m_60795_()) {
|
||||
+ if (!this.f_91073_.m_46859_(blockpos)) {
|
||||
this.f_91072_.m_105269_(blockpos, blockhitresult.m_82434_());
|
||||
if (this.f_91073_.m_8055_(blockpos).m_60795_()) {
|
||||
flag = true;
|
||||
@@ -1580,8 +_,10 @@
|
||||
}
|
||||
|
||||
this.f_91074_.m_36334_();
|
||||
+ net.minecraftforge.common.ForgeHooks.onEmptyLeftClick(this.f_91074_);
|
||||
this.f_91074_.m_36334_();
|
||||
+ net.minecraftforge.common.ForgeHooks.onEmptyLeftClick(this.f_91074_);
|
||||
}
|
||||
|
||||
+ if (inputEvent.shouldSwingHand())
|
||||
this.f_91074_.m_6674_(InteractionHand.MAIN_HAND);
|
||||
return flag;
|
||||
}
|
||||
|
||||
+ if (inputEvent.shouldSwingHand())
|
||||
this.f_91074_.m_6674_(InteractionHand.MAIN_HAND);
|
||||
return flag;
|
||||
}
|
||||
@@ -1554,6 +_,11 @@
|
||||
@@ -1597,6 +_,11 @@
|
||||
}
|
||||
|
||||
for(InteractionHand interactionhand : InteractionHand.values()) {
|
||||
+ net.minecraftforge.client.event.InputEvent.ClickInputEvent inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(1, this.f_91066_.f_92095_, interactionhand);
|
||||
+ var inputEvent = net.minecraftforge.client.ForgeHooksClient.onClickInput(1, this.f_91066_.f_92095_, interactionhand);
|
||||
+ if (inputEvent.isCanceled()) {
|
||||
+ if (inputEvent.shouldSwingHand()) this.f_91074_.m_6674_(interactionhand);
|
||||
+ return;
|
||||
+ }
|
||||
ItemStack itemstack = this.f_91074_.m_21120_(interactionhand);
|
||||
if (this.f_91077_ != null) {
|
||||
switch (this.f_91077_.m_6662_()) {
|
||||
@@ -1564,6 +_,7 @@
|
||||
if (!itemstack.m_246617_(this.f_91073_.m_246046_())) {
|
||||
return;
|
||||
@@ -1611,13 +_,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
+ if(!this.f_91074_.canInteractWith(entityhitresult.m_82443_(), 0)) return; //Forge: Entity may be traced via attack range, but the player may not have sufficient reach. No padding in client code.
|
||||
+ if(!this.f_91074_.canInteractWith(entityhitresult.m_82443_(), 0)) break; //Forge: Entity may be traced via attack range, but the player may not have sufficient reach. No padding in client code.
|
||||
InteractionResult interactionresult = this.f_91072_.m_105230_(this.f_91074_, entity, entityhitresult, interactionhand);
|
||||
if (!interactionresult.m_19077_()) {
|
||||
interactionresult = this.f_91072_.m_105226_(this.f_91074_, entity, interactionhand);
|
||||
@@ -1571,6 +_,7 @@
|
||||
}
|
||||
|
||||
if (interactionresult.m_19077_()) {
|
||||
if (interactionresult.m_19080_()) {
|
||||
+ if (inputEvent.shouldSwingHand())
|
||||
- if (interactionresult.m_19080_()) {
|
||||
+ if (interactionresult.m_19080_() && inputEvent.shouldSwingHand()) {
|
||||
this.f_91074_.m_6674_(interactionhand);
|
||||
}
|
||||
|
||||
@@ -1583,6 +_,7 @@
|
||||
@@ -1629,7 +_,7 @@
|
||||
int i = itemstack.m_41613_();
|
||||
InteractionResult interactionresult1 = this.f_91072_.m_233732_(this.f_91074_, interactionhand, blockhitresult);
|
||||
if (interactionresult1.m_19077_()) {
|
||||
if (interactionresult1.m_19080_()) {
|
||||
+ if (inputEvent.shouldSwingHand())
|
||||
- if (interactionresult1.m_19080_()) {
|
||||
+ if (interactionresult1.m_19080_() && inputEvent.shouldSwingHand()) {
|
||||
this.f_91074_.m_6674_(interactionhand);
|
||||
if (!itemstack.m_41619_() && (itemstack.m_41613_() != i || this.f_91072_.m_105290_())) {
|
||||
this.f_91063_.f_109055_.m_109320_(interactionhand);
|
||||
@@ -1598,6 +_,9 @@
|
||||
@@ -1645,6 +_,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,16 +366,16 @@
|
||||
if (!itemstack.m_41619_()) {
|
||||
InteractionResult interactionresult2 = this.f_91072_.m_233721_(this.f_91074_, interactionhand);
|
||||
if (interactionresult2.m_19077_()) {
|
||||
@@ -1624,6 +_,8 @@
|
||||
@@ -1671,6 +_,8 @@
|
||||
--this.f_91011_;
|
||||
}
|
||||
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onPreClientTick();
|
||||
+
|
||||
this.f_91026_.m_6180_("gui");
|
||||
this.f_240378_.m_240688_();
|
||||
this.f_91065_.m_193832_(this.f_91012_);
|
||||
this.f_91026_.m_7238_();
|
||||
@@ -1752,6 +_,8 @@
|
||||
@@ -1800,6 +_,8 @@
|
||||
this.f_91026_.m_6182_("keyboard");
|
||||
this.f_91068_.m_90931_();
|
||||
this.f_91026_.m_7238_();
|
||||
@@ -319,137 +384,65 @@
|
||||
}
|
||||
|
||||
private boolean m_91278_() {
|
||||
@@ -1894,8 +_,8 @@
|
||||
SkullBlockEntity.m_222885_(services, this);
|
||||
GameProfileCache.m_11004_(false);
|
||||
this.f_91007_ = MinecraftServer.m_129872_((p_231361_) -> {
|
||||
- return new IntegratedServer(p_231361_, this, p_231382_, p_231383_, p_231384_, services, (p_231447_) -> {
|
||||
- StoringChunkProgressListener storingchunkprogresslistener = new StoringChunkProgressListener(p_231447_ + 0);
|
||||
+ return new IntegratedServer(p_231361_, this, p_231382_, p_231383_, p_231384_, services, (p_210795_) -> { //TODO-PATCHING: Handle the registry freeze delay again.
|
||||
+ StoringChunkProgressListener storingchunkprogresslistener = new StoringChunkProgressListener(p_210795_ + 0);
|
||||
this.f_90999_.set(storingchunkprogresslistener);
|
||||
return ProcessorChunkProgressListener.m_143583_(storingchunkprogresslistener, this.f_91023_::add);
|
||||
});
|
||||
@@ -1945,6 +_,7 @@
|
||||
@@ -1996,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void m_91156_(ClientLevel p_91157_) {
|
||||
+ if (f_91073_ != null) net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Unload(f_91073_));
|
||||
+ if (f_91073_ != null) net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.level.LevelEvent.Unload(f_91073_));
|
||||
ProgressScreen progressscreen = new ProgressScreen(true);
|
||||
progressscreen.m_6309_(Component.m_237115_("connect.joining"));
|
||||
this.m_91362_(progressscreen);
|
||||
@@ -1978,10 +_,12 @@
|
||||
@@ -2029,10 +_,12 @@
|
||||
IntegratedServer integratedserver = this.f_91007_;
|
||||
this.f_91007_ = null;
|
||||
this.f_91063_.m_109150_();
|
||||
+ net.minecraftforge.client.ForgeHooksClient.firePlayerLogout(this.f_91072_, this.f_91074_);
|
||||
this.f_91072_ = null;
|
||||
NarratorChatListener.f_93311_.m_93328_();
|
||||
this.f_240365_.m_93328_();
|
||||
this.m_91362_(p_91321_);
|
||||
if (this.f_91073_ != null) {
|
||||
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Unload(f_91073_));
|
||||
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.level.LevelEvent.Unload(f_91073_));
|
||||
if (integratedserver != null) {
|
||||
this.f_91026_.m_6180_("waitForServer");
|
||||
|
||||
@@ -1996,6 +_,7 @@
|
||||
@@ -2046,6 +_,7 @@
|
||||
this.f_243981_.m_246151_();
|
||||
this.f_91065_.m_93089_();
|
||||
this.f_91008_ = null;
|
||||
this.f_91010_ = false;
|
||||
+ net.minecraftforge.client.ForgeHooksClient.handleClientLevelClosing(f_91073_);
|
||||
this.f_91004_.m_90740_();
|
||||
}
|
||||
|
||||
@@ -2082,66 +_,9 @@
|
||||
@@ -2153,6 +_,7 @@
|
||||
|
||||
private void m_91280_() {
|
||||
if (this.f_91077_ != null && this.f_91077_.m_6662_() != HitResult.Type.MISS) {
|
||||
- boolean flag = this.f_91074_.m_150110_().f_35937_;
|
||||
- BlockEntity blockentity = null;
|
||||
- HitResult.Type hitresult$type = this.f_91077_.m_6662_();
|
||||
- ItemStack itemstack;
|
||||
- if (hitresult$type == HitResult.Type.BLOCK) {
|
||||
- BlockPos blockpos = ((BlockHitResult)this.f_91077_).m_82425_();
|
||||
- BlockState blockstate = this.f_91073_.m_8055_(blockpos);
|
||||
- if (blockstate.m_60795_()) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- Block block = blockstate.m_60734_();
|
||||
+ if (net.minecraftforge.client.ForgeHooksClient.onClickInput(2, this.f_91066_.f_92097_, InteractionHand.MAIN_HAND).isCanceled()) return;
|
||||
boolean flag = this.f_91074_.m_150110_().f_35937_;
|
||||
BlockEntity blockentity = null;
|
||||
HitResult.Type hitresult$type = this.f_91077_.m_6662_();
|
||||
@@ -2165,10 +_,7 @@
|
||||
}
|
||||
|
||||
Block block = blockstate.m_60734_();
|
||||
- itemstack = block.m_7397_(this.f_91073_, blockpos, blockstate);
|
||||
- if (itemstack.m_41619_()) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (flag && Screen.m_96637_() && blockstate.m_155947_()) {
|
||||
- blockentity = this.f_91073_.m_7702_(blockpos);
|
||||
- }
|
||||
- } else {
|
||||
- if (hitresult$type != HitResult.Type.ENTITY || !flag) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- Entity entity = ((EntityHitResult)this.f_91077_).m_82443_();
|
||||
+ itemstack = blockstate.getCloneItemStack(this.f_91077_, this.f_91073_, blockpos, this.f_91074_);
|
||||
|
||||
if (flag && Screen.m_96637_() && blockstate.m_155947_()) {
|
||||
blockentity = this.f_91073_.m_7702_(blockpos);
|
||||
@@ -2179,7 +_,7 @@
|
||||
}
|
||||
|
||||
Entity entity = ((EntityHitResult)this.f_91077_).m_82443_();
|
||||
- itemstack = entity.m_142340_();
|
||||
- if (itemstack == null) {
|
||||
- return;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (itemstack.m_41619_()) {
|
||||
- String s = "";
|
||||
- if (hitresult$type == HitResult.Type.BLOCK) {
|
||||
- s = Registry.f_122824_.m_7981_(this.f_91073_.m_8055_(((BlockHitResult)this.f_91077_).m_82425_()).m_60734_()).toString();
|
||||
- } else if (hitresult$type == HitResult.Type.ENTITY) {
|
||||
- s = Registry.f_122826_.m_7981_(((EntityHitResult)this.f_91077_).m_82443_().m_6095_()).toString();
|
||||
- }
|
||||
-
|
||||
- f_90982_.warn("Picking on: [{}] {} gave null item", hitresult$type, s);
|
||||
- } else {
|
||||
- Inventory inventory = this.f_91074_.m_150109_();
|
||||
- if (blockentity != null) {
|
||||
- this.m_91122_(itemstack, blockentity);
|
||||
- }
|
||||
-
|
||||
- int i = inventory.m_36030_(itemstack);
|
||||
- if (flag) {
|
||||
- inventory.m_36012_(itemstack);
|
||||
- this.f_91072_.m_105241_(this.f_91074_.m_21120_(InteractionHand.MAIN_HAND), 36 + inventory.f_35977_);
|
||||
- } else if (i != -1) {
|
||||
- if (Inventory.m_36045_(i)) {
|
||||
- inventory.f_35977_ = i;
|
||||
- } else {
|
||||
- this.f_91072_.m_105206_(i);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- }
|
||||
+ if (!net.minecraftforge.client.ForgeHooksClient.onClickInput(2, this.f_91066_.f_92097_, InteractionHand.MAIN_HAND).isCanceled())
|
||||
+ net.minecraftforge.common.ForgeHooks.onPickBlock(this.f_91077_, this.f_91074_, this.f_91073_);
|
||||
+ // We delete this code wholly instead of commenting it out, to make sure we detect changes in it between MC versions
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2632,8 +_,8 @@
|
||||
return this.f_90993_;
|
||||
}
|
||||
|
||||
- private static Pack m_167933_(String p_167934_, Component p_167935_, boolean p_167936_, Supplier<PackResources> p_167937_, PackMetadataSection p_167938_, Pack.Position p_167939_, PackSource p_167940_) {
|
||||
- int i = p_167938_.m_10374_();
|
||||
+ private static Pack createClientPackAdapter(String p_167934_, Component p_167935_, boolean p_167936_, Supplier<PackResources> p_167937_, PackMetadataSection p_167938_, Pack.Position p_167939_, PackSource p_167940_, boolean hidden) {
|
||||
+ int i = p_167938_.getPackFormat(PackType.CLIENT_RESOURCES);
|
||||
Supplier<PackResources> supplier = p_167937_;
|
||||
if (i <= 3) {
|
||||
supplier = m_91330_(p_167937_);
|
||||
@@ -2643,7 +_,7 @@
|
||||
supplier = m_91352_(supplier);
|
||||
}
|
||||
|
||||
- return new Pack(p_167934_, p_167935_, p_167936_, supplier, p_167938_, PackType.CLIENT_RESOURCES, p_167939_, p_167940_);
|
||||
+ return new Pack(p_167934_, p_167935_, p_167936_, supplier, p_167938_, PackType.CLIENT_RESOURCES, p_167939_, p_167940_, hidden);
|
||||
}
|
||||
|
||||
private static Supplier<PackResources> m_91330_(Supplier<PackResources> p_91331_) {
|
||||
@@ -2660,6 +_,14 @@
|
||||
+ itemstack = entity.getPickedResult(this.f_91077_);
|
||||
if (itemstack == null) {
|
||||
return;
|
||||
}
|
||||
@@ -2721,6 +_,19 @@
|
||||
|
||||
public void m_91312_(int p_91313_) {
|
||||
this.f_91051_.m_119410_(p_91313_);
|
||||
@@ -461,6 +454,11 @@
|
||||
+
|
||||
+ public SearchRegistry getSearchTreeManager() {
|
||||
+ return this.f_90997_;
|
||||
+ }
|
||||
+
|
||||
+ private float realPartialTick;
|
||||
+ public float getPartialTick() {
|
||||
+ return realPartialTick;
|
||||
}
|
||||
|
||||
public EntityModelSet m_167973_() {
|
||||
@@ -4,7 +4,7 @@
|
||||
this.f_91510_ = -1;
|
||||
}
|
||||
|
||||
+ if (net.minecraftforge.client.ForgeHooksClient.onRawMouseClicked(p_91532_, p_91533_, p_91534_)) return;
|
||||
+ if (net.minecraftforge.client.ForgeHooksClient.onMouseButtonPre(p_91532_, p_91533_, p_91534_)) return;
|
||||
boolean[] aboolean = new boolean[]{false};
|
||||
if (this.f_91503_.m_91265_() == null) {
|
||||
if (this.f_91503_.f_91080_ == null) {
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
}
|
||||
-
|
||||
+ net.minecraftforge.client.ForgeHooksClient.fireMouseInput(p_91532_, p_91533_, p_91534_);
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onMouseButtonPost(p_91532_, p_91533_, p_91534_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 1336 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user