Compare commits

...
12 Commits
Author SHA1 Message Date
LexManos 9c5d527d71 Migrate to Github Actions 2025-12-02 15:54:37 -08:00
Jonathing e70dc0a4b7 Fix Material#isFlammable not being accounted for in flammability (#10573) 2025-07-16 09:47:29 -07:00
JonathingandMarc Hermans e5ad486994 Fix a corner case where the UMLB can not extract a version from a library. (#8967) (#10522)
Co-authored-by: Marc Hermans <[email protected]>
2025-04-06 22:48:50 -05:00
Jonathing 1085852834 Add '#forge:chorus_additionally_grows_on' tag for similar mechanics to '#minecraft:azalea_grows_on' but for chorus (#10465) 2025-03-04 15:15:13 -08:00
JonathingandLexManos 4a16e75a77 Speed up mod annotation scanning by ~30% (#10473)
Co-authored-by: LexManos <[email protected]>
2025-03-04 15:14:43 -08:00
Jonathing 084952a216 Fix continuing to use items after dropping or when a shield breaks (#10383)
Fixes MC-231097 and MC-168573
Cache this.useItem before running item break logic, Fixes #10344
2025-03-04 15:11:49 -08:00
Jonathing 6e55ebe21b Backport even more future ResourceLocation methods (#10431) 2025-02-18 14:30:53 -08:00
Jonathing 1f988d315f Ensure NetworkConstants is loaded before mod construction (#10449) 2025-02-18 14:30:40 -08:00
JonathingandPaint_Ninja 764b334c21 Add clientSideOnly feature to mods.toml (#10085) (backport of #9804 to 1.20.1) (#10368)
Co-authored-by: Paint_Ninja <[email protected]>
2025-02-18 14:30:31 -08:00
Jonathing b018b8f476 Fix incorrect method reference in TntBlock.explode() (#10334) 2025-01-27 20:33:37 -08:00
Jonathing fb7e264a76 Fix issues in VillagerTrades.EmeraldsForVillagerTypeItem related to custom Villager Types (#10361)
Add VillagerType#registerBiomeType
Co-authored-by: Joseph T. McQuigg <[email protected]>
2025-01-27 20:33:27 -08:00
Jonathing f77fa169f8 Fix non-passengers being tickable without checking canUpdate() (#10307) 2025-01-22 14:54:16 -08:00
28 changed files with 360 additions and 367 deletions

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
name: Publish
on:
push:
branches: [ '1.18.x' ]
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 }}
-104
View File
@@ -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>
-208
View File
@@ -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", "17", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("docker_gradle_version", "7.4", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_main_branch", "1.19.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_branch_spec", """
+:refs/heads/(main*)
+:refs/heads/(master*)
+: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()
}
})
+12 -32
View File
@@ -30,19 +30,14 @@ plugins {
id 'de.undercouch.download' version '5.1.3'
id 'net.minecraftforge.gradle.patcher' version '[6.0,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0,6.2)' apply false
id 'net.minecraftforge.gradlejarsigner' version '1.0.4'
}
Util.init() //Init all our extension methods!
jarSigner.autoDetect('forge')
ext {
JAR_SIGNER = null
if (project.hasProperty('keystore')) {
JAR_SIGNER = [
storepass: project.properties.keystoreStorePass,
keypass: project.properties.keystoreKeyPass,
keystore: project.properties.keystore
]
}
MAPPING_CHANNEL = 'official'
MAPPING_VERSION = '1.18.2'
MC_VERSION = '1.18.2'
@@ -343,27 +338,6 @@ def sharedFmlonlyForge = { Project prj ->
changing = true
}
prj.afterEvaluate {
[prj.tasks.universalJar, prj.tasks.installerJar].each { t ->
def signTask = prj.task([type: SignJar, dependsOn: t], "sign${t.name.capitalize()}") {
onlyIf {
JAR_SIGNER != null && t.state.failure == null
}
def jarsigner = JAR_SIGNER == null ? [:] : JAR_SIGNER
alias = 'forge'
storePass = jarsigner.storepass
keyPass = jarsigner.keypass
keyStore = jarsigner.keystore
inputFile = t.archiveFile.get().asFile
outputFile = t.archiveFile.get().asFile
doFirst {
prj.logger.lifecycle('Signing: ' + inputFile)
}
}
t.finalizedBy(signTask)
}
}
prj.tasks.userdevConfig {
def launchPrefix = prj.name == "forge" ? "forge" : "fml"
getArtifacts(prj, prj.configurations.installer, true).each { key, lib -> libraries.add(lib.name) }
@@ -544,6 +518,7 @@ def sharedFmlonlyForge = { Project prj ->
//rename 'run.sh', "run_forge_${VERSION.replace('-', '_').sh"
//rename 'run.bat', "run_forge_${VERSION.replace('-', '_').bat"
}
jarSigner.sign(it)
}
}
}
@@ -658,7 +633,7 @@ project(':fmlonly') {
}
}
task installerJson(type: InstallerJson, dependsOn: 'signUniversalJar') {
task installerJson(type: InstallerJson, dependsOn: universalJar) {
icon = rootProject.file('icon.ico')
packedDependencies = PACKED_DEPS
@@ -1310,7 +1285,7 @@ project(':forge') {
}
}
task installerJson(type: InstallerJson, dependsOn: [launcherJson, genClientBinPatches, applyClientBinPatches, applyServerBinPatches, 'signUniversalJar']) {
task installerJson(type: InstallerJson, dependsOn: [launcherJson, genClientBinPatches, applyClientBinPatches, applyServerBinPatches, universalJar]) {
ext {
// remove :fatjar
BIN_PATCHER = BINPATCH_TOOL.substring(0, BINPATCH_TOOL.length() - 1 - BINPATCH_TOOL.split(':')[3].length())
@@ -1546,9 +1521,10 @@ project(':forge') {
}
}
}
jarSigner.sign(it)
}
task installerJar(type: InstallerJar, dependsOn: [genClientBinPatches, genServerBinPatches, 'signUniversalJar', launcherJson]) {
task installerJar(type: InstallerJar, dependsOn: [genClientBinPatches, genServerBinPatches, universalJar, launcherJson]) {
packedDependencies = PACKED_DEPS
from(extraTxts)
from(rootProject.file('/forge_installer_logo.png')) {
@@ -1609,6 +1585,10 @@ project(':forge') {
}
}
}
tasks.named('checkLicenseMain') {
mustRunAfter 'extractMapped'
}
reobfJar {
tool = FART
@@ -9,6 +9,7 @@ import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.EnumMap;
@@ -58,7 +59,8 @@ public abstract class ModContainer
this.modInfo = info;
this.modLoadingStage = ModLoadingStage.CONSTRUCT;
final String displayTestString = info.getConfig().<String>getConfigElement("displayTest").orElse("MATCH_VERSION"); // missing defaults to DEFAULT type
final String displayTestString = info.getConfig().<String>getConfigElement("displayTest")
.orElseGet(() -> (Boolean) info.getOwningFile().getFileProperties().getOrDefault(ModFileInfo.CLIENT_SIDE_ONLY_PROP, Boolean.FALSE) ? "IGNORE_ALL_VERSION" : "MATCH_VERSION");
Supplier<IExtensionPoint.DisplayTest> displayTestSupplier = switch (displayTestString) {
case "MATCH_VERSION" -> // default displaytest checks for version string match
() -> new IExtensionPoint.DisplayTest(() -> this.modInfo.getVersion().toString(),
@@ -106,16 +106,17 @@ public class UniqueModListBuilder
if (modInfoList.size() > 1) {
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
modInfoList.sort(Comparator.comparing(this::getVersion).reversed());
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), modInfoList.get(0).getModInfos().get(0).getVersion());
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), this.getVersion(modInfoList.get(0)));
}
return modInfoList.get(0);
}
private ArtifactVersion getVersion(final ModFile mf)
{
if (mf.getModFileInfo() == null) {
if (mf.getModFileInfo() == null || mf.getModInfos() == null || mf.getModInfos().isEmpty()) {
return mf.getJarVersion();
}
return mf.getModInfos().get(0).getVersion();
}
@@ -18,4 +18,8 @@ public class InvalidModFileException extends RuntimeException
super(String.format(Locale.ENGLISH, "%s (%s)", message, ((ModFileInfo)modFileInfo).getFile().getFileName()));
this.modFileInfo = modFileInfo;
}
public IModFileInfo getBrokenFile() {
return this.modFileInfo;
}
}
@@ -11,6 +11,7 @@ import cpw.mods.modlauncher.Launcher;
import cpw.mods.modlauncher.api.IModuleLayerManager;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.minecraftforge.fml.loading.EarlyLoadingException;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.LogMarkers;
import net.minecraftforge.fml.loading.UniqueModListBuilder;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
@@ -19,6 +20,8 @@ import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.forgespi.locating.IModLocator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@@ -52,17 +55,40 @@ public class ModDiscoverer {
List<EarlyLoadingException.ExceptionData> discoveryErrorData = new ArrayList<>();
boolean successfullyLoadedMods = true;
boolean distIsDedicatedServer = FMLLoader.getDist().isDedicatedServer();
//Loop all mod locators to get the prime mods to load from.
for (IModLocator locator : modLocatorList) {
try {
LOGGER.debug(LogMarkers.SCAN,"Trying locator {}", locator);
var locatedFiles = locator.scanMods();
if (locatedFiles.stream().anyMatch(file -> !(file instanceof ModFile))) {
LOGGER.error(LogMarkers.SCAN, "A mod locator returned a file which is not a ModFile instance!. They will be skipped!");
// Backported from 1.19.2 so we don't accidentally process any bad mod files when getting client-only mods
var badModFiles = locatedFiles.stream().filter(file -> !(file instanceof ModFile)).toList();
if (!badModFiles.isEmpty()) {
LOGGER.error(LogMarkers.SCAN, "Locator {} returned {} files which is are not ModFile instances! They will be skipped!", locator, badModFiles.size());
locatedFiles.removeAll(badModFiles);
}
if (distIsDedicatedServer) {
var clientOnlyModFiles = locatedFiles.stream()
.filter(file -> {
// some mod files can have null infos, like javafml, mclanguage, lowcode, and fmlcore
@Nullable var info = file.getModFileInfo();
return info != null && (Boolean) info.getFileProperties().getOrDefault(ModFileInfo.CLIENT_SIDE_ONLY_PROP, Boolean.FALSE);
})
.toList();
if (!clientOnlyModFiles.isEmpty()) {
LOGGER.warn(LogMarkers.SCAN, "Locator {} returned {} files which are client-side-only mods, but we're on a dedicated server. They will be skipped!", locator, clientOnlyModFiles.size());
locatedFiles.removeAll(clientOnlyModFiles);
}
}
LOGGER.debug(LogMarkers.SCAN, "Locator {} found {} valid mod files", locator, locatedFiles.size());
handleLocatedFiles(loadedFiles, locatedFiles);
} catch (InvalidModFileException imfe) {
// We don't generally expect this exception, since it should come from the candidates stream above and be handled in the Locator, but just in case.
LOGGER.error(LogMarkers.SCAN, "Locator {} found an invalid mod file {}", locator, imfe.getBrokenFile(), imfe);
} catch (EarlyLoadingException exception) {
LOGGER.error(LogMarkers.SCAN, "Failed to load mods with locator {}", locator, exception);
discoveryErrorData.addAll(exception.getAllData());
@@ -43,6 +43,10 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
private final String license;
private final List<String> usesServices;
public static final String CLIENT_SIDE_ONLY_PROP = "__FORGE_clientSideOnly";
private static final Map<String, Object> CLIENT_SIDE_ONLY_MAP = Map.of(CLIENT_SIDE_ONLY_PROP, Boolean.TRUE);
ModFileInfo(final ModFile modFile, final IConfigurable config)
{
this.modFile = modFile;
@@ -56,8 +60,21 @@ public class ModFileInfo implements IModFileInfo, IConfigurable
this.license = config.<String>getConfigElement("license")
.orElse("");
this.showAsResourcePack = config.<Boolean>getConfigElement("showAsResourcePack").orElse(false);
boolean clientSideOnly = config.<Boolean>getConfigElement("clientSideOnly").orElse(false);
this.usesServices = config.<List<String>>getConfigElement("services").orElse(List.of());
this.properties = config.<Map<String, Object>>getConfigElement("properties").orElse(Collections.emptyMap());
var maybeProps = config.<Map<String, Object>>getConfigElement("properties");
if (clientSideOnly) {
if (maybeProps.isPresent()) {
this.properties = new HashMap<>(maybeProps.get());
this.properties.put(CLIENT_SIDE_ONLY_PROP, Boolean.TRUE);
} else {
this.properties = CLIENT_SIDE_ONLY_MAP;
}
} else {
this.properties = maybeProps.orElse(Collections.emptyMap());
}
this.modFile.setFileProperties(this.properties);
this.issueURL = config.<String>getConfigElement("issueTrackerURL").map(StringUtils::toURL).orElse(null);
final List<? extends IConfigurable> modConfigs = config.getConfigList("mods");
@@ -45,7 +45,7 @@ public class Scanner {
try (InputStream in = Files.newInputStream(path)){
ModClassVisitor mcv = new ModClassVisitor();
ClassReader cr = new ClassReader(in);
cr.accept(mcv, 0);
cr.accept(mcv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
mcv.buildData(result.getClasses(), result.getAnnotations());
} catch (IOException | IllegalArgumentException e) {
// mark path bad
+4 -1
View File
@@ -12,6 +12,9 @@ loaderVersion="${loader_version_range}" #mandatory This is typically bumped ever
license="${mod_license}"
# A URL to refer people to when problems occur with this mod
#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
# If your mod is purely client-side and has no multiplayer functionality (be it dedicated servers or Open to LAN),
# set this to true, and Forge will set the correct displayTest for you and skip loading your mod on dedicated servers.
#clientSideOnly=true #optional - defaults to false if absent
# A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory
# The modid of the mod
@@ -36,7 +39,7 @@ authors="${mod_authors}" #optional
# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component.
# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value.
# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself.
#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional)
#displayTest="MATCH_VERSION" # if nothing is specified, MATCH_VERSION is the default when clientSideOnly=false, otherwise IGNORE_ALL_VERSION when clientSideOnly=true (#optional)
# The description text for the mod (multi line!) (#mandatory)
description='''${mod_description}'''
@@ -8,6 +8,14 @@
return false;
}
@@ -266,6 +_,7 @@
public boolean m_108700_(boolean p_108701_) {
ServerboundPlayerActionPacket.Action serverboundplayeractionpacket$action = p_108701_ ? ServerboundPlayerActionPacket.Action.DROP_ALL_ITEMS : ServerboundPlayerActionPacket.Action.DROP_ITEM;
+ if (m_6117_() && m_7655_() == InteractionHand.MAIN_HAND && (p_108701_ || m_21211_().m_41613_() == 1)) m_5810_(); // Forge: fix MC-231097 on the clientside
ItemStack itemstack = this.m_150109_().m_182403_(p_108701_);
this.f_108617_.m_104955_(new ServerboundPlayerActionPacket(serverboundplayeractionpacket$action, BlockPos.f_121853_, Direction.DOWN));
return !itemstack.m_41619_();
@@ -461,6 +_,11 @@
}
@@ -1,18 +1,26 @@
--- a/net/minecraft/resources/ResourceLocation.java
+++ b/net/minecraft/resources/ResourceLocation.java
@@ -38,10 +_,12 @@
@@ -38,14 +_,20 @@
}
}
+ /** Forge: Consider using {@link #parse(String)} instead, as Mojang made this constructor private in Vanilla 1.21 */
+ /** @deprecated Forge: Consider using {@link #parse(String)} instead, as Mojang made this constructor private in 1.21 */
+ @Deprecated(forRemoval = true, since = "1.20.6")
public ResourceLocation(String p_135809_) {
this(m_135832_(p_135809_, ':'));
}
+ /** Forge: Consider using {@link #fromNamespaceAndPath(String, String)} instead, as Mojang made this constructor private in Vanilla 1.21 */
+ /** @deprecated Forge: Consider using {@link #fromNamespaceAndPath(String, String)} instead, as Mojang made this constructor private in 1.21 */
+ @Deprecated(forRemoval = true, since = "1.20.6")
public ResourceLocation(String p_135811_, String p_135812_) {
this(new String[]{p_135811_, p_135812_});
}
+ /** @deprecated Forge: Consider using {@link #bySeparator(String, char)} instead, as Mojang removed this method in 1.21 */
+ @Deprecated(forRemoval = true, since = "1.20.6")
public static ResourceLocation m_135822_(String p_135823_, char p_135824_) {
return new ResourceLocation(m_135832_(p_135823_, p_135824_));
}
@@ -116,6 +_,12 @@
return i;
}
@@ -26,19 +34,121 @@
public String m_179910_() {
return this.toString().replace('/', '_').replace(':', '_');
}
@@ -182,5 +_,15 @@
@@ -182,5 +_,117 @@
public JsonElement serialize(ResourceLocation p_135855_, Type p_135856_, JsonSerializationContext p_135857_) {
return new JsonPrimitive(p_135855_.toString());
}
+ }
+
+ /** Forge: Backport of Vanilla 1.21 method */
+ // FORGE: BACKPORTS FROM 1.21
+
+ /** Forge: This is a backported method from 1.21, and is the replacement for {@link #ResourceLocation(String, String)}. */
+ public static ResourceLocation fromNamespaceAndPath(String namespace, String path) {
+ return new ResourceLocation(namespace, path);
+ }
+
+ /** Forge: Backport of Vanilla 1.21 method */
+ /** Forge: This is a backported method from 1.21, and is the replacement for {@link #ResourceLocation(String)}. */
+ public static ResourceLocation parse(String location) {
+ return new ResourceLocation(location);
+ }
+
+ /**
+ * Forge: This is a backported method from 1.21, and acts as an alternative to using {@link #parse(String)}. If you
+ * know for sure you are going to be using the {@linkplain #DEFAULT_NAMESPACE default namespace}
+ * ({@code "minecraft"}), use this.
+ */
+ public static ResourceLocation withDefaultNamespace(String path) {
+ return new ResourceLocation(f_179908_, assertValidPath(f_179908_, path), null);
+ }
+
+ /** Forge: This is a backported method from 1.21, and is the replacement for {@link #of(String, char)}. */
+ public static ResourceLocation bySeparator(String location, char separator) {
+ return m_135822_(location, separator);
+ }
+
+ /**
+ * Forge: This is a backported method from 1.21, and is the same as {@link #bySeparator(String, char)} but returns
+ * {@code null} if a resource location cannot be created.
+ */
+ public static @Nullable ResourceLocation tryBySeparator(String location, char separator) {
+ int i = location.indexOf(separator);
+ if (i >= 0) {
+ String s = location.substring(i + 1);
+ if (!m_135841_(s)) {
+ return null;
+ } else if (i != 0) {
+ String s1 = location.substring(0, i);
+ return m_135843_(s1) ? new ResourceLocation(s1, s, null) : null;
+ } else {
+ return new ResourceLocation(f_179908_, s, null);
+ }
+ } else {
+ return m_135841_(location) ? new ResourceLocation(f_179908_, location, null) : null;
+ }
+ }
+
+ // FORGE: BACKPORTS FROM 1.19.3
+
+ /** Forge: Dummy for {@link #ResourceLocation(String, String, ForgeDummy)} */
+ private interface ForgeDummy { }
+
+ /** Forge: Backported constructor from 1.19.3, which skips additional validations. */
+ private ResourceLocation(String namespace, String path, @Nullable ForgeDummy dummy) {
+ this.f_135804_ = namespace;
+ this.f_135805_ = path;
+ }
+
+ /** Forge: Backported method from 1.19.3 to handle path assertion without needing to use the constructor. */
+ private static String assertValidPath(String namespace, String path) {
+ if (!m_135841_(path)) {
+ throw new ResourceLocationException("Non [a-z0-9/._-] character in path of location: " + namespace + ":" + path);
+ } else {
+ return path;
+ }
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a new resource location with a different path. */
+ public ResourceLocation withPath(String path) {
+ return new ResourceLocation(this.f_135804_, assertValidPath(this.f_135804_, path), null);
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a new resource location with a modified path. */
+ public ResourceLocation withPath(java.util.function.UnaryOperator<String> pathFunction) {
+ return this.withPath(pathFunction.apply(this.f_135805_));
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a new resource location with a prefixed path. */
+ public ResourceLocation withPrefix(String prefix) {
+ return this.withPath(prefix + this.f_135805_);
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a new resource location with a suffixed path. */
+ public ResourceLocation withSuffix(String suffix) {
+ return this.withPath(this.f_135805_ + suffix);
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a language key with a prefix and a suffix. */
+ public String toLanguageKey(String prefix, String suffix) {
+ return this.toLanguageKey(prefix) + "." + suffix;
+ }
+
+ // FORGE: BACKPORTS FROM 1.19
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a language key. */
+ public String toLanguageKey() {
+ return this.f_135804_ + "." + this.f_135805_;
+ }
+
+ /**
+ * Forge: This is a backported method from 1.19.3, can be used to quickly create a language key, skipping the
+ * namespace if it is {@code "minecraft"}.
+ */
+ public String toShortLanguageKey() {
+ return this.f_135804_.equals("minecraft") ? this.f_135805_ : this.toLanguageKey();
+ }
+
+ /** Forge: This is a backported method from 1.19.3, can be used to quickly create a language key with a prefix. */
+ public String toLanguageKey(String prefix) {
+ return prefix + "." + this.toLanguageKey();
}
}
@@ -1,10 +1,15 @@
--- a/net/minecraft/server/Bootstrap.java
+++ b/net/minecraft/server/Bootstrap.java
@@ -55,6 +_,8 @@
@@ -55,6 +_,13 @@
CauldronInteraction.m_175649_();
ArgumentTypes.m_121586_();
Registry.m_206101_();
+ net.minecraftforge.registries.GameData.vanillaSnapshot();
+ // Forge: Hacky fix to ensure that NetworkConstants is loaded before mods are constructed.
+ // Many older mods use network internals that shouldn't be used, yet are exposed so they get used anyways.
+ // This can cause class-loading issues with ForgeMod loading NetworkConstants and HandshakeResolver.
+ // To ensure that doesn't happen, we load it here and now. This is not an issue in 1.20.2 and newer.
+ net.minecraftforge.network.NetworkHooks.init();
+ if (false) // skip redirectOutputToLog, Forge already redirects stdout and stderr output to log so that they print with more context
m_135890_();
}
@@ -84,6 +84,14 @@
}
}
@@ -640,6 +_,7 @@
return Registry.f_122826_.m_7981_(p_8648_.m_6095_()).toString();
});
profilerfiller.m_6174_("tickNonPassenger");
+ if (p_8648_.canUpdate())
p_8648_.m_8119_();
this.m_46473_().m_7238_();
@@ -656,9 +_,10 @@
++p_8664_.f_19797_;
ProfilerFiller profilerfiller = this.m_46473_();
@@ -240,12 +240,13 @@
public TextFilter m_8967_() {
return this.f_8939_;
}
@@ -1511,11 +_,13 @@
@@ -1511,11 +_,14 @@
public boolean m_182294_(boolean p_182295_) {
Inventory inventory = this.m_150109_();
+ ItemStack selected = inventory.m_36056_();
+ if (selected.m_41619_() || !selected.onDroppedByPlayer(this)) return false;
+ if (m_6117_() && m_7655_() == InteractionHand.MAIN_HAND && (p_182295_ || selected.m_41613_() == 1)) m_5810_(); // Forge: fix MC-231097 on the serverside
ItemStack itemstack = inventory.m_182403_(p_182295_);
this.f_36096_.m_182417_(inventory, inventory.f_35977_).ifPresent((p_182293_) -> {
this.f_36096_.m_150404_(p_182293_, inventory.m_36056_());
@@ -0,0 +1,21 @@
--- a/net/minecraft/world/entity/npc/VillagerTrades.java
+++ b/net/minecraft/world/entity/npc/VillagerTrades.java
@@ -151,6 +_,7 @@
private final int f_35667_;
public EmeraldsForVillagerTypeItem(int p_35669_, int p_35670_, int p_35671_, Map<VillagerType, Item> p_35672_) {
+ if (false) // FORGE: Modders can add custom villager types, so remove this validation
Registry.f_122868_.m_123024_().filter((p_35680_) -> {
return !p_35672_.containsKey(p_35680_);
}).findAny().ifPresent((p_35677_) -> {
@@ -165,7 +_,9 @@
@Nullable
public MerchantOffer m_5670_(Entity p_35674_, Random p_35675_) {
if (p_35674_ instanceof VillagerDataHolder) {
- ItemStack itemstack = new ItemStack(this.f_35664_.get(((VillagerDataHolder)p_35674_).m_7141_().m_35560_()), this.f_35665_);
+ Item item = this.f_35664_.get(((VillagerDataHolder)p_35674_).m_7141_().m_35560_());
+ if (item == null) return null; // FORGE: Account for modded villager types by returning null if there is no trade
+ ItemStack itemstack = new ItemStack(item, this.f_35665_);
return new MerchantOffer(itemstack, new ItemStack(Items.f_42616_), this.f_35666_, this.f_35667_, 0.05F);
} else {
return null;
@@ -0,0 +1,12 @@
--- a/net/minecraft/world/entity/npc/VillagerType.java
+++ b/net/minecraft/world/entity/npc/VillagerType.java
@@ -65,4 +_,9 @@
public static VillagerType m_204073_(Holder<Biome> p_204074_) {
return p_204074_.m_203543_().map(f_35827_::get).orElse(f_35821_);
}
+
+ /** FORGE: Registers the VillagerType that will spawn in the given biome. This method should be called during FMLCommonSetupEvent using event.enqueueWork() */
+ public static void registerBiomeType(ResourceKey<Biome> biomeKey, VillagerType villagerType) {
+ f_35827_.put(biomeKey, villagerType);
+ }
}
@@ -135,14 +135,23 @@
if (!this.f_19853_.f_46443_) {
this.m_36246_(Stats.f_12982_.m_12902_(this.f_20935_.m_41720_()));
}
@@ -859,6 +_,7 @@
@@ -857,10 +_,15 @@
if (p_36383_ >= 3.0F) {
int i = 1 + Mth.m_14143_(p_36383_);
InteractionHand interactionhand = this.m_7655_();
+ // FORGE: cache this.useItem -- if this.stopUsingItem() is called, it will be set to ItemStack.EMPTY
+ ItemStack currentItem = this.f_20935_;
this.f_20935_.m_41622_(i, this, (p_36149_) -> {
p_36149_.m_21190_(interactionhand);
+ net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(this, this.f_20935_, interactionhand);
+ if (this.f_20935_ == currentItem) this.m_5810_(); // Forge: fix MC-168573
});
if (this.f_20935_.m_41619_()) {
- if (this.f_20935_.m_41619_()) {
+ // FORGE: use cached item since this.useItem could be ItemStack.EMPTY
+ if (currentItem.m_41619_()) {
if (interactionhand == InteractionHand.MAIN_HAND) {
this.m_8061_(EquipmentSlot.MAINHAND, ItemStack.f_41583_);
} else {
@@ -877,10 +_,13 @@
protected void m_6475_(DamageSource p_36312_, float p_36313_) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/block/ChorusFlowerBlock.java
+++ b/net/minecraft/world/level/block/ChorusFlowerBlock.java
@@ -43,7 +_,7 @@
@@ -43,11 +_,11 @@
BlockPos blockpos = p_51704_.m_7494_();
if (p_51703_.m_46859_(blockpos) && blockpos.m_123342_() < p_51703_.m_151558_()) {
int i = p_51702_.m_61143_(f_51647_);
@@ -9,6 +9,20 @@
boolean flag = false;
boolean flag1 = false;
BlockState blockstate = p_51703_.m_8055_(p_51704_.m_7495_());
- if (blockstate.m_60713_(Blocks.f_50259_)) {
+ if (blockstate.m_60713_(Blocks.f_50259_) || blockstate.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON)) {
flag = true;
} else if (blockstate.m_60713_(this.f_51648_)) {
int j = 1;
@@ -55,7 +_,7 @@
for(int k = 0; k < 4; ++k) {
BlockState blockstate1 = p_51703_.m_8055_(p_51704_.m_6625_(j + 1));
if (!blockstate1.m_60713_(this.f_51648_)) {
- if (blockstate1.m_60713_(Blocks.f_50259_)) {
+ if (blockstate1.m_60713_(Blocks.f_50259_) || blockstate1.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON)) {
flag1 = true;
}
break;
@@ -99,7 +_,7 @@
} else {
this.m_51658_(p_51703_, p_51704_);
@@ -18,3 +32,12 @@
}
}
}
@@ -134,7 +_,7 @@
public boolean m_7898_(BlockState p_51683_, LevelReader p_51684_, BlockPos p_51685_) {
BlockState blockstate = p_51684_.m_8055_(p_51685_.m_7495_());
- if (!blockstate.m_60713_(this.f_51648_) && !blockstate.m_60713_(Blocks.f_50259_)) {
+ if (!blockstate.m_60713_(this.f_51648_) && !blockstate.m_60713_(Blocks.f_50259_) && !blockstate.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON)) {
if (!blockstate.m_60795_()) {
return false;
} else {
@@ -0,0 +1,36 @@
--- a/net/minecraft/world/level/block/ChorusPlantBlock.java
+++ b/net/minecraft/world/level/block/ChorusPlantBlock.java
@@ -30,7 +_,7 @@
BlockState blockstate3 = p_51711_.m_8055_(p_51712_.m_142126_());
BlockState blockstate4 = p_51711_.m_8055_(p_51712_.m_142128_());
BlockState blockstate5 = p_51711_.m_8055_(p_51712_.m_142125_());
- return this.m_49966_().m_61124_(f_55153_, Boolean.valueOf(blockstate.m_60713_(this) || blockstate.m_60713_(Blocks.f_50491_) || blockstate.m_60713_(Blocks.f_50259_))).m_61124_(f_55152_, Boolean.valueOf(blockstate1.m_60713_(this) || blockstate1.m_60713_(Blocks.f_50491_))).m_61124_(f_55148_, Boolean.valueOf(blockstate2.m_60713_(this) || blockstate2.m_60713_(Blocks.f_50491_))).m_61124_(f_55149_, Boolean.valueOf(blockstate3.m_60713_(this) || blockstate3.m_60713_(Blocks.f_50491_))).m_61124_(f_55150_, Boolean.valueOf(blockstate4.m_60713_(this) || blockstate4.m_60713_(Blocks.f_50491_))).m_61124_(f_55151_, Boolean.valueOf(blockstate5.m_60713_(this) || blockstate5.m_60713_(Blocks.f_50491_)));
+ return this.m_49966_().m_61124_(f_55153_, Boolean.valueOf(blockstate.m_60713_(this) || blockstate.m_60713_(Blocks.f_50491_) || blockstate.m_60713_(Blocks.f_50259_) || blockstate.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON))).m_61124_(f_55152_, Boolean.valueOf(blockstate1.m_60713_(this) || blockstate1.m_60713_(Blocks.f_50491_))).m_61124_(f_55148_, Boolean.valueOf(blockstate2.m_60713_(this) || blockstate2.m_60713_(Blocks.f_50491_))).m_61124_(f_55149_, Boolean.valueOf(blockstate3.m_60713_(this) || blockstate3.m_60713_(Blocks.f_50491_))).m_61124_(f_55150_, Boolean.valueOf(blockstate4.m_60713_(this) || blockstate4.m_60713_(Blocks.f_50491_))).m_61124_(f_55151_, Boolean.valueOf(blockstate5.m_60713_(this) || blockstate5.m_60713_(Blocks.f_50491_)));
}
public BlockState m_7417_(BlockState p_51728_, Direction p_51729_, BlockState p_51730_, LevelAccessor p_51731_, BlockPos p_51732_, BlockPos p_51733_) {
@@ -38,7 +_,7 @@
p_51731_.m_186460_(p_51732_, this, 1);
return super.m_7417_(p_51728_, p_51729_, p_51730_, p_51731_, p_51732_, p_51733_);
} else {
- boolean flag = p_51730_.m_60713_(this) || p_51730_.m_60713_(Blocks.f_50491_) || p_51729_ == Direction.DOWN && p_51730_.m_60713_(Blocks.f_50259_);
+ boolean flag = p_51730_.m_60713_(this) || p_51730_.m_60713_(Blocks.f_50491_) || p_51729_ == Direction.DOWN && (p_51730_.m_60713_(Blocks.f_50259_) || p_51730_.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON));
return p_51728_.m_61124_(f_55154_.get(p_51729_), Boolean.valueOf(flag));
}
}
@@ -63,13 +_,13 @@
}
BlockState blockstate2 = p_51725_.m_8055_(blockpos.m_7495_());
- if (blockstate2.m_60713_(this) || blockstate2.m_60713_(Blocks.f_50259_)) {
+ if (blockstate2.m_60713_(this) || blockstate2.m_60713_(Blocks.f_50259_) || blockstate2.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON)) {
return true;
}
}
}
- return blockstate.m_60713_(this) || blockstate.m_60713_(Blocks.f_50259_);
+ return blockstate.m_60713_(this) || blockstate.m_60713_(Blocks.f_50259_) || blockstate.m_204336_(net.minecraftforge.common.Tags.Blocks.CHORUS_ADDITIONALLY_GROWS_ON);
}
protected void m_7926_(StateDefinition.Builder<Block, BlockState> p_51735_) {
@@ -38,12 +38,12 @@
}
}
+ @Deprecated //Forge: Prefer using IForgeBlock#catchFire
+ @Deprecated //Forge: Prefer using IForgeBlock#onCaughtFire
public static void m_57433_(Level p_57434_, BlockPos p_57435_) {
m_57436_(p_57434_, p_57435_, (LivingEntity)null);
}
+ @Deprecated //Forge: Prefer using IForgeBlock#catchFire
+ @Deprecated //Forge: Prefer using IForgeBlock#onCaughtFire
private static void m_57436_(Level p_57437_, BlockPos p_57438_, @Nullable LivingEntity p_57439_) {
if (!p_57437_.f_46443_) {
PrimedTnt primedtnt = new PrimedTnt(p_57437_, (double)p_57438_.m_123341_() + 0.5D, (double)p_57438_.m_123342_(), (double)p_57438_.m_123343_() + 0.5D, p_57439_);
@@ -0,0 +1,5 @@
{
"values": [
"#forge:end_stones"
]
}
@@ -148,7 +148,6 @@ public class ForgeMod
return uuid.toString();
});
LOGGER.debug(FORGEMOD, "Loading Network data for FML net version: {}", NetworkConstants.init());
CrashReportCallables.registerCrashCallable("FML", ForgeVersion::getSpec);
CrashReportCallables.registerCrashCallable("Forge", ()->ForgeVersion.getGroup()+":"+ForgeVersion.getVersion());
@@ -45,6 +45,7 @@ public class Tags
public static final TagKey<Block> CHESTS_ENDER = tag("chests/ender");
public static final TagKey<Block> CHESTS_TRAPPED = tag("chests/trapped");
public static final TagKey<Block> CHESTS_WOODEN = tag("chests/wooden");
public static final TagKey<Block> CHORUS_ADDITIONALLY_GROWS_ON = tag("chorus_additionally_grows_on");
public static final TagKey<Block> COBBLESTONE = tag("cobblestone");
public static final TagKey<Block> COBBLESTONE_NORMAL = tag("cobblestone/normal");
public static final TagKey<Block> COBBLESTONE_INFESTED = tag("cobblestone/infested");
@@ -39,6 +39,7 @@ public final class ForgeBlockTagsProvider extends BlockTagsProvider
tag(CHESTS_ENDER).add(Blocks.ENDER_CHEST);
tag(CHESTS_TRAPPED).add(Blocks.TRAPPED_CHEST);
tag(CHESTS_WOODEN).add(Blocks.CHEST, Blocks.TRAPPED_CHEST);
tag(CHORUS_ADDITIONALLY_GROWS_ON).addTags(END_STONES);
tag(COBBLESTONE).addTags(COBBLESTONE_NORMAL, COBBLESTONE_INFESTED, COBBLESTONE_MOSSY, COBBLESTONE_DEEPSLATE);
tag(COBBLESTONE_NORMAL).add(Blocks.COBBLESTONE);
tag(COBBLESTONE_INFESTED).add(Blocks.INFESTED_COBBLESTONE);
@@ -550,7 +550,7 @@ public interface IForgeBlock
*/
default boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction)
{
return state.getFlammability(level, pos, direction) > 0;
return state.getMaterial().isFlammable() && state.getFlammability(level, pos, direction) > 0;
}
/**
@@ -47,6 +47,11 @@ public class NetworkHooks
{
private static final Logger LOGGER = LogManager.getLogger();
public static void init()
{
LOGGER.debug("Loading Network data for FML net version: {}", NetworkConstants.init());
}
public static String getFMLVersion(final String ip)
{
return ip.contains("\0") ? Objects.equals(ip.split("\0")[1], NetworkConstants.NETVERSION) ? NetworkConstants.NETVERSION : ip.split("\0")[1] : NetworkConstants.NOVERSION;