mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 09:05:17 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c974df523e | ||
|
|
d13dd327bd | ||
|
|
216cc50162 | ||
|
|
0ec923d730 | ||
|
|
8418bad66d | ||
|
|
ae3c937073 | ||
|
|
3c3f496015 | ||
|
|
22d0c94c82 | ||
|
|
77785cb181 | ||
|
|
9130c27d05 | ||
|
|
1b26f0c967 | ||
|
|
723799cdb8 | ||
|
|
64caebe63c | ||
|
|
8dffec4dbc | ||
|
|
d6b2bf7ca3 | ||
|
|
e7629d5ae4 | ||
|
|
7187d8d97f | ||
|
|
f20ab8e6ce | ||
|
|
1837d8c36c | ||
|
|
132704e5f2 | ||
|
|
e9ce8a6cc6 | ||
|
|
350bfa51e1 | ||
|
|
ddb5f6c749 | ||
|
|
d00f5c4013 | ||
|
|
f4e8c6b67e | ||
|
|
6c4f5e2865 | ||
|
|
d1071fd0f8 | ||
|
|
064e2fed48 | ||
|
|
f36781652c |
No files matched your search
@@ -0,0 +1,28 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ '1.20.1' ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: MinecraftForge/SharedActions/.github/workflows/gradle.yml@main
|
||||
with:
|
||||
java: 17
|
||||
gradle_setup: './gradlew setup'
|
||||
gradle_tasks: 'build publish'
|
||||
artifact_name: 'forge'
|
||||
secrets:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
PROMOTE_ARTIFACT_WEBHOOK: ${{ secrets.PROMOTE_ARTIFACT_WEBHOOK }}
|
||||
PROMOTE_ARTIFACT_USERNAME: ${{ secrets.PROMOTE_ARTIFACT_USERNAME }}
|
||||
PROMOTE_ARTIFACT_PASSWORD: ${{ secrets.PROMOTE_ARTIFACT_PASSWORD }}
|
||||
MAVEN_USER: ${{ secrets.MAVEN_USER }}
|
||||
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
|
||||
SIGN_KEY_ALIAS: ${{ secrets.SIGN_KEY_ALIAS }}
|
||||
SIGN_KEY_PASSWORD: ${{ secrets.SIGN_KEY_PASSWORD }}
|
||||
SIGN_KEYSTORE_PASSWORD: ${{ secrets.SIGN_KEYSTORE_PASSWORD }}
|
||||
SIGN_KEYSTORE_DATA: ${{ secrets.SIGN_KEYSTORE_DATA }}
|
||||
Vendored
-104
@@ -1,104 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<name>MinecraftForge_Forge Config DSL Script</name>
|
||||
<groupId>MinecraftForge_Forge</groupId>
|
||||
<artifactId>MinecraftForge_Forge_dsl</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jetbrains-all</id>
|
||||
<url>https://download.jetbrains.com/teamcity-repository</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>teamcity-server</id>
|
||||
<url>https://teamcity.minecraftforge.net/app/dsl-plugins-repository</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>JetBrains</id>
|
||||
<url>https://download.jetbrains.com/teamcity-repository</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>${basedir}</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<version>${kotlin.version}</version>
|
||||
|
||||
<configuration/>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>process-test-sources</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>teamcity-configs-maven-plugin</artifactId>
|
||||
<version>${teamcity.dsl.version}</version>
|
||||
<configuration>
|
||||
<format>kotlin</format>
|
||||
<dstDir>target/generated-configs</dstDir>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin</artifactId>
|
||||
<version>${teamcity.dsl.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.teamcity</groupId>
|
||||
<artifactId>configs-dsl-kotlin-plugins</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-script-runtime</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
Vendored
-208
@@ -1,208 +0,0 @@
|
||||
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
|
||||
project hierarchy. The script should contain a single call to the
|
||||
project() function with a Project instance or an init function as
|
||||
an argument.
|
||||
|
||||
VcsRoots, BuildTypes, Templates, and subprojects can be
|
||||
registered inside the project using the vcsRoot(), buildType(),
|
||||
template(), and subProject() methods respectively.
|
||||
|
||||
To debug settings scripts in command-line, run the
|
||||
|
||||
mvnDebug org.jetbrains.teamcity:teamcity-configs-maven-plugin:generate
|
||||
|
||||
command and attach your debugger to the port 8000.
|
||||
|
||||
To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View
|
||||
-> Tool Windows -> Maven Projects), find the generate task node
|
||||
(Plugins -> teamcity-configs -> teamcity-configs:generate), the
|
||||
'Debug' option is available in the context menu for the task.
|
||||
*/
|
||||
|
||||
version = "2021.2"
|
||||
|
||||
project {
|
||||
|
||||
buildType(Build)
|
||||
buildType(BuildSecondaryBranches)
|
||||
buildType(PullRequests)
|
||||
buildType(PullRequestChecks)
|
||||
buildType(PullRequestCompatibility)
|
||||
|
||||
params {
|
||||
text("docker_jdk_version", "21", 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", "8.8", 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.20.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*)
|
||||
+:refs/heads/(develop|release|staging|main|master)
|
||||
+:refs/heads/(1.*)
|
||||
""".trimIndent(), label = "The branch specification of the repository", description = "By default all main branches are build by the configuration. Modify this value to adapt the branches build.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
text("github_repository_name", "MinecraftForge", label = "The github repository name. Used to connect to it in VCS Roots.", description = "This is the repository slug on github. So for example `MinecraftForge` or `MinecraftForge`. It is interpolated into the global VCS Roots.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_ARTIFACT_ID", "forge", label = "Published artifact id", description = "The maven coordinate artifact id that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_FML_ARTIFACT_ID", "fmlonly", label = "Published fmlonly artifact id", description = "The maven coordinate artifact id for fml only that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_FML_ARTIFACT_VERSION", "0.0.0-SNAPSHOT", label = "Published fmlonly artifact version", description = "The version for fml only that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
text("env.PUBLISHED_JAVA_GROUP", "net.minecraftforge", label = "Published group", description = "The maven coordinate group that has been published by this build. Can not be empty.", allowEmpty = false)
|
||||
//These are references and not actually keys
|
||||
password("env.CROWDIN_KEY", "credentialsJSON:a3102dbe-805d-4177-9f54-3d2c2eb08fd5", display = ParameterDisplay.HIDDEN)
|
||||
password("env.KEYSTORE_URL", "credentialsJSON:a7ae1c82-8058-4061-8d12-7f6bc2618d2e", display = ParameterDisplay.HIDDEN)
|
||||
password("env.KEYSTORE_PASSWORD", "credentialsJSON:d7b964e3-a1fd-47a8-b892-6f601fe47479", display = ParameterDisplay.HIDDEN)
|
||||
text("additional_publishing_gradle_parameters", "-PcrowdinKey=%env.CROWDIN_KEY% -PkeystoreKeyPass=%env.KEYSTORE_PASSWORD% -PkeystoreStorePass=%env.KEYSTORE_PASSWORD% -Pkeystore=%env.KEYSTORE_URL%", label = "Additional gradle parameters for publish", description = "Contains the additional gradle parameters used during publishing.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
|
||||
checkbox("should_execute_build", "false", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
checkbox("should_execute_test", "false", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
}
|
||||
|
||||
features {
|
||||
githubIssues {
|
||||
id = "MinecraftForge_MinecraftForge__IssueTracker"
|
||||
displayName = "MinecraftForge/MinecraftForge"
|
||||
repositoryURL = "https://github.com/MinecraftForge/MinecraftForge"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Build : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_BuildMainBranches"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"), AbsoluteId("MinecraftForge_PublishProjectUsingGradle"), AbsoluteId("MinecraftForge_TriggersStaticFilesWebpageGenerator"))
|
||||
id("MinecraftForge_MinecraftForge__Build")
|
||||
name = "Build"
|
||||
description = "Builds and Publishes the main branches of the project."
|
||||
|
||||
features {
|
||||
feature {
|
||||
id = "trigger_fml_only_files_generator"
|
||||
type = "triggerBuildFeature"
|
||||
param("triggers", "MinecraftForge_FilesGenerator_GeneratePages")
|
||||
param("parameters", """
|
||||
env.PUBLISHED_JAVA_FML_ARTIFACT_ID~env.PUBLISHED_JAVA_ARTIFACT_ID
|
||||
env.PUBLISHED_JAVA_FML_ARTIFACT_VERSION~env.PUBLISHED_JAVA_ARTIFACT_VERSION
|
||||
env.PUBLISHED_JAVA_GROUP
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
object BuildSecondaryBranches : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_ExcludesBuildingDefaultBranch"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_BuildMainBranches"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__BuildSecondaryBranches")
|
||||
name = "Build - Secondary Branches"
|
||||
description = "Builds and Publishes the secondary branches of the project."
|
||||
params {
|
||||
text("git_branch_spec", """
|
||||
+:refs/heads/(*)
|
||||
-:refs/heads/noci*
|
||||
""".trimIndent(), label = "The branch specification of the repository", description = "By default all main branches are build by the configuration. Modify this value to adapt the branches build.", display = ParameterDisplay.HIDDEN, allowEmpty = true)
|
||||
}
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
|
||||
object PullRequests : BuildType({
|
||||
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"), AbsoluteId("MinecraftForge_BuildUsingGradle"))
|
||||
id("MinecraftForge_MinecraftForge__PullRequests")
|
||||
name = "Pull Requests"
|
||||
description = "Builds pull requests for the project"
|
||||
|
||||
params {
|
||||
checkbox("should_execute_build", "true", label = "Should build", description = "Indicates if the build task should be executed.", display = ParameterDisplay.HIDDEN,
|
||||
checked = "true", unchecked = "false")
|
||||
text(
|
||||
"gradle_build_task",
|
||||
"assemble",
|
||||
label = "Gradle build task to execute during build",
|
||||
description = "Determines the build task that is executed to build the project.",
|
||||
display = ParameterDisplay.HIDDEN,
|
||||
allowEmpty = false
|
||||
)
|
||||
}
|
||||
|
||||
vcs {
|
||||
branchFilter = """
|
||||
+:*
|
||||
-:1.*
|
||||
-:<default>
|
||||
""".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()
|
||||
}
|
||||
})
|
||||
+21
-29
@@ -29,13 +29,14 @@ plugins {
|
||||
id 'eclipse'
|
||||
id 'idea'
|
||||
id 'de.undercouch.download' version '5.4.0'
|
||||
id 'net.minecraftforge.gradle.patcher' version '[6.0.11,6.2)' apply false
|
||||
id 'net.minecraftforge.gradle.mcp' version '[6.0.11,6.2)' apply false
|
||||
id 'net.minecraftforge.gradle.patcher' version '[6.0.52,6.2)' apply false
|
||||
id 'net.minecraftforge.gradle.mcp' version '[6.0.52,6.2)' apply false
|
||||
}
|
||||
|
||||
Util.init() //Init all our extension methods!
|
||||
|
||||
ext {
|
||||
HAS_CLEAN = findProject(':clean') != null
|
||||
JAR_SIGNER = null
|
||||
if (project.hasProperty('keystore')) {
|
||||
JAR_SIGNER = [
|
||||
@@ -55,11 +56,11 @@ ext {
|
||||
MERGETOOL_VERSION = '1.1.5'
|
||||
ACCESSTRANSFORMERS_VERSION = '8.0.4'
|
||||
COREMODS_VERSION = '5.2.4'
|
||||
EVENTBUS_VERSION = '6.0.5'
|
||||
EVENTBUS_VERSION = '6.2.33'
|
||||
MODLAUNCHER_VERSION = '10.0.9'
|
||||
SECUREJARHANDLER_VERSION = '2.1.10'
|
||||
BOOTSTRAPLAUNCHER_VERSION = '1.1.2'
|
||||
ASM_VERSION = '9.7.1'
|
||||
ASM_VERSION = '9.9.1'
|
||||
INSTALLER_VERSION = '2.2.+'
|
||||
MIXIN_VERSION = '0.8.5'
|
||||
TERMINALCONSOLEAPPENDER_VERSION = '1.2.0'
|
||||
@@ -227,7 +228,7 @@ project(':mcp') {
|
||||
}
|
||||
}
|
||||
|
||||
if (!System.env.TEAMCITY_VERSION) {
|
||||
if (HAS_CLEAN) {
|
||||
project(':clean') {
|
||||
evaluationDependsOn(':mcp')
|
||||
apply plugin: 'net.minecraftforge.gradle.patcher'
|
||||
@@ -890,7 +891,7 @@ project(':fmlonly') {
|
||||
}
|
||||
|
||||
project(':forge') {
|
||||
evaluationDependsOn(System.env.TEAMCITY_VERSION ? ':mcp' : ':clean')
|
||||
evaluationDependsOn(HAS_CLEAN ? ':clean' : ':mcp')
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'net.minecraftforge.gradle.patcher'
|
||||
apply plugin: 'org.cadixdev.licenser'
|
||||
@@ -970,18 +971,14 @@ project(':forge') {
|
||||
|
||||
patcher {
|
||||
excs.from file("$rootDir/src/main/resources/forge.exc")
|
||||
parent = project(System.env.TEAMCITY_VERSION ? ':mcp' : ':clean')
|
||||
parent = project(HAS_CLEAN ? ':clean' : ':mcp')
|
||||
patches = file("$rootDir/patches/minecraft")
|
||||
patchedSrc = file('src/main/java')
|
||||
srgPatches = true
|
||||
accessTransformers.from file("$rootDir/src/main/resources/META-INF/accesstransformer.cfg")
|
||||
sideAnnotationStrippers.from file("$rootDir/src/main/resources/forge.sas")
|
||||
|
||||
// the clean project provides these. if we're not using it, we need to provide them ourselves
|
||||
if (System.env.TEAMCITY_VERSION) {
|
||||
mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION
|
||||
mcVersion = MC_VERSION
|
||||
}
|
||||
mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION
|
||||
mcVersion = MC_VERSION
|
||||
|
||||
runs {
|
||||
forge_client {
|
||||
@@ -1635,6 +1632,12 @@ project(':forge') {
|
||||
}
|
||||
}
|
||||
|
||||
final mdkGradleWrapper = tasks.register('mdkGradleWrapper', Wrapper) {
|
||||
gradleVersion = "9.8.2"
|
||||
scriptFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradlew")
|
||||
jarFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradle/wrapper/gradle-wrapper.jar")
|
||||
}
|
||||
|
||||
task makeMdk(type: Zip) {
|
||||
archiveBaseName = project.name
|
||||
archiveClassifier = 'mdk'
|
||||
@@ -1644,8 +1647,9 @@ project(':forge') {
|
||||
from rootProject.file('gradlew')
|
||||
from rootProject.file('gradlew.bat')
|
||||
from extraTxts
|
||||
from(rootProject.file('gradle/')){
|
||||
into('gradle/')
|
||||
into('gradle/wrapper/') {
|
||||
from mdkGradleWrapper.map(Wrapper.&getJarFile)
|
||||
from mdkGradleWrapper.map(Wrapper.&getPropertiesFile)
|
||||
}
|
||||
from(rootProject.file('mdk/')){
|
||||
rootProject.file('mdk/gitignore.txt').eachLine{
|
||||
@@ -1803,7 +1807,7 @@ project(':forge') {
|
||||
|
||||
//evaluationDependsOnChildren()
|
||||
task setup() { //These must be strings so that we can do lazy resolution. Else we need evaluationDependsOnChildren above
|
||||
if (!System.env.TEAMCITY_VERSION)
|
||||
if (HAS_CLEAN)
|
||||
dependsOn ':clean:extractMapped'
|
||||
if (symlinkValid)
|
||||
dependsOn ':fmlonly:extractMapped'
|
||||
@@ -1818,21 +1822,9 @@ task doChecks {
|
||||
if (symlinkValid)
|
||||
project.gradle.startParameter.excludedTaskNames.add(':fmlonly:genPatches')
|
||||
|
||||
if (!System.env.TEAMCITY_VERSION)
|
||||
if (HAS_CLEAN)
|
||||
project.gradle.startParameter.excludedTaskNames.add(':clean:genPatches')
|
||||
|
||||
//Also output FMLOnly when building a version.
|
||||
if (System.env.TEAMCITY_VERSION) {
|
||||
//Only setup the CI environment if and only if the environment variables are set.
|
||||
tasks.configureTeamCity {
|
||||
doLast {
|
||||
println "##teamcity[buildNumber '${project(':forge').version}']"
|
||||
println "##teamcity[setParameter name='env.PUBLISHED_JAVA_ARTIFACT_VERSION' value='${project(':forge').version}']"
|
||||
println "##teamcity[setParameter name='env.PUBLISHED_JAVA_FML_ARTIFACT_VERSION' value='${project(':fmlonly').version}']"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
// IntelliJ IDEA does not do this by itself anymore...
|
||||
|
||||
@@ -4,9 +4,9 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.ow2.asm:asm:9.5'
|
||||
implementation 'org.ow2.asm:asm-tree:9.5'
|
||||
implementation 'net.minecraftforge:srgutils:0.5.+'
|
||||
implementation 'org.ow2.asm:asm:9.9.1'
|
||||
implementation 'org.ow2.asm:asm-tree:9.9.1'
|
||||
implementation 'net.minecraftforge:srgutils:0.6.5'
|
||||
implementation 'commons-io:commons-io:2.12.0'
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.5.0.202303070854-r'
|
||||
|
||||
@@ -202,7 +202,7 @@ public class FMLLoader
|
||||
|
||||
public static void addAccessTransformer(Path atPath, ModFile modName)
|
||||
{
|
||||
LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
|
||||
LOGGER.debug(SCAN, "Adding Access Transformer in {} in {}", atPath, modName.getFilePath());
|
||||
accessTransformer.offerResource(atPath, modName.getFileName());
|
||||
}
|
||||
|
||||
|
||||
+123
-14
@@ -5,6 +5,8 @@
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.Launcher;
|
||||
import cpw.mods.modlauncher.api.IModuleLayerManager;
|
||||
import net.minecraftforge.fml.loading.progress.ProgressMeter;
|
||||
import net.minecraftforge.fml.loading.progress.StartupNotificationManager;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -23,28 +25,44 @@ public class ImmediateWindowHandler {
|
||||
|
||||
private static ProgressMeter earlyProgress;
|
||||
public static void load(final String launchTarget, final String[] arguments) {
|
||||
final var serviceLayer = Launcher.INSTANCE.findLayerManager()
|
||||
.flatMap(manager -> manager.getLayer(IModuleLayerManager.Layer.SERVICE))
|
||||
.orElse(null);
|
||||
final var providerName = FMLConfig.getConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_PROVIDER);
|
||||
|
||||
if (!List.of("forgeclient", "forgeclientuserdev", "forgeclientdev").contains(launchTarget)) {
|
||||
provider = new DummyProvider();
|
||||
LOGGER.info("ImmediateWindowProvider not loading because launch target is {}", launchTarget);
|
||||
} else if (!FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_CONTROL)) {
|
||||
provider = new DummyProvider();
|
||||
LOGGER.info("ImmediateWindowProvider not loading because splash screen is disabled");
|
||||
} else if (providerName == null) {
|
||||
LOGGER.info("ImmediateWindowProvider not loading because splash screen provider is null");
|
||||
} else if (serviceLayer == null) {
|
||||
LOGGER.error("Failed to find service layer for ImmediateWindowProvider");
|
||||
} else {
|
||||
final var providername = FMLConfig.getConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_PROVIDER);
|
||||
LOGGER.info("Loading ImmediateWindowProvider {}", providername);
|
||||
final var maybeProvider = ServiceLoader.load(ImmediateWindowProvider.class)
|
||||
.stream()
|
||||
.map(ServiceLoader.Provider::get)
|
||||
.filter(p -> Objects.equals(p.name(), providername))
|
||||
.findFirst();
|
||||
provider = maybeProvider.or(() -> {
|
||||
LOGGER.info("Failed to find ImmediateWindowProvider {}, disabling", providername);
|
||||
return Optional.of(new DummyProvider());
|
||||
}).orElseThrow();
|
||||
LOGGER.info("Loading ImmediateWindowProvider {}", providerName);
|
||||
|
||||
for (var itr = ServiceLoader.load(serviceLayer, ImmediateWindowProvider.class).iterator(); itr.hasNext(); ) {
|
||||
try {
|
||||
var srvc = itr.next();
|
||||
if (providerName.equals(srvc.name())) {
|
||||
provider = new Wrapper(srvc);
|
||||
break;
|
||||
}
|
||||
} catch (ServiceConfigurationError e) {
|
||||
LOGGER.error("Failed to initalize ImmediateWindowProvider Service", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (provider == null)
|
||||
LOGGER.info("Failed to find ImmediateWindowProvider {}, disabling", providerName);
|
||||
}
|
||||
|
||||
// Only update config if the provider isn't the dummy provider
|
||||
if (!Objects.equals(provider.name(), "dummyprovider"))
|
||||
if (provider != null)
|
||||
FMLConfig.updateConfig(FMLConfig.ConfigValue.EARLY_WINDOW_PROVIDER, provider.name());
|
||||
else
|
||||
provider = new DummyProvider();
|
||||
|
||||
FMLLoader.progressWindowTick = provider.initialize(arguments);
|
||||
earlyProgress = StartupNotificationManager.addProgressBar("EARLY", 0);
|
||||
earlyProgress.label("Bootstrapping Minecraft");
|
||||
@@ -78,6 +96,7 @@ public class ImmediateWindowHandler {
|
||||
public static String getGLVersion() {
|
||||
return provider.getGLVersion();
|
||||
}
|
||||
|
||||
public static void updateProgress(final String message) {
|
||||
earlyProgress.label(message);
|
||||
}
|
||||
@@ -156,4 +175,94 @@ public class ImmediateWindowHandler {
|
||||
// NOOP
|
||||
}
|
||||
}
|
||||
|
||||
// We create a wrapper because we want to log errors to the log files, which not all paths of ModLauncher do. Little dirty, but works for now.
|
||||
private static class Wrapper implements ImmediateWindowProvider {
|
||||
private final ImmediateWindowProvider delegate;
|
||||
|
||||
private Wrapper(ImmediateWindowProvider delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
try {
|
||||
return delegate.name();
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.name", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public Runnable initialize(String[] arguments) {
|
||||
try {
|
||||
return delegate.initialize(arguments);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.initialize", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFramebufferSize(IntConsumer width, IntConsumer height) {
|
||||
try {
|
||||
delegate.updateFramebufferSize(width, height);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.updateFramebufferSize", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public long setupMinecraftWindow(IntSupplier width, IntSupplier height, Supplier<String> title, LongSupplier monitor) {
|
||||
try {
|
||||
return delegate.setupMinecraftWindow(width, height, title, monitor);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.setupMinecraftWindow", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean positionWindow(Optional<Object> monitor, IntConsumer widthSetter, IntConsumer heightSetter, IntConsumer xSetter, IntConsumer ySetter) {
|
||||
try {
|
||||
return delegate.positionWindow(monitor, widthSetter, heightSetter, xSetter, ySetter);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.positionWindow", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> Supplier<T> loadingOverlay(Supplier<?> mc, Supplier<?> ri, Consumer<Optional<Throwable>> ex, boolean fade) {
|
||||
try {
|
||||
return delegate.loadingOverlay(mc, ri, ex, fade);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.loadingOverlay", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateModuleReads(ModuleLayer layer) {
|
||||
try {
|
||||
delegate.updateModuleReads(layer);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.updateModuleReads", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public void periodicTick() {
|
||||
try {
|
||||
delegate.periodicTick();
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.periodicTick", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
public String getGLVersion() {
|
||||
try {
|
||||
return delegate.getGLVersion();
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to call provider.getGLVersion", t);
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,14 @@
|
||||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
@@ -30,6 +32,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class LoadingModList
|
||||
{
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static LoadingModList INSTANCE;
|
||||
private final List<ModFileInfo> modFiles;
|
||||
private final List<ModInfo> sortedList;
|
||||
@@ -78,9 +81,22 @@ public class LoadingModList
|
||||
|
||||
public void addAccessTransformers()
|
||||
{
|
||||
modFiles.stream()
|
||||
.map(ModFileInfo::getFile)
|
||||
.forEach(mod -> mod.getAccessTransformer().ifPresent(path -> FMLLoader.addAccessTransformer(path, mod)));
|
||||
var errors = new ArrayList<EarlyLoadingException.ExceptionData>();
|
||||
for (ModFileInfo modFile : modFiles) {
|
||||
ModFile mod = modFile.getFile();
|
||||
for (Path at : mod.getAccessTransformers()) {
|
||||
if (!Files.exists(at)) {
|
||||
var message = "Invalid mod file: " + modFile.getFile().getFileName() + ". Missing Access Transformer: " + at;
|
||||
errors.add(new EarlyLoadingException.ExceptionData(message));
|
||||
LOGGER.error(message);
|
||||
} else {
|
||||
FMLLoader.addAccessTransformer(at, mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
preLoadErrors.add(new EarlyLoadingException("Invalid Access Transformers", null, errors));
|
||||
}
|
||||
}
|
||||
|
||||
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
|
||||
|
||||
+2
-1
@@ -28,7 +28,8 @@ public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService
|
||||
private static final Set<String> SERVICES = Set.of(
|
||||
"cpw.mods.modlauncher.api.ITransformationService",
|
||||
"net.minecraftforge.forgespi.locating.IModLocator",
|
||||
"net.minecraftforge.forgespi.locating.IDependencyLocator"
|
||||
"net.minecraftforge.forgespi.locating.IDependencyLocator",
|
||||
"net.minecraftforge.fml.loading.ImmediateWindowProvider"
|
||||
);
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,8 +34,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
|
||||
public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
{
|
||||
public final class RuntimeDistCleaner implements ILaunchPluginService {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final Marker DISTXFORM = MarkerFactory.getMarker("DISTXFORM");
|
||||
private static String DIST;
|
||||
@@ -61,7 +60,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
{
|
||||
unpack(classNode.visibleAnnotations).stream()
|
||||
.filter(ann->Objects.equals(ann.desc, ONLYIN))
|
||||
.filter(ann->ann.values.indexOf("_interface") != -1)
|
||||
.filter(ann-> ann.values.contains("_interface"))
|
||||
.filter(ann->!Objects.equals(((String[])ann.values.get(ann.values.indexOf("value") + 1))[1], DIST))
|
||||
.map(ann -> ((Type)ann.values.get(ann.values.indexOf("_interface") + 1)).getInternalName())
|
||||
.forEach(intf -> {
|
||||
@@ -151,7 +150,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
{
|
||||
return unpack(anns).stream().
|
||||
filter(ann->Objects.equals(ann.desc, ONLYIN)).
|
||||
filter(ann->ann.values.indexOf("_interface") == -1).
|
||||
filter(ann-> !ann.values.contains("_interface")).
|
||||
anyMatch(ann -> !Objects.equals(((String[])ann.values.get(ann.values.indexOf("value")+1))[1], side));
|
||||
}
|
||||
|
||||
@@ -177,6 +176,10 @@ public class RuntimeDistCleaner implements ILaunchPluginService
|
||||
if (internalName.startsWith("net/minecraftforge/"))
|
||||
return NAY;
|
||||
|
||||
// No Vanilla classes use @OnlyIn(Dist.SERVER), so we can skip them entirely when we're running on a client
|
||||
if (FMLEnvironment.dist.isClient() && (internalName.startsWith("net/minecraft/") || internalName.startsWith("com/mojang/")))
|
||||
return NAY;
|
||||
|
||||
return YAY;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
@@ -60,6 +62,7 @@ public class ModFile implements IModFile {
|
||||
private CompletableFuture<ModFileScanData> futureScanResult;
|
||||
private List<CoreModFile> coreMods;
|
||||
private Path accessTransformer;
|
||||
private List<Path> accessTransformers = Collections.emptyList();
|
||||
|
||||
static final Attributes.Name TYPE = new Attributes.Name("FMLModType");
|
||||
private SecureJar.Status securityStatus;
|
||||
@@ -104,7 +107,11 @@ public class ModFile implements IModFile {
|
||||
}
|
||||
|
||||
public Optional<Path> getAccessTransformer() {
|
||||
return Optional.ofNullable(Files.exists(accessTransformer) ? accessTransformer : null);
|
||||
return Optional.ofNullable(accessTransformer);
|
||||
}
|
||||
|
||||
public List<Path> getAccessTransformers() {
|
||||
return accessTransformers;
|
||||
}
|
||||
|
||||
public boolean identifyMods() {
|
||||
@@ -113,7 +120,28 @@ public class ModFile implements IModFile {
|
||||
LOGGER.debug(LogMarkers.LOADING,"Loading mod file {} with languages {}", this.getFilePath(), this.modFileInfo.requiredLanguageLoaders());
|
||||
this.coreMods = ModFileParser.getCoreMods(this);
|
||||
this.coreMods.forEach(mi-> LOGGER.debug(LogMarkers.LOADING,"Found coremod {}", mi.getPath()));
|
||||
this.accessTransformer = findResource("META-INF", "accesstransformer.cfg");
|
||||
List<String> cfg;
|
||||
// Note: Some mods may have invalid tomls copied from other projects.
|
||||
// Unfortunately we must protect against those landmines.
|
||||
try {
|
||||
cfg = this.modFileInfo.getConfig().<List<String>>getConfigElement("accessTransformers").orElse(null);
|
||||
} catch (Exception e) {
|
||||
cfg = null;
|
||||
LOGGER.warn("{} contains an invalid 'accessTransformers' TOML entry. Should be e.g. accessTransformers = [\"META-INF/accesstransformer.cfg\", \"META-INF/extra_at.cfg\"] or accessTransformers = [] for no ATs. Falling back to default.", this.getFileName());
|
||||
}
|
||||
if (cfg == null) {
|
||||
var path = findResource("META-INF", "accesstransformer.cfg");
|
||||
if (Files.exists(path)) {
|
||||
this.accessTransformer = path;
|
||||
this.accessTransformers = List.of(path);
|
||||
}
|
||||
} else if (!cfg.isEmpty()) {
|
||||
var paths = new ArrayList<Path>(cfg.size());
|
||||
for (var path : cfg) {
|
||||
paths.add(getSecureJar().getPath(path.replace('\\', '/')));
|
||||
}
|
||||
this.accessTransformers = List.copyOf(paths);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -6,6 +6,7 @@
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.electronwill.nightconfig.core.file.FileConfig;
|
||||
import com.electronwill.nightconfig.core.io.ParsingException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.mojang.logging.LogUtils;
|
||||
@@ -13,6 +14,7 @@ import net.minecraftforge.fml.loading.LogMarkers;
|
||||
import net.minecraftforge.forgespi.language.IModFileInfo;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import net.minecraftforge.forgespi.locating.ModFileFactory;
|
||||
import net.minecraftforge.forgespi.locating.ModFileLoadingException;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -22,7 +24,6 @@ import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ModFileParser {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -41,10 +42,15 @@ public class ModFileParser {
|
||||
}
|
||||
|
||||
final FileConfig fileConfig = FileConfig.builder(modsjson).build();
|
||||
fileConfig.load();
|
||||
fileConfig.close();
|
||||
final NightConfigWrapper configWrapper = new NightConfigWrapper(fileConfig);
|
||||
return new ModFileInfo(modFile, configWrapper, configWrapper::setFile);
|
||||
try {
|
||||
fileConfig.load();
|
||||
fileConfig.close();
|
||||
final NightConfigWrapper configWrapper = new NightConfigWrapper(fileConfig);
|
||||
return new ModFileInfo(modFile, configWrapper, configWrapper::setFile);
|
||||
} catch (ParsingException e) {
|
||||
LOGGER.error("Mod candidate {} contains a corrupt or misconfigured toml.", modFile.getFileName());
|
||||
throw new ModFileLoadingException("Mod candidate " + modFile.getFileName() + " contains a corrupt or misconfigured toml.");
|
||||
}
|
||||
}
|
||||
|
||||
protected static List<CoreModFile> getCoreMods(final ModFile modFile) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
org.gradle.daemon=false
|
||||
+93
-132
@@ -1,156 +1,87 @@
|
||||
// Don't see a feature you're wanting to use?
|
||||
// See our MDKExamples repository for minimal examples for features like JarInJar
|
||||
// https://github.com/MinecraftForge/MDKExamples
|
||||
plugins {
|
||||
id 'eclipse'
|
||||
id 'idea'
|
||||
id 'java'
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.gradle' version '[6.0,6.2)'
|
||||
id 'net.minecraftforge.gradle' version '[7.0,8)'
|
||||
id 'net.minecraftforge.renamer' version '1.1.8+' // Required on all versions which use SRG maps at runtime.
|
||||
}
|
||||
|
||||
version = mod_version
|
||||
group = mod_group_id
|
||||
|
||||
base {
|
||||
archivesName = mod_id
|
||||
}
|
||||
version = '1.0'
|
||||
group = 'com.example'
|
||||
base.archivesName = 'examplemod'
|
||||
|
||||
// Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17.
|
||||
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
|
||||
|
||||
println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}"
|
||||
println "Java: ${providers.systemProperty('java.version').get()}, " +
|
||||
"JVM: ${providers.systemProperty('java.vm.version').get()} (${providers.systemProperty('java.vendor').get()}), " +
|
||||
"Arch: ${providers.systemProperty('os.arch').get()}"
|
||||
|
||||
minecraft {
|
||||
// The mappings can be changed at any time and must be in the following format.
|
||||
// Channel: Version:
|
||||
// official MCVersion Official field/method names from Mojang mapping files
|
||||
// parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official
|
||||
//
|
||||
// You must be aware of the Mojang license when using the 'official' or 'parchment' mappings.
|
||||
// See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
|
||||
//
|
||||
// Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge
|
||||
// Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started
|
||||
//
|
||||
// Use non-default mappings at your own risk. They may not always work.
|
||||
// Simply re-run your setup task after changing the mappings to update your workspace.
|
||||
mappings channel: mapping_channel, version: mapping_version
|
||||
// Declare which mappings to use
|
||||
mappings channel: mapping_channel, version: minecraft_version
|
||||
|
||||
// When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game.
|
||||
// In most cases, it is not necessary to enable.
|
||||
// enableEclipsePrepareRuns = true
|
||||
// enableIdeaPrepareRuns = true
|
||||
// Access Transformer files may now be automatically detected, or explicitly declared.
|
||||
// Setting the below flag will cause ForgeGradle to look for META-INF/accesstransformer.cfg
|
||||
// Alternatively, provide it a file(<path>) or files(<paths>) for explicitly declared files. If you use any
|
||||
// explicitly declared access transformers, all transformers must be also declared in the mods.toml
|
||||
// accessTransformer = true
|
||||
|
||||
// This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game.
|
||||
// It is REQUIRED to be set to true for this template to function.
|
||||
// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
|
||||
copyIdeResources = true
|
||||
|
||||
// When true, this property will add the folder name of all declared run configurations to generated IDE run configurations.
|
||||
// The folder name can be set on a run configuration using the "folderName" property.
|
||||
// By default, the folder name of a run configuration is the name of the Gradle project containing it.
|
||||
// generateRunFolders = true
|
||||
|
||||
// This property enables access transformers for use in development.
|
||||
// They will be applied to the Minecraft artifact.
|
||||
// The access transformer file can be anywhere in the project.
|
||||
// However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge.
|
||||
// This default location is a best practice to automatically put the file in the right place in the final jar.
|
||||
// See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information.
|
||||
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
// Default run configurations.
|
||||
// These can be tweaked, removed, or duplicated as needed.
|
||||
runs {
|
||||
// applies to all the run configs below
|
||||
configureEach {
|
||||
workingDirectory project.file('run')
|
||||
workingDir.convention layout.projectDirectory.dir('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'
|
||||
//systemProperty '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'
|
||||
|
||||
mods {
|
||||
"${mod_id}" {
|
||||
source sourceSets.main
|
||||
}
|
||||
}
|
||||
//args "-mixin.config=${mod_id}.mixins.json"
|
||||
}
|
||||
|
||||
client {
|
||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
||||
property 'forge.enabledGameTestNamespaces', mod_id
|
||||
register('client') {
|
||||
systemProperty 'forge.enabledGameTestNamespaces', mod_id
|
||||
}
|
||||
|
||||
server {
|
||||
property 'forge.enabledGameTestNamespaces', mod_id
|
||||
register('server') {
|
||||
systemProperty 'forge.enabledGameTestNamespaces', mod_id
|
||||
args '--nogui'
|
||||
}
|
||||
|
||||
// This run config launches GameTestServer and runs all registered gametests, then exits.
|
||||
// By default, the server will crash when no gametests are provided.
|
||||
// The gametest system is also enabled by default for other run configs under the /test command.
|
||||
gameTestServer {
|
||||
property 'forge.enabledGameTestNamespaces', mod_id
|
||||
register('gameTestServer') {
|
||||
systemProperty 'forge.enabledGameTestNamespaces', mod_id
|
||||
}
|
||||
|
||||
data {
|
||||
// example of overriding the workingDirectory set in configureEach above
|
||||
workingDirectory project.file('run-data')
|
||||
register('data') {
|
||||
workingDir = layout.projectDirectory.dir('run-data')
|
||||
|
||||
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
|
||||
args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
|
||||
args '--mod', mod_id, '--all', '--output', layout.projectDirectory.dir('src/generated/resources'), '--existing', layout.projectDirectory.dir('src/main/resources')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include resources generated by data generators.
|
||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
||||
repositories {
|
||||
// Put repositories for dependencies here
|
||||
// ForgeGradle automatically adds the Forge maven and Maven Central for you
|
||||
|
||||
// If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
|
||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
|
||||
// flatDir {
|
||||
// dir 'libs'
|
||||
// }
|
||||
minecraft.mavenizer(it)
|
||||
maven fg.forgeMaven
|
||||
maven fg.minecraftLibsMaven
|
||||
// Needed for JEI
|
||||
// maven { url = 'https://maven.blamejared.com/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Specify the version of Minecraft to use.
|
||||
// Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact.
|
||||
// The "userdev" classifier will be requested and setup by ForgeGradle.
|
||||
// If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"],
|
||||
// then special handling is done to allow a setup of a vanilla dependency without the use of an external repository.
|
||||
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
||||
|
||||
// Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings
|
||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
||||
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}")
|
||||
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}")
|
||||
// runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}")
|
||||
|
||||
// Example mod dependency using a mod jar from ./libs with a flat dir repository
|
||||
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
|
||||
// The group id is ignored when searching -- in this case, it is "blank"
|
||||
// implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")
|
||||
|
||||
// For more info:
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
// Minecraft/Forge itself
|
||||
implementation minecraft.dependency("net.minecraftforge:forge:$minecraft_version-$forge_version")
|
||||
// A 3rd party mod, which needs to be deobfuscated from SRG names to the mappings we're using
|
||||
// implementation renamer.dependency('mezz.jei:jei-1.20.1-forge:15.20.0.129')
|
||||
// annotationProcessor 'org.spongepowered:mixin:0.8.7:processor'
|
||||
}
|
||||
|
||||
// This block of code expands all declared replace properties in the specified resource targets.
|
||||
// A missing property will result in an error. Properties are expanded using ${} Groovy notation.
|
||||
// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments.
|
||||
// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
|
||||
tasks.named('processResources', ProcessResources).configure {
|
||||
tasks.named('processResources', ProcessResources) {
|
||||
var replaceProperties = [
|
||||
minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range,
|
||||
forge_version: forge_version, forge_version_range: forge_version_range,
|
||||
@@ -158,15 +89,15 @@ tasks.named('processResources', ProcessResources).configure {
|
||||
mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version,
|
||||
mod_authors: mod_authors, mod_description: mod_description,
|
||||
]
|
||||
inputs.properties replaceProperties
|
||||
inputs.property('replaceProperties', replaceProperties)
|
||||
|
||||
filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
|
||||
expand replaceProperties + [project: project]
|
||||
expand replaceProperties
|
||||
}
|
||||
}
|
||||
|
||||
// Example for how to get properties into the manifest for reading at runtime.
|
||||
tasks.named('jar', Jar).configure {
|
||||
tasks.named('jar', Jar) {
|
||||
manifest {
|
||||
attributes([
|
||||
'Specification-Title' : mod_id,
|
||||
@@ -174,34 +105,64 @@ tasks.named('jar', Jar).configure {
|
||||
'Specification-Version' : '1', // We are version 1 of ourselves
|
||||
'Implementation-Title' : project.name,
|
||||
'Implementation-Version' : project.jar.archiveVersion,
|
||||
'Implementation-Vendor' : mod_authors,
|
||||
'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
'Implementation-Vendor' : mod_authors
|
||||
])
|
||||
//attributes['MixinConfigs'] = "${mod_id}.mixins.json"
|
||||
}
|
||||
|
||||
// This is the preferred method to reobfuscate your jar file
|
||||
finalizedBy 'reobfJar'
|
||||
// This artifact will not be renamed. While this will not launch in production
|
||||
// the artifact may be helpful for other developers if your mod is used as a library.
|
||||
// By assigning this archive classifier, jar file name will end in '-unobfuscated'
|
||||
// e.g. 'examplemod-1.0-unobfuscated.jar'
|
||||
archiveClassifier = 'unobfuscated'
|
||||
}
|
||||
|
||||
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing:
|
||||
// tasks.named('publish').configure {
|
||||
// dependsOn 'reobfJar'
|
||||
// }
|
||||
// Set the default mappings file to our default minecraft dependency
|
||||
// This must be done after `minecraft.dependency('coords')` has been done so that gradle knows what dependency we want
|
||||
// This mapping will be used by default for all renamer tasks, including deobfuscating dependencies
|
||||
// You can still override each specific task, this is just to save repeating yourself in your buildscript.
|
||||
renamer.mappings.from minecraft.dependency.toSrgFile
|
||||
|
||||
// If you are choosing to use mixins, you must give Renamer the additional information for it to handle the refmaps.
|
||||
//renamer.enableMixinRefmaps {
|
||||
// config "${mod_id}.mixins.json"
|
||||
// refMap "${mod_id}.refmap.json"
|
||||
//}
|
||||
|
||||
// Creates a task named 'renameJar'
|
||||
renamer.classes(tasks.named('jar', Jar)) {
|
||||
// This artifact will be remapped according to the provided mappings file
|
||||
// Setting the classifier to '' will attach no extra details to the file name.
|
||||
// e.g. 'examplemod-1.0.jar'
|
||||
archiveClassifier = ''
|
||||
// Unless set globally like above, You need to point to the mappings you wish to apply, typically this is
|
||||
// the Mapped names to SRG for older versions.
|
||||
// ForgeGradle/Mavenizer generate these files for the dependencies you declare. So you can use the helper.
|
||||
// Or you can specify the file or dependency if you host them yourself.
|
||||
// map.from minecraft.dependency.toSrgFile
|
||||
|
||||
// The mixin AP does not include all annotated entries, instead containing some in the augmented mappings.
|
||||
// So, if you are using mixins or have dependencies which use them, uncomment the below line to tell renamer
|
||||
// that the generated mappings are available. See the MDKExample for more details.
|
||||
// mappings renamer.mixin.generatedMappings
|
||||
}
|
||||
|
||||
// Example configuration to allow publishing using the maven-publish plugin
|
||||
// We recommend publishing all of your artifacts to publicly accessible maven so that others can easily consume them as dependencies
|
||||
publishing {
|
||||
publications {
|
||||
register('mavenJava', MavenPublication) {
|
||||
artifact jar
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "file://${project.projectDir}/mcmodsrepo"
|
||||
}
|
||||
// Publishing to a local folder makes it easy to see exactly what you would publish to a real server
|
||||
maven { url = layout.projectDirectory.dir('repo').asFile.toURI() }
|
||||
}
|
||||
|
||||
publications.register('mavenJava', MavenPublication) {
|
||||
from components.java // Publish the normal jar
|
||||
artifact renameJar // Publish the renamed jar in addition
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
||||
}
|
||||
|
||||
// IntelliJ no longer downloads javadocs and sources by default, this tells Gradle to force IntelliJ to do it.
|
||||
idea.module { downloadJavadoc = downloadSources = true }
|
||||
+16
-13
@@ -1,25 +1,29 @@
|
||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
org.gradle.daemon=false
|
||||
org.gradle.caching=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.configuration-cache.parallel=true
|
||||
org.gradle.configuration-cache.problems=warn
|
||||
|
||||
net.minecraftforge.gradle.merge-source-sets=true
|
||||
|
||||
## Environment Properties
|
||||
|
||||
# The Minecraft version must agree with the Forge version to get a valid artifact
|
||||
minecraft_version=@MC_VERSION@
|
||||
minecraft_version=1.20.1
|
||||
# The Minecraft version range can use any release version of Minecraft as bounds.
|
||||
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
|
||||
# as they do not follow standard versioning conventions.
|
||||
minecraft_version_range=[@MC_VERSION@,@MC_NEXT_VERSION@)
|
||||
minecraft_version_range=[1.20.1, 1.20.2)
|
||||
# The Forge version must agree with the Minecraft version to get a valid artifact
|
||||
forge_version=@FORGE_VERSION@
|
||||
# The Forge version range can use any version of Forge as bounds or match the loader version range
|
||||
forge_version_range=[@FORGE_SPEC_VERSION@,)
|
||||
forge_version_range=[47,)
|
||||
# The loader version range can only use the major version of Forge/FML as bounds
|
||||
loader_version_range=[@FORGE_SPEC_VERSION@,)
|
||||
loader_version_range=[47,)
|
||||
# The mapping channel to use for mappings.
|
||||
# The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"].
|
||||
# The default set of supported mapping channels are ["official", "parchment"].
|
||||
# Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin.
|
||||
#
|
||||
# | Channel | Version | |
|
||||
@@ -31,12 +35,11 @@ loader_version_range=[@FORGE_SPEC_VERSION@,)
|
||||
# See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
|
||||
#
|
||||
# Parchment is an unofficial project maintained by ParchmentMC, separate from Minecraft Forge.
|
||||
# Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started
|
||||
mapping_channel=@MAPPING_CHANNEL@
|
||||
# Unlike in FG6, Parchment no longer requires the Librarian plugin to be set up.
|
||||
mapping_channel=official
|
||||
# The mapping version to query from the mapping channel.
|
||||
# This must match the format required by the mapping channel.
|
||||
mapping_version=@MAPPING_VERSION@
|
||||
|
||||
mapping_version=1.20.1
|
||||
|
||||
## Mod Properties
|
||||
|
||||
|
||||
+3
-11
@@ -1,13 +1,5 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
name = 'MinecraftForge'
|
||||
url = 'https://maven.minecraftforge.net/'
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
|
||||
}
|
||||
rootProject.name = 'examplemod'
|
||||
@@ -41,6 +41,12 @@ authors="${mod_authors}" #optional
|
||||
# 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" # if nothing is specified, MATCH_VERSION is the default when clientSideOnly=false, otherwise IGNORE_ALL_VERSION when clientSideOnly=true (#optional)
|
||||
|
||||
# Access Transformers
|
||||
# Optional, if not specified Forge will attempt to find the default META-INF/accesstransformer.cfg and silently continue if not found. May default to an empty list in a future MC.
|
||||
# If you specify AT path strings in this list, Forge will attempt to load each of them and throw errors for any that aren't found.
|
||||
# Specifying an empty list when your mod has no ATs is recommended to opt-out of the default for slightly better loading performance.
|
||||
#accessTransformers = []
|
||||
|
||||
# The description text for the mod (multi line!) (#mandatory)
|
||||
description='''${mod_description}'''
|
||||
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
|
||||
|
||||
@@ -88,12 +88,15 @@
|
||||
}
|
||||
|
||||
public void m_105287_() {
|
||||
@@ -262,7 +_,7 @@
|
||||
@@ -262,7 +_,10 @@
|
||||
|
||||
private boolean m_105281_(BlockPos p_105282_) {
|
||||
ItemStack itemstack = this.f_105189_.f_91074_.m_21205_();
|
||||
- return p_105282_.equals(this.f_105191_) && ItemStack.m_150942_(itemstack, this.f_105192_);
|
||||
+ return p_105282_.equals(this.f_105191_) && ItemStack.m_150942_(itemstack, this.f_105192_) && !f_105192_.shouldCauseBlockBreakReset(itemstack);
|
||||
+ // FORGE: Remove this method call, but keep the bytecode intact for hacks that target it
|
||||
+ if (Boolean.FALSE)
|
||||
+ ItemStack.m_150942_(itemstack, this.f_105192_);
|
||||
+ return p_105282_.equals(this.f_105191_) && !f_105192_.shouldCauseBlockBreakReset(itemstack);
|
||||
}
|
||||
|
||||
private void m_105297_() {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/net/minecraft/commands/SharedSuggestionProvider.java
|
||||
+++ b/net/minecraft/commands/SharedSuggestionProvider.java
|
||||
@@ -82,7 +_,7 @@
|
||||
if (m_82949_(p_82946_, s)) {
|
||||
p_82948_.accept(t);
|
||||
}
|
||||
- } else if (m_82949_(p_82946_, resourcelocation.m_135827_()) || resourcelocation.m_135827_().equals("minecraft") && m_82949_(p_82946_, resourcelocation.m_135815_())) {
|
||||
+ } else if (m_82949_(p_82946_, resourcelocation.m_135827_()) || m_82949_(p_82946_, resourcelocation.m_135815_())) { // Forge: Removed "minecraft" namespace requirement for path searching to allow modded path suggestions to show up
|
||||
p_82948_.accept(t);
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -44,12 +44,20 @@
|
||||
}
|
||||
|
||||
public ResourceLocation m_132042_() {
|
||||
@@ -61,4 +_,8 @@
|
||||
@@ -60,5 +_,16 @@
|
||||
|
||||
public FriendlyByteBuf m_132045_() {
|
||||
return new FriendlyByteBuf(this.f_132030_.copy());
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ @Override public int getIndex() { return Integer.MAX_VALUE; }
|
||||
+ @Override public ResourceLocation getName() { return m_132042_(); }
|
||||
+ @Override public FriendlyByteBuf getInternalData() { return m_132045_(); }
|
||||
+ @Override public FriendlyByteBuf getInternalData() {
|
||||
+ // Create a heap copy to pass off to other consumers because we could be reading from a pooled buffer that never gets released.
|
||||
+ // Using a heap buffer means that it will be released when the GC determines its free.
|
||||
+ // See: https://github.com/MinecraftForge/MinecraftForge/issues/10861
|
||||
+ var heapCopy = io.netty.buffer.Unpooled.buffer(this.f_132030_.readableBytes());
|
||||
+ heapCopy.writeBytes(this.f_132030_.slice()); // We use a slice to not mess with the reader index, just in case someone else wants to touch the buffer later
|
||||
+ return new FriendlyByteBuf(heapCopy);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -124,7 +_,11 @@
|
||||
@@ -124,7 +_,14 @@
|
||||
}
|
||||
|
||||
public void m_214168_(BlockPos p_215120_, ServerboundPlayerActionPacket.Action p_215121_, Direction p_215122_, int p_215123_, int p_215124_) {
|
||||
@@ -9,7 +9,10 @@
|
||||
+ if (event.isCanceled() || (!this.m_9295_() && event.getResult() == net.minecraftforge.eventbus.api.Event.Result.DENY)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!this.f_9245_.canReach(p_215120_, 1.5)) { // Vanilla check is eye-to-center distance < 6, so padding is 6 - 4.5 = 1.5
|
||||
+
|
||||
+ boolean canReachUnmodded = this.testPlayerCanReach(p_215120_);
|
||||
+ boolean canReachModded = this.f_9245_.canReach(p_215120_, 1.5); // Vanilla uses ServerGamePacketListenerImpl.MAX_INTERACTION_DISTANCE which is 6*6, default Block reach is 4.5, so add 1.5 padding
|
||||
+ if (canReachUnmodded == canReachModded ? !this.f_9245_.canReachRaw(p_215120_, 1.5) : !canReachModded) {
|
||||
this.m_215125_(p_215120_, false, p_215124_, "too far");
|
||||
} else if (p_215120_.m_123342_() >= p_215123_) {
|
||||
this.f_9245_.f_8906_.m_9829_(new ClientboundBlockUpdatePacket(p_215120_, this.f_9244_.m_8055_(p_215120_)));
|
||||
@@ -21,6 +24,18 @@
|
||||
blockstate.m_60686_(this.f_9244_, p_215120_, this.f_9245_);
|
||||
f = blockstate.m_60625_(this.f_9245_, this.f_9245_.m_9236_(), p_215120_);
|
||||
}
|
||||
@@ -209,6 +_,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ private boolean testPlayerCanReach(BlockPos pos) {
|
||||
+ // don't mixin into this
|
||||
+ return this.f_9245_.canReach(pos, 1.5);
|
||||
+ }
|
||||
+
|
||||
public void m_215116_(BlockPos p_215117_, int p_215118_, String p_215119_) {
|
||||
if (this.m_9280_(p_215117_)) {
|
||||
this.m_215125_(p_215117_, true, p_215118_, p_215119_);
|
||||
@@ -221,7 +_,8 @@
|
||||
|
||||
public boolean m_9280_(BlockPos p_9281_) {
|
||||
|
||||
+16
-3
@@ -26,12 +26,14 @@
|
||||
this.f_9743_.m_5810_();
|
||||
}
|
||||
|
||||
@@ -1035,7 +_,7 @@
|
||||
@@ -1035,7 +_,9 @@
|
||||
Vec3 vec3 = blockhitresult.m_82450_();
|
||||
BlockPos blockpos = blockhitresult.m_82425_();
|
||||
Vec3 vec31 = Vec3.m_82512_(blockpos);
|
||||
- if (!(this.f_9743_.m_146892_().m_82557_(vec31) > f_215198_)) {
|
||||
+ if (this.f_9743_.canReach(blockpos, 1.5)) { // Vanilla uses eye-to-center distance < 6, which implies a padding of 1.5
|
||||
+ boolean canReachUnmodded = this.testPlayerCanReach(blockpos);
|
||||
+ boolean canReachModded = this.f_9743_.canReach(blockpos, 1.5); // Vanilla uses eye-to-center distance < ServerGamePacketListenerImpl which is 6*6, default block reach is 4.5, so add 1.5 padding
|
||||
+ if (canReachUnmodded == canReachModded ? this.f_9743_.canReachRaw(blockpos, 1.5) : canReachModded) {
|
||||
Vec3 vec32 = vec3.m_82546_(vec31);
|
||||
double d0 = 1.0000001D;
|
||||
if (Math.abs(vec32.m_7096_()) < 1.0000001D && Math.abs(vec32.m_7098_()) < 1.0000001D && Math.abs(vec32.m_7094_()) < 1.0000001D) {
|
||||
@@ -44,6 +46,17 @@
|
||||
InteractionResult interactionresult = this.f_9743_.f_8941_.m_7179_(this.f_9743_, serverlevel, itemstack, interactionhand, blockhitresult);
|
||||
if (direction == Direction.UP && !interactionresult.m_19077_() && blockpos.m_123342_() >= i - 1 && m_9790_(this.f_9743_, itemstack)) {
|
||||
Component component = Component.m_237110_("build.tooHigh", i - 1).m_130940_(ChatFormatting.RED);
|
||||
@@ -1066,6 +_,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ private boolean testPlayerCanReach(BlockPos pos) {
|
||||
+ return this.f_9743_.canReach(pos, 1.5);
|
||||
+ }
|
||||
+
|
||||
public void m_5760_(ServerboundUseItemPacket p_9932_) {
|
||||
PacketUtils.m_131359_(p_9932_, this, this.f_9743_.m_284548_());
|
||||
this.m_215201_(p_9932_.m_238013_());
|
||||
@@ -1187,10 +_,13 @@
|
||||
}
|
||||
|
||||
@@ -65,7 +78,7 @@
|
||||
|
||||
AABB aabb = entity.m_20191_();
|
||||
- if (aabb.m_272282_(this.f_9743_.m_146892_()) < f_215198_) {
|
||||
+ if (this.f_9743_.canReach(entity, 3)) { // Vanilla padding is 3.0 (distSq < 6.0 * 6.0)
|
||||
+ if (this.f_9743_.canReachRaw(entity, 3.0)) { // Vanilla uses MAX_INTERACTION_DISTANCE which is 6*6 default entity reach is 3.0 so add 3.0 padding
|
||||
p_9866_.m_179617_(new ServerboundInteractPacket.Handler() {
|
||||
private void m_143678_(InteractionHand p_143679_, ServerGamePacketListenerImpl.EntityInteraction p_143680_) {
|
||||
ItemStack itemstack = ServerGamePacketListenerImpl.this.f_9743_.m_21120_(p_143679_);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
--- a/net/minecraft/world/Container.java
|
||||
+++ b/net/minecraft/world/Container.java
|
||||
@@ -78,10 +_,14 @@
|
||||
}
|
||||
|
||||
static boolean m_272074_(BlockEntity p_273154_, Player p_273222_) {
|
||||
- return m_271806_(p_273154_, p_273222_, 8);
|
||||
+ return stillValidBlockEntity(p_273154_, p_273222_, p_273222_.m_21133_(net.minecraftforge.common.ForgeMod.BLOCK_REACH.get()) + 3.5); // Vanilla uses 8, default reach is 4.5 so add 3.5 padding
|
||||
}
|
||||
|
||||
static boolean m_271806_(BlockEntity p_272877_, Player p_272670_, int p_273411_) {
|
||||
+ return stillValidBlockEntity(p_272877_, p_272670_, (double)p_273411_);
|
||||
+ }
|
||||
+
|
||||
+ static boolean stillValidBlockEntity(BlockEntity p_272877_, Player p_272670_, double p_273411_) {
|
||||
Level level = p_272877_.m_58904_();
|
||||
BlockPos blockpos = p_272877_.m_58899_();
|
||||
if (level == null) {
|
||||
@@ -422,7 +422,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2980,9 +_,22 @@
|
||||
@@ -2980,9 +_,31 @@
|
||||
this.f_19859_ = this.m_146908_();
|
||||
}
|
||||
|
||||
@@ -439,6 +439,15 @@
|
||||
+ this.updateFluidHeightAndDoFluidPushing(com.google.common.base.Predicates.alwaysTrue());
|
||||
+ }
|
||||
+
|
||||
+ private static final class FluidCalcs {
|
||||
+ double height = 0.0D;
|
||||
+ Vec3 direction = Vec3.f_82478_;
|
||||
+ int count = 0;
|
||||
+ double height(double height) {
|
||||
+ return (this.height = this.height >= height ? this.height : height);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void updateFluidHeightAndDoFluidPushing(Predicate<FluidState> shouldUpdate) {
|
||||
if (this.m_146899_()) {
|
||||
- return false;
|
||||
@@ -446,11 +455,14 @@
|
||||
} else {
|
||||
AABB aabb = this.m_20191_().m_82406_(0.001D);
|
||||
int i = Mth.m_14107_(aabb.f_82288_);
|
||||
@@ -2997,25 +_,28 @@
|
||||
Vec3 vec3 = Vec3.f_82478_;
|
||||
int k1 = 0;
|
||||
@@ -2994,28 +_,32 @@
|
||||
double d0 = 0.0D;
|
||||
boolean flag = this.m_6063_();
|
||||
boolean flag1 = false;
|
||||
- Vec3 vec3 = Vec3.f_82478_;
|
||||
- int k1 = 0;
|
||||
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectMap<net.minecraftforge.fluids.FluidType, org.apache.commons.lang3.tuple.MutableTriple<Double, Vec3, Integer>> interimCalcs = new it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<>(net.minecraftforge.fluids.FluidType.SIZE.get() - 1);
|
||||
+ it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<net.minecraftforge.fluids.FluidType, FluidCalcs> fluidPushCalcs = null;
|
||||
|
||||
for(int l1 = i; l1 < j; ++l1) {
|
||||
for(int i2 = k; i2 < l; ++i2) {
|
||||
@@ -464,59 +476,50 @@
|
||||
if (d1 >= aabb.f_82289_) {
|
||||
flag1 = true;
|
||||
- d0 = Math.max(d1 - aabb.f_82289_, d0);
|
||||
- if (flag) {
|
||||
+ org.apache.commons.lang3.tuple.MutableTriple<Double, Vec3, Integer> interim = interimCalcs.computeIfAbsent(fluidType, t -> org.apache.commons.lang3.tuple.MutableTriple.of(0.0D, Vec3.f_82478_, 0));
|
||||
+ interim.setLeft(Math.max(d1 - aabb.f_82289_, interim.getLeft()));
|
||||
+ if (this.isPushedByFluid(fluidType)) {
|
||||
+ if (fluidPushCalcs == null)
|
||||
+ fluidPushCalcs = new it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap<net.minecraftforge.fluids.FluidType, FluidCalcs>(2);
|
||||
+ var interim = fluidPushCalcs.computeIfAbsent(fluidType, type -> new FluidCalcs());
|
||||
+ d0 = interim.height(d1 - aabb.f_82289_);
|
||||
+ flag = this.isPushedByFluid(fluidType);
|
||||
if (flag) {
|
||||
Vec3 vec31 = fluidstate.m_76179_(this.m_9236_(), blockpos$mutableblockpos);
|
||||
- if (d0 < 0.4D) {
|
||||
- vec31 = vec31.m_82490_(d0);
|
||||
+ if (interim.getLeft() < 0.4D) {
|
||||
+ vec31 = vec31.m_82490_(interim.getLeft());
|
||||
if (d0 < 0.4D) {
|
||||
vec31 = vec31.m_82490_(d0);
|
||||
}
|
||||
|
||||
- vec3 = vec3.m_82549_(vec31);
|
||||
- ++k1;
|
||||
+ interim.setMiddle(interim.getMiddle().m_82549_(vec31));
|
||||
+ interim.setRight(interim.getRight() + 1);
|
||||
+ interim.direction = interim.direction.m_82549_(vec31);
|
||||
+ interim.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3023,27 +_,28 @@
|
||||
@@ -3023,6 +_,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- if (vec3.m_82553_() > 0.0D) {
|
||||
- if (k1 > 0) {
|
||||
- vec3 = vec3.m_82490_(1.0D / (double)k1);
|
||||
+ interimCalcs.forEach((fluidType, interim) -> {
|
||||
+ if (interim.getMiddle().m_82553_() > 0.0D) {
|
||||
+ if (interim.getRight() > 0) {
|
||||
+ interim.setMiddle(interim.getMiddle().m_82490_(1.0D / (double)interim.getRight()));
|
||||
}
|
||||
|
||||
if (!(this instanceof Player)) {
|
||||
- vec3 = vec3.m_82541_();
|
||||
+ interim.setMiddle(interim.getMiddle().m_82541_());
|
||||
+ if (fluidPushCalcs == null) return;
|
||||
+ fluidPushCalcs.forEach((fluidType, interim) -> {
|
||||
+ var vec3 = interim.direction;
|
||||
+ var k1 = interim.count;
|
||||
if (vec3.m_82553_() > 0.0D) {
|
||||
if (k1 > 0) {
|
||||
vec3 = vec3.m_82490_(1.0D / (double)k1);
|
||||
@@ -3033,6 +_,7 @@
|
||||
}
|
||||
|
||||
Vec3 vec32 = this.m_20184_();
|
||||
- vec3 = vec3.m_82490_(p_204033_ * 1.0D);
|
||||
+ interim.setMiddle(interim.getMiddle().m_82490_(this.getFluidMotionScale(fluidType)));
|
||||
+ var p_204033_ = this.getFluidMotionScale(fluidType);
|
||||
vec3 = vec3.m_82490_(p_204033_ * 1.0D);
|
||||
double d2 = 0.003D;
|
||||
- if (Math.abs(vec32.f_82479_) < 0.003D && Math.abs(vec32.f_82481_) < 0.003D && vec3.m_82553_() < 0.0045000000000000005D) {
|
||||
- vec3 = vec3.m_82541_().m_82490_(0.0045000000000000005D);
|
||||
+ if (Math.abs(vec32.f_82479_) < 0.003D && Math.abs(vec32.f_82481_) < 0.003D && interim.getMiddle().m_82553_() < 0.0045000000000000005D) {
|
||||
+ interim.setMiddle(interim.getMiddle().m_82541_().m_82490_(0.0045000000000000005D));
|
||||
}
|
||||
|
||||
- this.m_20256_(this.m_20184_().m_82549_(vec3));
|
||||
+ this.m_20256_(this.m_20184_().m_82549_(interim.getMiddle()));
|
||||
if (Math.abs(vec32.f_82479_) < 0.003D && Math.abs(vec32.f_82481_) < 0.003D && vec3.m_82553_() < 0.0045000000000000005D) {
|
||||
@@ -3042,8 +_,8 @@
|
||||
this.m_20256_(this.m_20184_().m_82549_(vec3));
|
||||
}
|
||||
|
||||
- this.f_19799_.put(p_204032_, d0);
|
||||
- return flag1;
|
||||
+ this.setFluidTypeHeight(fluidType, interim.getLeft());
|
||||
+ this.setFluidTypeHeight(fluidType, interim.height);
|
||||
+ });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,3 +43,16 @@
|
||||
crashreportcategory.m_128159_("Item ID", Item.m_41393_(p_36042_.m_41720_()));
|
||||
crashreportcategory.m_128159_("Item data", p_36042_.m_41773_());
|
||||
crashreportcategory.m_128165_("Item name", () -> {
|
||||
@@ -530,7 +_,11 @@
|
||||
if (this.f_35978_.m_213877_()) {
|
||||
return false;
|
||||
} else {
|
||||
- return !(p_36009_.m_20280_(this.f_35978_) > 64.0D);
|
||||
+ // Vanilla uses 64 which is 8*8. Default reach is 3.0 so add 5.0 padding
|
||||
+ // magic number so required Mixins can still target here
|
||||
+ double reachOld = 64.0;
|
||||
+ double reach = p_36009_.m_21133_(net.minecraftforge.common.ForgeMod.ENTITY_REACH.get()) + 5.0;
|
||||
+ return !(p_36009_.m_20280_(this.f_35978_) > reach * reach);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,15 +251,18 @@
|
||||
}
|
||||
|
||||
float f4 = 0.0F;
|
||||
@@ -1121,8 +_,9 @@
|
||||
@@ -1121,8 +_,12 @@
|
||||
if (flag3) {
|
||||
float f3 = 1.0F + EnchantmentHelper.m_44821_(this) * f;
|
||||
|
||||
- for(LivingEntity livingentity : this.m_9236_().m_45976_(LivingEntity.class, p_36347_.m_20191_().m_82377_(1.0D, 0.25D, 1.0D))) {
|
||||
- if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.m_20280_(livingentity) < 9.0D) {
|
||||
+ for(LivingEntity livingentity : this.m_9236_().m_45976_(LivingEntity.class, this.m_21120_(InteractionHand.MAIN_HAND).getSweepHitBox(this, p_36347_))) {
|
||||
+ double entityReachSq = Mth.m_144952_(this.getEntityReach()); // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks.
|
||||
+ if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.m_20280_(livingentity) < entityReachSq) {
|
||||
+ // Use entity reach instead of constant 9.0. Vanilla uses bottom center-to-center checks here, so don't update this to use canReach, since it uses closest-corner checks.
|
||||
+ // magic number so required Mixins can still target here
|
||||
+ var reachOld = 9.0;
|
||||
+ var reach = this.m_21133_(net.minecraftforge.common.ForgeMod.ENTITY_REACH.get());
|
||||
+ if (livingentity != this && livingentity != p_36347_ && !this.m_7307_(livingentity) && (!(livingentity instanceof ArmorStand) || !((ArmorStand)livingentity).m_31677_()) && this.m_20280_(livingentity) < reach * reach) {
|
||||
livingentity.m_147240_((double)0.4F, (double)Mth.m_14031_(this.m_146908_() * ((float)Math.PI / 180F)), (double)(-Mth.m_14089_(this.m_146908_() * ((float)Math.PI / 180F))));
|
||||
livingentity.m_6469_(this.m_269291_().m_269075_(this), f3);
|
||||
}
|
||||
|
||||
@@ -10,3 +10,11 @@
|
||||
if (p_219950_ != null) {
|
||||
lootparams$builder.m_287239_(p_219950_.m_36336_()).m_287286_(LootContextParams.f_81455_, p_219950_);
|
||||
}
|
||||
@@ -171,6 +_,6 @@
|
||||
}
|
||||
|
||||
default boolean m_219954_(Player p_219955_) {
|
||||
- return !this.m_213877_() && this.m_20182_().m_82509_(p_219955_.m_20182_(), 8.0D);
|
||||
+ return !this.m_213877_() && this.m_20182_().m_82509_(p_219955_.m_20182_(), p_219955_.m_21133_(net.minecraftforge.common.ForgeMod.ENTITY_REACH.get()) + 5.0); // Vanilla uses 8 default reach is 3.0 so add 5.0 padding
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,18 @@
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -67,7 +_,11 @@
|
||||
|
||||
protected static boolean m_38889_(ContainerLevelAccess p_38890_, Player p_38891_, Block p_38892_) {
|
||||
return p_38890_.m_39299_((p_38916_, p_38917_) -> {
|
||||
- return !p_38916_.m_8055_(p_38917_).m_60713_(p_38892_) ? false : p_38891_.m_20275_((double)p_38917_.m_123341_() + 0.5D, (double)p_38917_.m_123342_() + 0.5D, (double)p_38917_.m_123343_() + 0.5D) <= 64.0D;
|
||||
+ // Vanilla uses 64 which is 8*8. Default reach is 4.5 so add 3.5 padding
|
||||
+ // magic number so required Mixins can still target here
|
||||
+ double reachOld = 64.0;
|
||||
+ double reach = p_38891_.m_21133_(net.minecraftforge.common.ForgeMod.BLOCK_REACH.get()) + 3.5;
|
||||
+ return !p_38916_.m_8055_(p_38917_).m_60713_(p_38892_) ? false : p_38891_.m_20275_((double)p_38917_.m_123341_() + 0.5D, (double)p_38917_.m_123342_() + 0.5D, (double)p_38917_.m_123343_() + 0.5D) <= reach * reach;
|
||||
}, true);
|
||||
}
|
||||
|
||||
@@ -229,6 +_,8 @@
|
||||
ItemStack itemstack1 = p_150438_.get();
|
||||
this.f_150394_.set(p_150436_, itemstack1);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
--- a/net/minecraft/world/inventory/HorseInventoryMenu.java
|
||||
+++ b/net/minecraft/world/inventory/HorseInventoryMenu.java
|
||||
@@ -62,7 +_,11 @@
|
||||
}
|
||||
|
||||
public boolean m_6875_(Player p_39661_) {
|
||||
- return !this.f_39654_.m_149511_(this.f_39653_) && this.f_39653_.m_6542_(p_39661_) && this.f_39654_.m_6084_() && this.f_39654_.m_20270_(p_39661_) < 8.0F;
|
||||
+ // Make pehkui's mixin happy so we stop getting crash reports. It requires the magic float 8.0F
|
||||
+ float magic_number = 8.0F;
|
||||
+ // Default reach is 3 vanilla uses 8 here so add 5 padding
|
||||
+ double reach = p_39661_.m_21133_(net.minecraftforge.common.ForgeMod.ENTITY_REACH.get()) + 5;
|
||||
+ return !this.f_39654_.m_149511_(this.f_39653_) && this.f_39653_.m_6542_(p_39661_) && this.f_39654_.m_6084_() && this.f_39654_.m_20270_(p_39661_) < reach;
|
||||
}
|
||||
|
||||
private boolean m_150577_(AbstractHorse p_150578_) {
|
||||
@@ -0,0 +1,15 @@
|
||||
--- a/net/minecraft/world/inventory/ItemCombinerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/ItemCombinerMenu.java
|
||||
@@ -108,7 +_,11 @@
|
||||
|
||||
public boolean m_6875_(Player p_39780_) {
|
||||
return this.f_39770_.m_39299_((p_39785_, p_39786_) -> {
|
||||
- return !this.m_8039_(p_39785_.m_8055_(p_39786_)) ? false : p_39780_.m_20275_((double)p_39786_.m_123341_() + 0.5D, (double)p_39786_.m_123342_() + 0.5D, (double)p_39786_.m_123343_() + 0.5D) <= 64.0D;
|
||||
+ // Vanilla uses 64 which is 8*8. Default reach is 4.5 so add 3.5 padding
|
||||
+ // magic number so required Mixins can still target here
|
||||
+ double reachOld = 64.0;
|
||||
+ double reach = p_39780_.m_21133_(net.minecraftforge.common.ForgeMod.BLOCK_REACH.get()) + 3.5;
|
||||
+ return !this.m_8039_(p_39785_.m_8055_(p_39786_)) ? false : p_39780_.m_20275_((double)p_39786_.m_123341_() + 0.5D, (double)p_39786_.m_123342_() + 0.5D, (double)p_39786_.m_123343_() + 0.5D) <= reach * reach;
|
||||
}, true);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
float f7 = f2 * f4;
|
||||
- double d0 = 5.0D;
|
||||
- Vec3 vec31 = vec3.m_82520_((double)f6 * 5.0D, (double)f5 * 5.0D, (double)f7 * 5.0D);
|
||||
+ double d0 = p_41437_.getBlockReach();
|
||||
+ double d0 = p_41437_.m_21133_(net.minecraftforge.common.ForgeMod.BLOCK_REACH.get()) + 0.5; // Block reach is 4.5, vanilla uses 5.0 here, so add 0.5 padding
|
||||
+ Vec3 vec31 = vec3.m_82520_((double)f6 * d0, (double)f5 * d0, (double)f7 * d0);
|
||||
return p_41436_.m_45547_(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, p_41438_, p_41437_));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
+ private boolean isFlammable(LevelReader level, BlockPos pos, Direction face) {
|
||||
+ return pos.m_123342_() >= level.m_141937_() && pos.m_123342_() < level.m_151558_() && !level.m_46805_(pos) ? false : level.m_8055_(pos).isFlammable(level, pos, face);
|
||||
+ return pos.m_123342_() >= level.m_141937_() && pos.m_123342_() < level.m_151558_() && !level.m_46805_(pos) ? false : level.m_8055_(pos).m_278200_() && level.m_8055_(pos).isFlammable(level, pos, face);
|
||||
+ }
|
||||
+
|
||||
@Nullable
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ project(":mcp").projectDir = file("projects/mcp")
|
||||
project(":fmlonly").projectDir = file("projects/fmlonly")
|
||||
project(":forge").projectDir = file("projects/forge")
|
||||
|
||||
if (!System.env.TEAMCITY_VERSION) {
|
||||
if (false && !'true'.equals(System.env.CI)) {
|
||||
include ':clean'
|
||||
project(":clean").projectDir = file("projects/clean")
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"faces": {
|
||||
"down": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
},
|
||||
"east": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
},
|
||||
"north": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
},
|
||||
"south": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
},
|
||||
"up": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
},
|
||||
"west": {
|
||||
"forge_data": {
|
||||
"block_light": 10,
|
||||
"sky_light": 10
|
||||
},
|
||||
"texture": "#all"
|
||||
}
|
||||
},
|
||||
"forge_data": {
|
||||
"block_light": 15,
|
||||
"sky_light": 15
|
||||
},
|
||||
"from": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"to": [
|
||||
16,
|
||||
16,
|
||||
16
|
||||
]
|
||||
}
|
||||
],
|
||||
"render_type": "minecraft:cutout",
|
||||
"textures": {
|
||||
"all": "minecraft:block/diamond_ore"
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
},
|
||||
"loader": "forge:item_layers",
|
||||
"render_types": {},
|
||||
"render_types_fast": {},
|
||||
"textures": {
|
||||
"layer0": "minecraft:item/coal",
|
||||
"layer1": "minecraft:item/stick",
|
||||
|
||||
@@ -172,11 +172,18 @@ public abstract class EntityRenderersEvent extends Event implements IModBusEvent
|
||||
* @return the skin renderer, or {@code null} if no renderer is registered for that skin name
|
||||
* @see #getSkins()
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends EntityRenderer<? extends Player>> @Nullable R getPlayerSkin(String skinName)
|
||||
{
|
||||
return (R) skinMap.get(skinName);
|
||||
}
|
||||
|
||||
/** @deprecated Use getEntitySkin, return type down graded to EntityRenderer instead of LivingEntityRenderer */
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends LivingEntityRenderer<? extends Player, ? extends EntityModel<? extends Player>>> R getSkin(String skinName)
|
||||
{
|
||||
return (R) skinMap.get(skinName);
|
||||
return skinMap.get(skinName) instanceof LivingEntityRenderer<?,?> renderer ? (R) renderer : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,11 +194,18 @@ public abstract class EntityRenderersEvent extends Event implements IModBusEvent
|
||||
* @param <R> the type of the renderer
|
||||
* @return the renderer, or {@code null} if no renderer is registered for that entity type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity, R extends EntityRenderer<T>> @Nullable R getEntityRenderer(EntityType<? extends T> entityType)
|
||||
{
|
||||
return (R) renderers.get(entityType);
|
||||
}
|
||||
|
||||
/** @deprecated Use getEntityRenderer, return type down graded to EntityRenderer instead of LivingEntityRenderer */
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends LivingEntity, R extends LivingEntityRenderer<T, ? extends EntityModel<T>>> R getRenderer(EntityType<? extends T> entityType)
|
||||
{
|
||||
return (R) renderers.get(entityType);
|
||||
return renderers.get(entityType) instanceof LivingEntityRenderer<?,?> renderer ? (R) renderer : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -361,6 +361,10 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
|
||||
partObj.addProperty("shade", part.shade);
|
||||
}
|
||||
|
||||
if (!part.getFaceData().equals(ForgeFaceData.DEFAULT)) {
|
||||
partObj.add("forge_data", ForgeFaceData.CODEC.encodeStart(JsonOps.INSTANCE, part.getFaceData()).result().get());
|
||||
}
|
||||
|
||||
JsonObject faces = new JsonObject();
|
||||
for (Direction dir : Direction.values()) {
|
||||
BlockElementFace face = part.faces.get(dir);
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.mojang.serialization.Lifecycle;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
@@ -420,7 +421,7 @@ public class ForgeHooks
|
||||
return message; // Vanilla should never get here with the patches we use, but let's be safe with dumb mods
|
||||
|
||||
return onServerChatSubmittedEvent(sender, getRawText(message), message);
|
||||
});
|
||||
}, Util.backgroundExecutor());
|
||||
}
|
||||
|
||||
static final Pattern URL_PATTERN = Pattern.compile(
|
||||
|
||||
@@ -95,6 +95,10 @@ public class ForgeI18n {
|
||||
}
|
||||
|
||||
public static String parseFormat(final String format, final Object... args) {
|
||||
// No format elements and no quotes: MessageFormat would return the pattern unchanged, so skip parsing it
|
||||
if (format != null && format.indexOf('{') < 0 && format.indexOf('\'') < 0) {
|
||||
return format;
|
||||
}
|
||||
final ExtendedMessageFormat extendedMessageFormat = new ExtendedMessageFormat(format, customFactories);
|
||||
return extendedMessageFormat.format(args);
|
||||
}
|
||||
|
||||
@@ -628,7 +628,7 @@ public interface IForgeBlock
|
||||
*/
|
||||
default boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction)
|
||||
{
|
||||
return state.ignitedByLava() || state.getFlammability(level, pos, direction) > 0;
|
||||
return state.getFlammability(level, pos, direction) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package net.minecraftforge.common.extensions;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
@@ -14,30 +13,29 @@ import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
|
||||
public interface IForgePlayer
|
||||
{
|
||||
|
||||
private Player self()
|
||||
{
|
||||
return (Player) this;
|
||||
public interface IForgePlayer {
|
||||
private Player self() {
|
||||
return (Player)this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The entity reach is increased by 3 for creative players, unless it is currently zero, which disables attacks and entity interactions.
|
||||
* This comes from {@link net.minecraft.client.multiplayer.MultiPlayerGameMode#getPickRange() MultiPlayerGameMode.getPickRange()}
|
||||
* If you want the raw value, get the attribute yourself.
|
||||
* @return The entity reach of this player.
|
||||
*/
|
||||
default double getEntityReach()
|
||||
{
|
||||
default double getEntityReach() {
|
||||
double range = self().getAttributeValue(ForgeMod.ENTITY_REACH.get());
|
||||
return range == 0 ? 0 : range + (self().isCreative() ? 3 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The reach distance is increased by 0.5 for creative players, unless it is currently zero, which disables interactions.
|
||||
* This comes from {@link net.minecraft.client.multiplayer.MultiPlayerGameMode#getPickRange() MultiPlayerGameMode.getPickRange()}
|
||||
* If you want the raw value, get the attribute yourself.
|
||||
* @return The reach distance of this player.
|
||||
*/
|
||||
default double getBlockReach()
|
||||
{
|
||||
default double getBlockReach() {
|
||||
double reach = self().getAttributeValue(ForgeMod.BLOCK_REACH.get());
|
||||
return reach == 0 ? 0 : reach + (self().isCreative() ? 0.5 : 0);
|
||||
}
|
||||
@@ -50,8 +48,7 @@ public interface IForgePlayer
|
||||
* @return If the player can attack the entity.
|
||||
* @apiNote Do not use for block checks, as this method uses {@link #getEntityReach()}
|
||||
*/
|
||||
default boolean canReach(Vec3 entityHitVec, double padding)
|
||||
{
|
||||
default boolean canReach(Vec3 entityHitVec, double padding) {
|
||||
return self().getEyePosition().closerThan(entityHitVec, getEntityReach() + padding);
|
||||
}
|
||||
|
||||
@@ -63,11 +60,27 @@ public interface IForgePlayer
|
||||
* @return If the player can attack the passed entity.
|
||||
* @apiNote Prefer using {@link #canReach(Vec3, double)} if you have a {@link HitResult} available.
|
||||
*/
|
||||
default boolean canReach(Entity entity, double padding)
|
||||
{
|
||||
default boolean canReach(Entity entity, double padding) {
|
||||
return isCloseEnough(entity, getEntityReach() + padding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player can reach an entity.<br>
|
||||
* On the server, additional padding is added to account for movement/lag.
|
||||
*
|
||||
* Unlike {@link #getEntityReach()} or {@link #canReach(Entity,double)} this does not
|
||||
* add the 3.0 creative mode implicit padding.
|
||||
*
|
||||
* @param entity The entity being range-checked.
|
||||
* @param padding Extra validation distance.
|
||||
* @return If the player can attack the passed entity.
|
||||
* @apiNote Prefer using {@link #canReach(Vec3, double)} if you have a {@link HitResult} available.
|
||||
*/
|
||||
default boolean canReachRaw(Entity entity, double padding) {
|
||||
double range = self().getAttributeValue(ForgeMod.ENTITY_REACH.get()) + padding;
|
||||
return isCloseEnough(entity, range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player can reach a block.<br>
|
||||
* On the server, additional padding is added to account for movement/lag.
|
||||
@@ -75,10 +88,25 @@ public interface IForgePlayer
|
||||
* @param padding Extra validation distance.
|
||||
* @return If the player can interact with this location.
|
||||
*/
|
||||
default boolean canReach(BlockPos pos, double padding)
|
||||
{
|
||||
default boolean canReach(BlockPos pos, double padding) {
|
||||
double reach = this.getBlockReach() + padding;
|
||||
return self().getEyePosition().distanceToSqr(Vec3.atCenterOf(pos)) < reach * reach;
|
||||
return self().getEyePosition().distanceToSqr(Vec3.atCenterOf(pos)) <= reach * reach;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player can reach a block.<br>
|
||||
* On the server, additional padding is added to account for movement/lag.
|
||||
*
|
||||
* Unlike {@link #getBlockReach()} or {@link #canReach(BlockPos,double)} this does not
|
||||
* add the 0.5 creative mode implicit padding.
|
||||
*
|
||||
* @param pos The position being range-checked.
|
||||
* @param padding Extra validation distance.
|
||||
* @return If the player can interact with this location.
|
||||
*/
|
||||
default boolean canReachRaw(BlockPos pos, double padding) {
|
||||
double reach = self().getAttributeValue(ForgeMod.BLOCK_REACH.get()) + padding;
|
||||
return self().getEyePosition().distanceToSqr(Vec3.atCenterOf(pos)) <= reach * reach;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,8 +116,12 @@ public interface IForgePlayer
|
||||
* @return If the eye-to-center distance between this player and the passed entity is less than dist.
|
||||
* @implNote This method inflates the bounding box by the pick radius, which differs from vanilla. But vanilla doesn't use the pick radius, the only entity with > 0 is AbstractHurtingProjectile.
|
||||
*/
|
||||
default boolean isCloseEnough(Entity entity, double dist)
|
||||
{
|
||||
default boolean isCloseEnough(Entity entity, double dist) {
|
||||
// This cuses the "eye-to-closest-corner" checks, which can cause issues with servers.
|
||||
// https://github.com/MinecraftForge/MinecraftForge/issues/9309
|
||||
// But to not break expectations of others, its staying until a config can be set.
|
||||
// The vanilla code is:
|
||||
// return entity.getBoundingBox().distanceToSqr(self().getEyePosition()) < dist * dist;
|
||||
Vec3 eye = self().getEyePosition();
|
||||
AABB aabb = entity.getBoundingBox().inflate(entity.getPickRadius());
|
||||
return aabb.distanceToSqr(eye) < dist * dist;
|
||||
|
||||
@@ -18,33 +18,30 @@ import java.util.function.Supplier;
|
||||
* for each of your collections.<p/>
|
||||
* This list does not support modification operations, but the underlying lists may be mutated safely externally.
|
||||
*/
|
||||
public class ConcatenatedListView<T> implements List<T>
|
||||
{
|
||||
public class ConcatenatedListView<T> implements List<T> {
|
||||
@SafeVarargs
|
||||
public static <T> ConcatenatedListView<T> of(List<T>... lists)
|
||||
{
|
||||
public static <T> ConcatenatedListView<T> of(List<T>... lists) {
|
||||
return new ConcatenatedListView<>(List.of(lists));
|
||||
}
|
||||
|
||||
public static <T> List<T> of(List<? extends List<? extends T>> members)
|
||||
{
|
||||
return switch (members.size()) {
|
||||
case 0 -> List.of();
|
||||
case 1 -> Collections.unmodifiableList(members.get(0));
|
||||
default -> new ConcatenatedListView<>(members);
|
||||
};
|
||||
public static <T> List<T> of(List<? extends List<? extends T>> members) {
|
||||
if (members.isEmpty())
|
||||
return List.of();
|
||||
if (members.size() == 1)
|
||||
return (Collections.unmodifiableList(members.get(0)));
|
||||
@SuppressWarnings("unchecked")
|
||||
var typed = (List<List<T>>)members;
|
||||
return new ConcatenatedListView<>(typed);
|
||||
}
|
||||
|
||||
private final List<? extends List<? extends T>> lists;
|
||||
private final List<List<T>> lists;
|
||||
|
||||
private ConcatenatedListView(List<? extends List<? extends T>> lists)
|
||||
{
|
||||
private ConcatenatedListView(List<List<T>> lists) {
|
||||
this.lists = lists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
public int size() {
|
||||
int size = 0;
|
||||
for (var list : lists)
|
||||
size += list.size();
|
||||
@@ -52,28 +49,26 @@ public class ConcatenatedListView<T> implements List<T>
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (List<? extends T> list : lists)
|
||||
public boolean isEmpty() {
|
||||
for (List<? extends T> list : lists) {
|
||||
if (!list.isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
for (var list : lists)
|
||||
public boolean contains(Object o) {
|
||||
for (var list : lists) {
|
||||
if (list.contains(o))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index)
|
||||
{
|
||||
for (var list : lists)
|
||||
{
|
||||
public T get(int index) {
|
||||
for (var list : lists) {
|
||||
int size = list.size();
|
||||
if (index < size)
|
||||
return list.get(index);
|
||||
@@ -83,11 +78,9 @@ public class ConcatenatedListView<T> implements List<T>
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o)
|
||||
{
|
||||
public int indexOf(Object o) {
|
||||
int offset = 0;
|
||||
for (var list : lists)
|
||||
{
|
||||
for (var list : lists) {
|
||||
int foundIndex = list.indexOf(o);
|
||||
if (foundIndex >= 0)
|
||||
return offset + foundIndex;
|
||||
@@ -97,11 +90,9 @@ public class ConcatenatedListView<T> implements List<T>
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o)
|
||||
{
|
||||
public int lastIndexOf(Object o) {
|
||||
int offset = 0;
|
||||
for (var list : Lists.reverse(lists))
|
||||
{
|
||||
for (var list : Lists.reverse(lists)) {
|
||||
int foundIndex = list.lastIndexOf(o);
|
||||
if (foundIndex >= 0)
|
||||
return offset + foundIndex;
|
||||
@@ -112,20 +103,17 @@ public class ConcatenatedListView<T> implements List<T>
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<T> iterator()
|
||||
{
|
||||
public Iterator<T> iterator() {
|
||||
return Iterables.unmodifiableIterable(Iterables.concat(lists)).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<T> spliterator()
|
||||
{
|
||||
public Spliterator<T> spliterator() {
|
||||
return Iterables.unmodifiableIterable(Iterables.concat(lists)).spliterator();
|
||||
}
|
||||
|
||||
// Delegate to a concatenated collection
|
||||
private <C extends Collection<T>> C concatenate(Supplier<C> collectionFactory)
|
||||
{
|
||||
private <C extends Collection<T>> C concatenate(Supplier<C> collectionFactory) {
|
||||
var concat = collectionFactory.get();
|
||||
for (var list : lists)
|
||||
concat.addAll(list);
|
||||
|
||||
@@ -374,7 +374,7 @@ public class HandshakeHandler
|
||||
});
|
||||
|
||||
// we're done when sentMessages is empty
|
||||
if (sentMessages.isEmpty() && packetPosition >= messageList.size()-1 && pendingFutures.isEmpty()) {
|
||||
if (sentMessages.isEmpty() && packetPosition >= messageList.size() && pendingFutures.isEmpty()) {
|
||||
// clear ourselves - we're done!
|
||||
this.manager.channel().attr(NetworkConstants.FML_HANDSHAKE_HANDLER).set(null);
|
||||
LOGGER.debug(FMLHSMARKER, "Handshake complete!");
|
||||
|
||||
@@ -15,6 +15,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.fml.IExtensionPoint;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -127,11 +128,21 @@ public record ServerStatusPing(
|
||||
return Objects.hash(channels, mods, fmlNetworkVer);
|
||||
}
|
||||
|
||||
private List<Map.Entry<ResourceLocation, ChannelData>> getChannelsForMod(String modId)
|
||||
private HashMap<String, List<Map.Entry<ResourceLocation, ChannelData>>> getChannelsByMod()
|
||||
{
|
||||
return channels.entrySet().stream()
|
||||
.filter(c -> c.getKey().getNamespace().equals(modId))
|
||||
.toList();
|
||||
var ret = new HashMap<String, List<Map.Entry<ResourceLocation, ChannelData>>>();
|
||||
for (var channel : channels.entrySet())
|
||||
{
|
||||
var namespace = channel.getKey().getNamespace();
|
||||
var list = ret.get(namespace);
|
||||
if (list == null)
|
||||
{
|
||||
list = new ArrayList<>();
|
||||
ret.put(namespace, list);
|
||||
}
|
||||
list.add(channel);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<Map.Entry<ResourceLocation, ChannelData>> getNonModChannels()
|
||||
@@ -161,11 +172,12 @@ public record ServerStatusPing(
|
||||
buf.writeBoolean(false); // placeholder for whether we are truncating
|
||||
buf.writeShort(mods.size()); // short so that we can replace it later in case of truncation
|
||||
int writtenCount = 0;
|
||||
var channelsByMod = getChannelsByMod();
|
||||
for (var modEntry : mods.entrySet())
|
||||
{
|
||||
var isIgnoreServerOnly = modEntry.getValue().equals(NetworkConstants.IGNORESERVERONLY);
|
||||
|
||||
var channelsForMod = getChannelsForMod(modEntry.getKey());
|
||||
var channelsForMod = channelsByMod.getOrDefault(modEntry.getKey(), List.of());
|
||||
var channelSizeAndVersionFlag = channelsForMod.size() << 1;
|
||||
if (isIgnoreServerOnly)
|
||||
{
|
||||
|
||||
@@ -331,7 +331,7 @@ public class GameData {
|
||||
if (forgeRegistry != null)
|
||||
forgeRegistry.freeze();
|
||||
LOGGER.debug(REGISTRIES, "Applying holder lookups: {}", registryKey.location());
|
||||
ObjectHolderRegistry.applyObjectHolders(registryKey.location()::equals);
|
||||
ObjectHolderRegistry.applyObjectHolders(registryKey.location());
|
||||
LOGGER.debug(REGISTRIES, "Holder lookups applied: {}", registryKey.location());
|
||||
} catch (Throwable t)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
class ObjectHolderRef implements Consumer<Predicate<ResourceLocation>>
|
||||
class ObjectHolderRef implements Consumer<Predicate<ResourceLocation>>, Runnable
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Field field;
|
||||
@@ -87,7 +87,12 @@ class ObjectHolderRef implements Consumer<Predicate<ResourceLocation>>
|
||||
{
|
||||
if (registry == null || !filter.test(registry.getRegistryName()))
|
||||
return;
|
||||
run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
Object thing;
|
||||
if (registry.containsKey(injectedObject))
|
||||
{
|
||||
|
||||
@@ -7,10 +7,11 @@ package net.minecraftforge.registries;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
@@ -40,12 +41,24 @@ public class ObjectHolderRegistry
|
||||
* The internal list is backed by a HashSet so it is HIGHLY recommended you implement a proper equals
|
||||
* and hashCode function to de-duplicate callers here.
|
||||
* The default @ObjectHolder implementation uses the hashCode/equals for the field the annotation is on.
|
||||
*
|
||||
* @deprecated Use {{@link #addHandler(ResourceLocation, Runnable)} if you are only targeting a single registry
|
||||
*/
|
||||
public static synchronized void addHandler(Consumer<Predicate<ResourceLocation>> ref)
|
||||
{
|
||||
objectHolders.add(ref);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a handler that is run after the named registry has been injected and finalized.
|
||||
* Handlers are kept in a HashSet per registry, so the same instance is only ever registered once.
|
||||
*/
|
||||
public static synchronized void addHandler(ResourceLocation registry, Runnable ref)
|
||||
{
|
||||
namedHandlers.computeIfAbsent(registry, id -> new HashSet<>()).add(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed the specified handler from the notification list.
|
||||
*
|
||||
@@ -60,12 +73,36 @@ public class ObjectHolderRegistry
|
||||
return objectHolders.remove(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a handler registered with {@link #addHandler(ResourceLocation, Runnable)}.
|
||||
*
|
||||
* @return true if handler was matched and removed.
|
||||
*/
|
||||
public static synchronized boolean removeHandler(ResourceLocation registry, Runnable ref)
|
||||
{
|
||||
var handlers = namedHandlers.get(registry);
|
||||
return handlers != null && handlers.remove(ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a check that is run once, before the handlers of the next holder pass.
|
||||
* Used to report holders that point at a registry that does not exist.
|
||||
*/
|
||||
public static synchronized void addValidator(Runnable ref)
|
||||
{
|
||||
validators.add(ref);
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// Everything below is internal, do not use.
|
||||
//==============================================================
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Set<Consumer<Predicate<ResourceLocation>>> objectHolders = new HashSet<>();
|
||||
// Order is not guaranteed, the old implementation kept every handler in one HashSet.
|
||||
private static final Map<ResourceLocation, Set<Runnable>> namedHandlers = new HashMap<>();
|
||||
private static final List<Runnable> validators = new ArrayList<>();
|
||||
|
||||
private static final Type OBJECT_HOLDER = Type.getType(ObjectHolder.class);
|
||||
private static final Type MOD = Type.getType(Mod.class);
|
||||
// Hardcoded list of vanilla classes that should have object holders for each field of the given registry type.
|
||||
@@ -83,48 +120,59 @@ public class ObjectHolderRegistry
|
||||
public static void findObjectHolders()
|
||||
{
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES,"Processing ObjectHolder annotations");
|
||||
final List<ModFileScanData.AnnotationData> annotations = ModList.get().getAllScanData().stream()
|
||||
.map(ModFileScanData::getAnnotations)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(a -> OBJECT_HOLDER.equals(a.annotationType()) || MOD.equals(a.annotationType()))
|
||||
.toList();
|
||||
final HashMap<Type, String> classModIds = new HashMap<>();
|
||||
final List<ModFileScanData.AnnotationData> annotations = new ArrayList<>();
|
||||
|
||||
if (annotations.stream().noneMatch(a -> OBJECT_HOLDER.equals(a.annotationType())))
|
||||
return; // No object holders found, skip the rest of the processing
|
||||
for (var data : ModList.get().getAllScanData()) {
|
||||
for (var annotation : data.getAnnotations()) {
|
||||
if (OBJECT_HOLDER.equals(annotation.annotationType())) {
|
||||
annotations.add(annotation);
|
||||
}
|
||||
// Gather all @Mod classes so that @ObjectHolder's in those classes don't need to specify the mod id; modder convenience
|
||||
else if (MOD.equals(annotation.annotationType())) {
|
||||
classModIds.put(annotation.clazz(), (String)annotation.annotationData().get("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is never actually true as we have an annotation in ConditionalRecipe, but also we want to always run the vanilla holders
|
||||
/*
|
||||
if (annotations.isEmpty()) {
|
||||
return; // No object holders found, skip the rest of the processing,
|
||||
}
|
||||
*/
|
||||
|
||||
Map<Type, String> classModIds = Maps.newHashMap();
|
||||
Map<Type, Class<?>> classCache = Maps.newHashMap();
|
||||
|
||||
// Gather all @Mod classes so that @ObjectHolder's in those classes don't need to specify the mod id; modder convenience
|
||||
annotations.stream()
|
||||
.filter(a -> MOD.equals(a.annotationType()))
|
||||
.forEach(data -> classModIds.put(data.clazz(), (String)data.annotationData().get("value")));
|
||||
|
||||
// Validate all the vanilla class-level object holders then scan those first
|
||||
VANILLA_OBJECT_HOLDERS.forEach(data -> {
|
||||
try
|
||||
{
|
||||
for (var data : VANILLA_OBJECT_HOLDERS) {
|
||||
try {
|
||||
Class<?> holderClass = Class.forName(data.holderClass(), true, ObjectHolderRegistry.class.getClassLoader());
|
||||
Class<?> registryClass = Class.forName(data.registryType(), true, ObjectHolderRegistry.class.getClassLoader());
|
||||
|
||||
Type holderType = Type.getType(holderClass);
|
||||
classCache.put(holderType, holderClass);
|
||||
scanTarget(classModIds, classCache, holderType, null, registryClass, data.registryName(), "minecraft", true, true);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Vanilla class not found, should not be possible", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Scan actual fields annotated with @ObjectHolder second
|
||||
annotations.stream()
|
||||
.filter(a -> OBJECT_HOLDER.equals(a.annotationType())).filter(a -> a.targetType() == ElementType.FIELD)
|
||||
.forEach(data -> scanTarget(classModIds, classCache, data.clazz(),
|
||||
data.memberName(), null, (String)data.annotationData().get("registryName"),
|
||||
(String)data.annotationData().get("value"), false, false));
|
||||
for (var data : annotations) {
|
||||
if (data.targetType() == ElementType.FIELD) {
|
||||
var registry = (String)data.annotationData().get("registryName");
|
||||
var name = (String)data.annotationData().get("value");
|
||||
scanTarget(classModIds, classCache, data.clazz(), data.memberName(), null, registry, name, false, false);
|
||||
}
|
||||
// This is where we WOULD scan for class targets, but Shrimp broke that in 1.19 and so I don't want to re-add a feature that apparently nobody used.
|
||||
}
|
||||
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES,"Found {} ObjectHolder annotations", objectHolders.size());
|
||||
int count = objectHolders.size();
|
||||
for (var set : namedHandlers.values())
|
||||
count += set.size();
|
||||
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES, "Found {} ObjectHolder annotations", count);
|
||||
}
|
||||
|
||||
private static void scanTarget(Map<Type, String> classModIds, Map<Type, Class<?>> classCache, Type type,
|
||||
@@ -149,9 +197,10 @@ public class ObjectHolderRegistry
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
ResourceLocation regName = ResourceLocation.parse(registryName);
|
||||
if (isClass)
|
||||
{
|
||||
scanClassForFields(classModIds, type, new ResourceLocation(registryName), registryClass, value, clazz, extractFromValue);
|
||||
scanClassForFields(classModIds, type, regName, registryClass, value, clazz, extractFromValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -168,9 +217,9 @@ public class ObjectHolderRegistry
|
||||
try
|
||||
{
|
||||
Field f = clazz.getDeclaredField(annotationTarget);
|
||||
ObjectHolderRef ref = ObjectHolderRef.create(new ResourceLocation(registryName), f, value, extractFromValue);
|
||||
ObjectHolderRef ref = ObjectHolderRef.create(regName, f, value, extractFromValue);
|
||||
if (ref != null)
|
||||
addHandler(ref);
|
||||
addHandler(regName, ref);
|
||||
}
|
||||
catch (NoSuchFieldException ex)
|
||||
{
|
||||
@@ -191,7 +240,7 @@ public class ObjectHolderRegistry
|
||||
continue;
|
||||
ObjectHolderRef ref = ObjectHolderRef.create(registryName, f, value + ':' + f.getName().toLowerCase(Locale.ENGLISH), extractFromExistingValues);
|
||||
if (ref != null)
|
||||
addHandler(ref);
|
||||
addHandler(registryName, ref);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,38 +256,115 @@ public class ObjectHolderRegistry
|
||||
throw new IllegalStateException("No registry name was declared for " + declaration);
|
||||
}
|
||||
|
||||
public static void applyObjectHolders()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
private static final Predicate<ResourceLocation> ALWAYS_TRUE = name -> true;
|
||||
public static void applyObjectHolders() {
|
||||
try {
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES, "Applying holder lookups");
|
||||
applyObjectHolders(key -> true);
|
||||
var exceptions = new ArrayList<Exception>();
|
||||
validate(exceptions);
|
||||
// Call named registries
|
||||
for (var handlers : namedHandlers.values())
|
||||
apply(handlers, exceptions);
|
||||
|
||||
// Call legacy for backward compatibility
|
||||
if (!objectHolders.isEmpty())
|
||||
apply(ALWAYS_TRUE, objectHolders, exceptions);
|
||||
|
||||
throwIfNeeded(exceptions);
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES, "Holder lookups applied");
|
||||
} catch (RuntimeException e)
|
||||
{
|
||||
} catch (RuntimeException e) {
|
||||
// It is more important that the calling contexts continue without exception to prevent further cascading errors
|
||||
LOGGER.error("", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #applyObjectHolders(ResourceLocation)}
|
||||
*/
|
||||
public static void applyObjectHolders(Predicate<ResourceLocation> filter)
|
||||
{
|
||||
RuntimeException aggregate = new RuntimeException("Failed to apply some object holders, see suppressed exceptions for details");
|
||||
objectHolders.forEach(objectHolder -> {
|
||||
try
|
||||
{
|
||||
objectHolder.accept(filter);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
aggregate.addSuppressed(e);
|
||||
}
|
||||
});
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES, "Apply filtered holder lookups");
|
||||
var exceptions = new ArrayList<Exception>();
|
||||
validate(exceptions);
|
||||
|
||||
if (aggregate.getSuppressed().length > 0)
|
||||
{
|
||||
throw aggregate;
|
||||
// call new registries if needed
|
||||
for (var entry : namedHandlers.entrySet()) {
|
||||
if (filter.test(entry.getKey())) {
|
||||
apply(entry.getValue(), exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
// Call legacy
|
||||
if (!objectHolders.isEmpty())
|
||||
apply(filter, objectHolders, exceptions);
|
||||
|
||||
throwIfNeeded(exceptions);
|
||||
LOGGER.debug(ForgeRegistry.REGISTRIES, "Holder lookups applied");
|
||||
}
|
||||
|
||||
/** Runs the handlers of one registry. */
|
||||
public static void applyObjectHolders(ResourceLocation registry) {
|
||||
var exceptions = new ArrayList<Exception>();
|
||||
validate(exceptions);
|
||||
|
||||
var handlers = namedHandlers.get(registry);
|
||||
if (handlers != null)
|
||||
apply(handlers, exceptions);
|
||||
|
||||
if (!objectHolders.isEmpty())
|
||||
apply(registry::equals, objectHolders, exceptions);
|
||||
|
||||
throwIfNeeded(exceptions);
|
||||
}
|
||||
|
||||
// Each validator runs once, at the first holder pass after it was registered.
|
||||
private static void validate(List<Exception> exceptions) {
|
||||
List<Runnable> pending;
|
||||
synchronized (ObjectHolderRegistry.class) {
|
||||
if (validators.isEmpty())
|
||||
return;
|
||||
pending = new ArrayList<>(validators);
|
||||
validators.clear();
|
||||
}
|
||||
|
||||
for (var validator : pending) {
|
||||
try {
|
||||
validator.run();
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void apply(Set<Runnable> handlers, List<Exception> exceptions) {
|
||||
for (var handler : handlers) {
|
||||
try {
|
||||
handler.run();
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void apply(Predicate<ResourceLocation> filter, Set<Consumer<Predicate<ResourceLocation>>> handlers, List<Exception> exceptions) {
|
||||
for (var handler : handlers) {
|
||||
try {
|
||||
handler.accept(filter);
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwIfNeeded(List<Exception> exceptions) {
|
||||
if (exceptions.isEmpty())
|
||||
return;
|
||||
|
||||
var aggregate = new RuntimeException("Failed to apply some object holders, see suppressed exceptions for details");
|
||||
for (var e : exceptions)
|
||||
aggregate.addSuppressed(e);
|
||||
throw aggregate;
|
||||
}
|
||||
|
||||
private record VanillaObjectHolderData(String holderClass, String registryName, String registryType) {}
|
||||
|
||||
@@ -26,8 +26,7 @@ public final class RegistryObject<T> implements Supplier<T>
|
||||
@Nullable
|
||||
private final ResourceLocation name;
|
||||
@Nullable
|
||||
private ResourceKey<T> key;
|
||||
private final boolean optionalRegistry;
|
||||
private final ResourceKey<T> key;
|
||||
@Nullable
|
||||
private T value;
|
||||
@Nullable
|
||||
@@ -135,7 +134,6 @@ public final class RegistryObject<T> implements Supplier<T>
|
||||
private RegistryObject() {
|
||||
this.name = null;
|
||||
this.key = null;
|
||||
this.optionalRegistry = false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -145,12 +143,7 @@ public final class RegistryObject<T> implements Supplier<T>
|
||||
throw new IllegalArgumentException("Invalid registry argument, must not be null");
|
||||
this.name = name;
|
||||
this.key = (ResourceKey<T>) ResourceKey.create(registry.getRegistryKey(), name);
|
||||
this.optionalRegistry = false;
|
||||
ObjectHolderRegistry.addHandler(pred ->
|
||||
{
|
||||
if (pred.test(registry.getRegistryName()))
|
||||
this.updateReference((IForgeRegistry<? extends T>) registry);
|
||||
});
|
||||
ObjectHolderRegistry.addHandler(registry.getRegistryName(), () -> this.updateReference((IForgeRegistry<? extends T>) registry));
|
||||
this.updateReference((IForgeRegistry<? extends T>) registry);
|
||||
}
|
||||
|
||||
@@ -158,31 +151,14 @@ public final class RegistryObject<T> implements Supplier<T>
|
||||
{
|
||||
this.name = name;
|
||||
this.key = ResourceKey.create(ResourceKey.createRegistryKey(registryName), name);
|
||||
this.optionalRegistry = optionalRegistry;
|
||||
final Throwable callerStack = new Throwable("Calling Site from mod: " + modid);
|
||||
ObjectHolderRegistry.addHandler(new Consumer<>()
|
||||
{
|
||||
private boolean registryExists = false;
|
||||
private boolean invalidRegistry = false;
|
||||
|
||||
@Override
|
||||
public void accept(Predicate<ResourceLocation> pred)
|
||||
{
|
||||
if (invalidRegistry)
|
||||
return;
|
||||
if (!RegistryObject.this.optionalRegistry && !registryExists)
|
||||
{
|
||||
if (!registryExists(registryName))
|
||||
{
|
||||
invalidRegistry = true;
|
||||
throw new IllegalStateException("Unable to find registry with key " + registryName + " for mod \"" + modid + "\". Check the 'caused by' to see further stack.", callerStack);
|
||||
}
|
||||
registryExists = true;
|
||||
}
|
||||
if (pred.test(registryName))
|
||||
RegistryObject.this.updateReference(registryName);
|
||||
}
|
||||
});
|
||||
if (!optionalRegistry) {
|
||||
final Throwable callerStack = new Throwable("Calling Site from mod: " + modid);
|
||||
ObjectHolderRegistry.addValidator(() -> {
|
||||
if (!registryExists(registryName))
|
||||
throw new IllegalStateException("Unable to find registry with key " + registryName + " for mod \"" + modid + "\". Check the 'caused by' to see further stack.", callerStack);
|
||||
});
|
||||
}
|
||||
ObjectHolderRegistry.addHandler(registryName, () -> this.updateReference(registryName));
|
||||
this.updateReference(registryName);
|
||||
}
|
||||
|
||||
@@ -485,8 +461,8 @@ public final class RegistryObject<T> implements Supplier<T>
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if (obj instanceof RegistryObject) {
|
||||
return Objects.equals(((RegistryObject<?>)obj).name, name);
|
||||
if (obj instanceof RegistryObject o) {
|
||||
return o.key == key && Objects.equals(o.name, name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -247,6 +247,12 @@ public class NewModelLoaderTest
|
||||
.with(BlockStateProperties.HORIZONTAL_FACING, Direction.SOUTH)
|
||||
.addModels(new ConfiguredModel(model, 0, 180, false))
|
||||
.partialState();
|
||||
models().getBuilder("test_forge_data")
|
||||
.texture("all", mcLoc("block/diamond_ore"))
|
||||
.element().from(0.0F, 0.0F, 0.0F).to(16.0F, 16.0F, 16.0F)
|
||||
.allFaces((dir, face) -> face.texture("#all").emissivity(10, 10))
|
||||
.emissivity(15, 15).end()
|
||||
.renderType("cutout");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user