Compare commits

...
105 Commits
Author SHA1 Message Date
LexManos b2d42fa577 1.19.2 RB 4
https://forums.minecraftforge.net/topic/149548-forge-434-minecraft-1192/
2024-06-06 15:04:11 -07:00
LexManos 1b5c118ec2 Update Gradle to 8.8 2024-06-06 14:37:37 -07:00
Paint_NinjaandJ-RAP d399884186 Fix NPE when acceptableValues in defineInList() does not allow nulls, fixes #9300, backport of #9903 (#9909)
Co-authored-by: J-RAP <[email protected]>
2024-04-18 21:41:55 +01:00
Paint_Ninja 091cc791b6 Optimise capabilities a tad, backport of #9886 (#9918) 2024-04-18 21:18:36 +01:00
Paint_Ninja c921aeec50 Make common config screen registration tasks easier, backport of #9884 (#9914) 2024-04-18 21:18:16 +01:00
Paint_Ninja f4aea1d8df Bump ASM, fix userdev, fix crowdin (#9925) 2024-04-18 19:57:21 +01:00
J-RAP ad271df245 Bump some deps (#9878)
- CoreMods 5.0.1 -> 5.1.2
- ASM 9.5 -> 9.6
- Installer 2.1 -> 2.2
- Installer tools 1.3.0 -> 1.4.1
2024-03-10 21:25:19 +00:00
Jonathan Colmenares 39dc348f8b Fix TagsProvider not honoring replace attribute (#9865) 2024-02-10 16:02:14 -08:00
Paint_Ninja 75eedc04a1 Make common DisplayTest registration tasks easier (#9838)
Backport of #9822 to 1.19.2
2023-12-31 15:37:33 +00:00
Paint_Ninja 81f99b0116 Optimise ForgeConfigSpec and make Range public (#9827)
Backport of #9810 to 1.19.2
2023-12-30 21:16:43 +00:00
Paint_Ninja f0a7a457bb Update to FG6 and Gradle 8, backport 1.20 MDK (#9754) 2023-11-02 13:41:09 -07:00
Paint_NinjaandSu5eD cf454b7da8 Improve mod description formatting in mods screen (#9771)
Co-authored-by: Su5eD <[email protected]>
2023-11-02 13:40:46 -07:00
Paint_Ninja afcce7d4e7 Backport CrashReportAnalyser to 1.19.2 (#9758) 2023-11-02 13:40:30 -07:00
Paint_Ninjaandembeddedt d4a2fbffa3 Optimise path filter in mod loading (#9712)
Co-authored-by: embeddedt <[email protected]>
2023-09-28 16:40:49 -07:00
Paint_NinjaandJab125 4b61de2088 Improve mod loading error message for errors inside mod constructors (#9709)
Co-authored-by: Jab125 <[email protected]>
2023-09-28 16:40:36 -07:00
LexManos bc2d0d1b25 1.19.2 RB 3 2023-09-21 11:59:41 -07:00
Paint_Ninja e2c1da98be Fix Level leak in debug HUD (#9701) 2023-09-03 11:03:37 -07:00
Paint_Ninjaanddhyces 0f6d11b1ee Keep order of sources in PackRepository (#9704)
Co-authored-by: dhyces <[email protected]>
2023-09-02 16:21:33 -07:00
Jonathan Colmenares 340d332e19 Fix parameter names in IForgeDimensionSpecialEffects.adjustLightmapColors to better describe what they are. (#9658) 2023-07-17 09:45:45 -07:00
Jonathan Colmenares 56f19dd53d Re-add in-game mod menu (#9655) 2023-07-17 08:51:03 -07:00
brandon3055 1fe420e4ab Fixed FluidUtil#tryFillContainer returning invalid result when simulating (#9358) 2023-07-15 10:52:57 -07:00
bconlon 945209c283 AlterGroundEvent for modifying block placement performed by AlterGroundDecorator (#9635) 2023-07-13 17:32:31 -07:00
embeddedt 3e5c3cabd5 Bump ASM to 9.5 (#9516) 2023-07-11 09:26:12 -07:00
Paint_Ninja b0f5a13f52 Improve logging for server connections (#9623) 2023-07-11 09:25:56 -07:00
Paint_Ninja 15fe8441f0 Log a proper duplicate mod(s) error message (#9625) 2023-07-11 09:25:42 -07:00
Brennan Ward babef71616 Fix erroneous getLevel call when firing SpecialSpawn (#9520) 2023-06-07 13:22:00 +00:00
Brennan Ward 1dd18ca27c [1.19.2] Fix the rest of the spawn event calls (#9482) 2023-05-31 11:52:38 +00:00
TelepathicGrunt 65c7390874 Loosen access for BucketItem's canBlockContainFluid (#9429) 2023-05-29 19:16:05 +00:00
Brennan WardandBrennan Ward fe3ad3b8f2 Fix event result being ignored (#9484)
Co-authored-by: Brennan Ward <[email protected]>
2023-05-08 22:52:15 +01:00
Brennan WardandBrennan Ward d05e76f7c4 Fix incorrect SpecialSpawn fire location (#9480)
Co-authored-by: Brennan Ward <[email protected]>
2023-05-03 07:08:07 +01:00
SizableShrimp bfa97bf097 [1.19.2] Fix forge grindstone hooks allowing stacks of non-stackable items (#9466) 2023-05-01 18:39:56 -05:00
Dennis C 469e9a6c1a Fix JSON model root transforms (#9411) 2023-03-22 11:09:58 +01:00
ferriarnus 58456c85af Fix StemBlock not checking canSustainPlant for the correct block
It now checks for Melons/Pumpkins instead of the stem itself.
2023-03-15 11:50:31 -07:00
cech12 7fe5b02ef3 Fix of inconsistent vaporization in BucketItem & FluidType (#9340) 2023-02-24 13:18:43 -08:00
SizableShrimp 184392e02e Backport ClientChatReceivedEvent.System for 1.19.2. Fixes #9352 (#9355) 2023-02-24 10:47:07 -08:00
Jonathan Colmenares d25a5466db Fire TickEvent.LevelTickEvent on ClientLevel tick (#9302) 2023-01-25 13:41:46 -08:00
Dennis C b5073c10ef Disable guiLight3d for generated item models (#9231) 2022-12-30 17:59:43 +01:00
sciwhiz12 16bc7cf783 Fix config key used by resource cache (#9253)
This bring it in line with the config key defined in the spec and
default config file in ResourceManagerBootCacheConfigurationHandler.

Fixes #9252
2022-12-26 13:20:27 -08:00
sciwhiz12 2d714f034f [1.19.2] Fix compatibility checker task configuration (#9233)
* Fix compatibility checker task configuration

The setupCheckJarCompatibility task exists to configure the main
compatibility checker task, checkJarCompatibility, because certain
configuration steps for that task could not be done until after the
configuration phase of Gradle.

However, that setup task previously held all the configuration for the
main check task in its task action. This caused problems because the
main check task's inputs are linked to other tasks, and the previous
situation made it so its configuration (by the setup task) happened
_after_ Gradle built the task dependency model/tree.

This meant that certain tasks which the main check task depended on did
not run before that task, because Gradle was unaware of this inter-task
dependency until it was too late (when it was already executing tasks).

This fixes the issue by moving the bulk of the configuration for the
main check task from the action of the setup task to the main
buildscript, therefore allowing Gradle to know about those task
dependencies and factor them in to its process of determining what tasks
to run and in what order.

The remaining configuration step in the setup task for the main check
task is linked to the setup task, and does not affect the task's
dependencies (because it uses a configuration which it resolves
immediately), so it stays in the setup task.

* Force checker setup task to never be up-to-date

The setup task configures the main check task, so it should always run
before that task. However, because it has an input and output, the setup
task is affected by Gradle's incremental build feature, which leads to
the possibility that Gradle considers the setup task as up-to-date,
therefore not executing its action and causing errors with the main
check task down the line.
2022-12-17 18:50:26 +01:00
LexManos 617ecb7ad3 43.2 Recommended Build. 2022-12-07 23:20:28 -08:00
Su5eD dd8239c255 Allow discovering services from the mods folder that use java's modular definition. (#9143) 2022-11-30 14:50:30 -08:00
Brennan Ward bdddc8c5d4 Make Datapack Registries support ICondition(s) (#9113) 2022-11-30 14:45:00 -08:00
Marc Hermans c1c619a109 Enable additional build types to handle pull request validation. (#9159) 2022-11-30 14:08:05 -08:00
sciwhiz12 f7eea35cb9 Check source permission level before selector permission (#9147)
In some situations, such as execution of a function by an advancement as
part of its reward, a command source stack may have a backing source of
a ServerPlayer which may lack the entity selector permission and have an
explicit permission level that should allow the use of entity selectors,
through CommandSourceStack#withPermission.

We now check if the permission level of the command source stack is
sufficient for entity selectors _before_ checking if the source is a
player and if they have the requisite permission.

This means that an operator permission level of 2 will always override
the Forge entity selector permission.

Fixes #9137
2022-11-30 14:07:18 -08:00
J.T. McQuigg a2434e1607 Fix fires spreading too/igniting custom portal frames. (#9142) 2022-11-30 14:06:22 -08:00
Minecraftschurli b806ecd0ff Add supplier to FlowerBlock so it works with custom MobEffects (#9139) 2022-11-30 14:04:15 -08:00
KnightMiner 8358b800e9 Fix some logical bugs related to the Grindstone Event (#9089) 2022-11-30 14:00:59 -08:00
Néstor Amador b25a092cf1 Call baked model's getModelData before getRenderTypes (#9163) 2022-11-28 17:53:19 +01:00
Jonathan Coates d812fdd0a3 Make Util.memoize thread-safe (#9155) 2022-11-23 09:18:04 +01:00
Néstor Amador 2d3ee8a228 Rendering tweaks and fixes: Part 4 (#9065) 2022-11-23 09:17:43 +01:00
matyrobbrt 97a9ca65f1 Fix Transformation loading PoseStack (#9083) 2022-11-21 20:49:41 +01:00
Néstor Amador f043fbbc51 Add simple block appearance API (#9066) 2022-11-21 20:48:30 +01:00
SizableShrimp a19ab3a8d4 Fix invalidated modded packets when on LAN (#9157) 2022-11-20 18:34:21 -08:00
Dennis C bc0517a404 Improve extensibility of DetectorRailBlock and PoweredRailBlock (#9130) 2022-11-08 12:18:48 -08:00
Su5eD dc9c0d7e35 Fix launch handler minecraft classpath locator (#9120) 2022-11-08 12:17:48 -08:00
matyrobbrt 1a2207b3b2 Add HitResult to EntityTeleportEvent$EnderPearl (#9135) 2022-11-08 12:17:18 -08:00
sciwhiz12 84ab9764e3 Throw aggregate exception for erroneous registry event dispatch (#9111)
This means that exceptions occurring during the dispatch of the registry
events, such as those from the suppliers of RegistryObjects, properly
cause a crash rather than merely being logged and allowing the game to
reach the main menu.

Fixes #8720
2022-11-08 12:17:00 -08:00
Nexus-Dino bef68991f0 Add missing semi-colon near the Dist import statement in example mod. 2022-11-08 12:16:49 -08:00
Nexus-Dino 526c13d662 Fix ClientModEvents example not subscribing to client-sided events (#9097) 2022-10-21 13:22:57 -07:00
matyrobbrt 67ffb78c23 Use GitHub action to lock issues with the spam label (#9087) 2022-10-21 13:22:31 -07:00
sciwhiz12 8f407c3a22 Remove structures slave map to Feature registry (#9091) 2022-10-21 13:22:18 -07:00
Dennis C 8980252e16 Improve logging of missing or unsupported dependencies (#9104) 2022-10-21 13:21:49 -07:00
DBotThePony 3baee80485 [1.19.x] Fix ValueSpec caching the return value incorrectly (#9046) 2022-10-14 17:43:21 +01:00
eerussianguy ca9599bb4d [1.19.x] Add event for registering spawn placements, and modifying existing (#9024) 2022-10-14 17:39:14 +01:00
eerussianguy 051db7907a [1.19.x] Add event for items being stacked or swapped in a GUI. (#9050) 2022-10-14 17:30:12 +01:00
Magnus Jensen bdba5ef2d3 [1.19.x] Fix PlayerInteractEvent.EntityInteractSpecific not cancelling on a server (#9079) 2022-10-14 17:18:17 +01:00
DBotThePony 838b9c0eda Fix canceling phantom spawns preventing any further attempts that tick. (#9041) 2022-10-13 11:40:56 -07:00
Magnus Jensen be584c54aa Rename fluid type milk translation keys (#9077) 2022-10-12 12:54:34 -07:00
ChampionAsh5357 1b3640b42d Fix minecart speed with water (#9076) 2022-10-12 12:51:13 -07:00
Sara Freimer be5dab5801 Add a cancellable event that gets fired when a Totem of Undying is used (#9069) 2022-10-12 12:46:08 -07:00
Marc Hermans aae628cd18 Fix performance issue and logging when resource caching is enabled (#9029) 2022-10-12 12:00:25 -07:00
Magnus Jensen e7bd08649f Fix NPE when feeding wolves and cats (#9074) 2022-10-07 19:55:40 -07:00
Paint_Ninja e1017a4c7e Fix logically breaking change to ForgeConfigSpec.Builder#comment where modders could not add a empty line to the start of comments. (#9061) 2022-10-03 11:50:32 -07:00
SizableShrimp 6f8ba9d295 Fix ServiceLoader bug
Signed-off-by: SizableShrimp <[email protected]>
2022-09-29 22:11:12 -07:00
SizableShrimp ac94478ae7 Fix ClientChatReceivedEvent for system messages
Signed-off-by: SizableShrimp <[email protected]>
2022-09-29 22:11:12 -07:00
DBotThePony 515c6082e0 Make ForgeConfigSpec$Builder.comment able to be called multiple times for the same entry. (#9056) 2022-09-27 23:23:59 -07:00
ChampionAsh5357 a753598113 Fix control modifier for mac with KeyMappings using Alt instead of Super (#9057) 2022-09-27 11:15:11 -07:00
J.T. McQuigg bc6c4be4e4 Fix is_desert tag not being applied correctly. (#9051) 2022-09-26 11:08:24 -07:00
Andy Dingley 98823a8f07 Fix mob griefing event for SmallFireballs not using owner entity. (#9038) 2022-09-21 13:24:25 -07:00
David Dempsey ecd8f1e54d Fix minecarts on rails not properly slowing down in water (#9033) 2022-09-21 13:20:03 -07:00
LexManos b0caea8e20 Change codestyle for BookShelves tag. Closes #9027
Add IS_CAVE tag Closes #8885
Add IS_DESERT tag Closes #8979
Simplify Mangrove Swamp tags Closes #8980
2022-09-09 11:27:39 -07:00
nikita488 e0477f8776 Allow faces of an "elements" model to have disabled ambient occlusion (#9019) 2022-09-08 16:17:44 +01:00
bconlon 94e1e54b53 [1.19.x] Recipe ID-based grouping between modded and vanilla recipes. (#8876) 2022-09-08 16:13:07 +01:00
nitro_dynamite18 9ce72331b7 Update fence_gates/wooden (#8936) 2022-09-08 16:12:26 +01:00
Jais Djurhuus-Kempel 1c31f42dae [1.19.x] Added event for growing fungus (#8981) 2022-09-08 16:11:59 +01:00
agnor99 0978a94358 Added Bookshelves block tag (#8991) 2022-09-08 16:11:39 +01:00
GizmoTheMoonPig e956a9c9f3 Create a Forge EntityType Tag for Bosses (#9017) 2022-09-08 16:10:48 +01:00
Monica S 82026d11a4 Allow mods to specify shader import namespace (#9021) 2022-09-08 16:10:31 +01:00
ferriarnus 6d233ac75c Grindstone Events (#8934)
One to modify the output, and one to modify the input.
2022-09-08 15:55:43 +01:00
Reece Mackie 73c1934e7e Fix the serialized names of the enum (#9014) 2022-09-04 19:46:54 +01:00
Technici4n bf1194ec75 Fix tryEmptyContainerAndStow duping fluids with stackable containers (#9004) 2022-09-03 21:48:07 +01:00
Ted Senft 22d2740725 Add mod mismatch event (#8989) 2022-09-03 21:26:43 +01:00
Minecraftschurli 02f26dc7a1 [1.19.x] add methods with more context to tree growers (#8956) 2022-09-03 20:24:00 +01:00
28Pollux28 db14cbb0e0 [1.19.X] Adding more precise events for Advancements (#8360) 2022-09-03 20:17:16 +01:00
Luke BemishandLexManos a2b35cae92 Default IItemHandler capability for shulker box itemstacks (#8827)
Co-authored-by: LexManos <[email protected]>
2022-09-03 20:16:25 +01:00
Take Weiland aab0e4c82e [1.19] Add hook for items to remain in the hotbar when picking blocks/entities (#8872) 2022-09-03 20:12:13 +01:00
Reece Mackieandsciwhiz12 6609708d14 [1.19.x] Block Model Builder Root Transform Support (#8860)
Co-authored-by: sciwhiz12 <[email protected]>
2022-09-03 20:11:46 +01:00
Budschie ed198f062c [1.19.x] Make LivingSetAttackTargetEvent compatible with the Brain/Behavior system. (Port of PR #8918) (#8954) 2022-09-03 20:11:10 +01:00
thedarkcolour 4e2d656e9d [1.19.x] Add IForgeBlock#onTreeGrow to replace IForgeBlock#onPlantGrow from 1.16 (#8999) 2022-09-03 20:07:09 +01:00
bconlon 2a4230868f [1.19.x] Moved Player.resetAttackStrengthTicker() to the end of Player.attack() (#9000) 2022-09-03 20:06:35 +01:00
Sirttas cf778b1759 fix misplaced patch in sapling block (#9005) 2022-09-03 20:05:37 +01:00
Brennan Ward 1b6daddd40 Fix failed entity interactions consuming the click. (#9007) 2022-09-03 20:00:57 +01:00
sciwhiz12 d7b137d144 Fix entity selector permission check to check original source (#8995)
Permission checks should be against the command source and not the
target entity, as is done in vanilla.

Fixes #8994
2022-08-25 11:42:11 -07:00
한현빈 b5d5855559 Hotfix for 1.19.2 item animation bug (#8987)
* [HOT FIX]: Fixes #8985 by no-oping for vanilla models instead of throwing error

Signed-off-by: tmvkrpxl0 <[email protected]>
2022-08-20 11:38:24 +02:00
LexManos c0aa8dd808 Add ability to Auto register capabilities via annotation (#8972) 2022-08-17 15:06:35 -07:00
265 changed files with 6279 additions and 1009 deletions

No files matched your search

+42
View File
@@ -0,0 +1,42 @@
name: 'Spam label'
on:
issues:
types: [labeled]
pull_request:
types: [labeled]
discussion:
types: [labeled]
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
lock:
if: ${{ (github.event.label.name == 'spam') && (github.event.action == 'labeled') }}
runs-on: ubuntu-latest
steps:
- uses: peter-evans/close-issue@v2
name: Close Issue
with:
close-reason: 'not_planned'
if: ${{ github.event_name != 'pull_request' }}
- run: gh pr close ${{ github.event.pull_request.html_url }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Close PR
if: ${{ github.event_name == 'pull_request' }}
- uses: maxkomarychev/[email protected]
name: Lock PR
if: ${{ github.event_name == 'pull_request' }}
with:
token: "${{ secrets.GITHUB_TOKEN }}"
issue_number: ${{ github.event.number }}
- uses: OSDKDev/[email protected]
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
name: Lock issue
if: ${{ github.event_name != 'pull_request' }}
+73 -1
View File
@@ -1,5 +1,7 @@
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.projectFeatures.githubIssues
import jetbrains.buildServer.configs.kotlin.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
/*
The settings script is an entry point for defining a TeamCity
@@ -30,11 +32,13 @@ project {
buildType(Build)
buildType(BuildSecondaryBranches)
buildType(PullRequests)
buildType(PullRequestChecks)
buildType(PullRequestCompatibility)
params {
text("docker_jdk_version", "17", label = "Gradle version", description = "The version of the JDK to use during execution of tasks in a JDK.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("docker_gradle_version", "7.4", label = "Gradle version", description = "The version of Gradle to use during execution of Gradle tasks.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_main_branch", "1.18.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_main_branch", "1.19.x", label = "Git Main Branch", description = "The git main or default branch to use in VCS operations.", display = ParameterDisplay.HIDDEN, allowEmpty = false)
text("git_branch_spec", """
+:refs/heads/(main*)
+:refs/heads/(master*)
@@ -134,3 +138,71 @@ object PullRequests : BuildType({
""".trimIndent()
}
})
object PullRequestChecks : BuildType({
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"))
id("MinecraftForge_MinecraftForge__PullRequestChecks")
name = "Pull Requests (Checks)"
description = "Checks pull requests for the project"
steps {
gradle {
name = "Check"
id = "RUNNER_10_Check"
tasks = "checkAll"
gradleParams = "--continue %gradle_custom_args%"
enableStacktrace = true
dockerImage = "%docker_gradle_image%"
dockerRunParameters = """
-v "/opt/cache/agent/gradle:/home/gradle/.gradle"
-v "/opt/cache/shared/gradle:/home/gradle/rocache:ro"
--network=host
-u 1000:1000
%docker_additional_args%
""".trimIndent()
}
}
vcs {
branchFilter = """
+:*
-:1.*
-:<default>
""".trimIndent()
}
})
object PullRequestCompatibility : BuildType({
templates(AbsoluteId("MinecraftForge_BuildPullRequests"), AbsoluteId("MinecraftForge_SetupGradleUtilsCiEnvironmen"), AbsoluteId("MinecraftForge_BuildWithDiscordNotifications"), AbsoluteId("MinecraftForge_SetupProjectUsingGradle"))
id("MinecraftForge_MinecraftForge__PullRequestCompatibility")
name = "Pull Requests (Compatibility)"
description = "Validates binary compatibility for pull requests made to the project"
steps {
gradle {
name = "Validate"
id = "RUNNER_10_Compatibility"
tasks = "checkJarCompatibility"
gradleParams = "--continue %gradle_custom_args%"
enableStacktrace = true
dockerImage = "%docker_gradle_image%"
dockerRunParameters = """
-v "/opt/cache/agent/gradle:/home/gradle/.gradle"
-v "/opt/cache/shared/gradle:/home/gradle/rocache:ro"
--network=host
-u 1000:1000
%docker_additional_args%
""".trimIndent()
}
}
vcs {
branchFilter = """
+:*
-:1.*
-:<default>
""".trimIndent()
}
})
Vendored
-125
View File
@@ -1,125 +0,0 @@
@Library('forge-shared-library')_
pipeline {
options {
disableConcurrentBuilds()
}
agent {
docker {
image 'gradle:7-jdk16'
//args '-v forgegc:/home/gradle/.gradle_cache/'
}
}
environment {
GRADLE_ARGS = '--no-daemon --console=plain' // No daemon for now as FG3 kinda derps. //'-Dorg.gradle.daemon.idletimeout=5000'
DISCORD_WEBHOOK = credentials('forge-discord-jenkins-webhook')
DISCORD_PREFIX = "Job: Forge Branch: ${BRANCH_NAME} Build: #${BUILD_NUMBER}"
JENKINS_HEAD = 'https://wiki.jenkins-ci.org/download/attachments/2916393/headshot.png'
}
stages {
stage('notify_start') {
when {
not {
changeRequest()
}
}
steps {
discordSend(
title: "${DISCORD_PREFIX} Started",
successful: true,
result: 'ABORTED', //White border
thumbnail: JENKINS_HEAD,
webhookURL: DISCORD_WEBHOOK
)
}
}
/*
stage('pull_cache') {
steps {
sh 'cp -r /home/gradle/.gradle_cache/jdks/ /home/gradle/.gradle/jdks/'
sh 'cp -r /home/gradle/.gradle_cache/wrapper/ /home/gradle/.gradle/wrapper/'
sh 'cp -r /home/gradle/.gradle_cache/caches/ /home/gradle/.gradle/caches/'
}
}
*/
stage('setup') {
steps {
withGradle {
sh './gradlew ${GRADLE_ARGS} --refresh-dependencies --continue setup'
}
script {
env.MYVERSION = sh(returnStdout: true, script: './gradlew :forge:properties -q | grep "^version:" | cut -d" " -f2').trim()
env.FMLONLY_VERSION = sh(returnStdout: true, script: './gradlew :fmlonly:properties -q | grep "^version:" | cut -d" " -f2').trim()
}
}
}
stage('changelog') {
when {
not {
changeRequest()
}
}
steps {
writeChangelog(currentBuild, 'build/changelog.txt')
}
}
stage('publish') {
when {
not {
changeRequest()
}
}
environment {
CROWDIN = credentials('forge-crowdin')
KEYSTORE = credentials('forge-jenkins-keystore-old')
KEYSTORE_KEYPASS = credentials('forge-jenkins-keystore-old-keypass')
KEYSTORE_STOREPASS = credentials('forge-jenkins-keystore-old-keypass')
}
steps {
withCredentials([usernamePassword(credentialsId: 'maven-forge-user', usernameVariable: 'MAVEN_USER', passwordVariable: 'MAVEN_PASSWORD')]) {
withGradle {
sh './gradlew ${GRADLE_ARGS} publish -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}'
}
}
}
post {
success {
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:forge ${env.MYVERSION} latest")], propagate: false, wait: false
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:fmlonly ${env.FMLONLY_VERSION} latest")], propagate: false, wait: false
}
}
}
stage('test_publish_pr') { //Publish to local repo to test full process, but don't include credentials so it can't sign/publish to maven
when {
changeRequest()
}
environment {
CROWDIN = credentials('forge-crowdin')
}
steps {
withGradle {
sh './gradlew ${GRADLE_ARGS} publish -PcrowdinKey=${CROWDIN}'
}
}
}
}
post {
always {
script {
archiveArtifacts artifacts: 'projects/forge/build/libs/**/*.*', fingerprint: true, onlyIfSuccessful: true, allowEmptyArchive: true
if (env.CHANGE_ID == null) { // This is unset for non-PRs
discordSend(
title: "${DISCORD_PREFIX} Finished ${currentBuild.currentResult}",
description: '```\n' + getChanges(currentBuild) + '\n```',
successful: currentBuild.resultIsBetterOrEqualTo("SUCCESS"),
result: currentBuild.currentResult,
thumbnail: JENKINS_HEAD,
webhookURL: DISCORD_WEBHOOK
)
}
}
}
}
}
+61 -54
View File
@@ -1,3 +1,4 @@
import de.undercouch.gradle.tasks.download.Download
import groovy.json.JsonBuilder
import java.nio.file.Files
@@ -16,12 +17,12 @@ import org.gradle.plugins.ide.eclipse.model.SourceFolder
plugins {
id 'org.cadixdev.licenser' version '0.6.1'
id 'com.github.ben-manes.versions' version '0.36.0'
id 'net.minecraftforge.gradleutils' version '2.+'
id 'com.github.ben-manes.versions' version '0.46.0'
id 'net.minecraftforge.gradleutils' version '[2.2,2.3)'
id 'eclipse'
id 'de.undercouch.download' version '4.1.2'
id 'net.minecraftforge.gradle.patcher' version '[5.1.50,5.2.0)' apply false
id 'net.minecraftforge.gradle.mcp' version '[5.1.50,5.2.0)' apply false
id 'de.undercouch.download' version '5.4.0'
id 'net.minecraftforge.gradle.patcher' version '[6.0,6.2)' apply false
id 'net.minecraftforge.gradle.mcp' version '[6.0,6.2)' apply false
}
Util.init() //Init all our extension methods!
@@ -47,8 +48,8 @@ ext {
MODLAUNCHER_VERSION = '10.0.8'
SECUREJARHANDLER_VERSION = '2.1.4'
BOOTSTRAPLAUNCHER_VERSION = '1.1.2'
ASM_VERSION = '9.3'
INSTALLER_VERSION = '2.1.+'
ASM_VERSION = '9.7'
INSTALLER_VERSION = '2.2.+'
MIXIN_VERSION = '0.8.5'
TERMINALCONSOLEAPPENDER_VERSION = '1.2.0'
JLINE_VERSION = '3.12.+'
@@ -74,10 +75,10 @@ ext {
FORGE_VERSION = VERSION.substring(MC_VERSION.length() + 1)
BINPATCH_TOOL = 'net.minecraftforge:binarypatcher:1.1.1:fatjar'
INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.3.0'
INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.4.1'
JAR_SPLITTER = 'net.minecraftforge:jarsplitter:1.1.4'
FART = 'net.minecraftforge:ForgeAutoRenamingTool:0.1.22:all'
MIN_TAG_FOR_CHANGELOG = "41.0"
MIN_TAG_FOR_CHANGELOG = '41.0'
}
println('Version: ' + VERSION +
@@ -95,7 +96,7 @@ def extraTxts = [
rootProject.tasks.createChangelog.outputFile
]
task downloadVersionManifest(type: Download) {
tasks.register('downloadVersionManifest', Download) {
src 'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json'
dest file('build/versions/version_manifest.json')
useETag 'all'
@@ -338,7 +339,7 @@ def sharedFmlonlyForge = { Project prj ->
}
prj.task([type: DownloadMavenArtifact], 'downloadInstaller') {
artifact = "net.minecraftforge:installer:${INSTALLER_VERSION}:shrunk"
artifact = "net.minecraftforge:installer:${INSTALLER_VERSION}:fatjar"
changing = true
}
@@ -1130,9 +1131,12 @@ project(':forge') {
]
}
task crowdin(type: Crowdin) {
key = project.hasProperty('crowdinKey') ? project.crowdinKey : null
//TODO: Merge our english.json?
tasks.register('downloadCrowdin', Download) {
src 'https://files.minecraftforge.net/crowdin.zip'
dest file('build/crowdin.zip')
useETag 'all'
onlyIfModified true
quiet true
}
sharedFmlonlyForge.call(project)
@@ -1184,8 +1188,6 @@ project(':forge') {
excs.from patcher.excs
}
task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks]){}
task checkPatchesAndFix(type: CheckPatches, dependsOn: genPatches) {
patchDir = file("$rootDir/patches")
autoFix = true
@@ -1202,57 +1204,59 @@ project(':forge') {
lineEnding = '\n'
}
def baseForgeVersion = System.getProperty("forge.compatibility_check_version")
if (baseForgeVersion == null)
baseForgeVersion = "${MC_VERSION}-${GIT_INFO.tag}.0"
if (baseForgeVersion == "null")
baseForgeVersion = null // Allow disabling from system property if not wanted
def baseForgeUniversal = null
if (baseForgeVersion != null)
baseForgeUniversal = project.dependencies.create("net.minecraftforge:forge:${baseForgeVersion}:universal")
def baseForgeVersionProperty = project.objects.property(String)
baseForgeVersionProperty.set(project.provider { getLatestForgeVersion(MC_VERSION) }.map { MC_VERSION + '-' + it })
baseForgeVersionProperty.finalizeValueOnRead()
def jarCompatibilityTaskSetup = { task ->
task.group = 'jar compatibility'
task.onlyIf {
baseForgeVersion != null
baseForgeVersionProperty.getOrNull() != null
}
task.inputs.property 'baseForgeVersion', baseForgeVersion
}
task downloadBaseCompatibilityBinPatches(type: DownloadBaseCompatibilityBinPatches) {
inputVersion = baseForgeVersion
tasks.register('setupCheckJarCompatibility', SetupCheckJarCompatibility) {
inputVersion = baseForgeVersionProperty
}
task applyBaseCompatibilityJarBinPatches(type: ApplyBinPatches) {
tasks.register('applyBaseCompatibilityJarBinPatches', ApplyBinPatches) {
jarCompatibilityTaskSetup(it)
clean = createJoinedSRG.output
patch = downloadBaseCompatibilityBinPatches.output
clean = project.tasks.createJoinedSRG.output
patch = project.tasks.named('setupCheckJarCompatibility').flatMap { it.baseBinPatchesOutput }
output = project.layout.buildDirectory.dir(name).map { it.file('output.jar') }
}
task checkJarCompatibility(type: CheckJarCompatibility) {
tasks.register('mergeBaseForgeJar', MergeJars) {
jarCompatibilityTaskSetup(it)
if (baseForgeVersion != null) {
def fmlLibs = project.configurations.detachedConfiguration(PACKED_DEPS.collect {
def artifactId = it.split(':')[1]
return project.dependencies.create("net.minecraftforge:${artifactId}:${baseForgeVersion}")
}.toArray(Dependency[]::new))
baseJar = project.tasks.applyBaseCompatibilityJarBinPatches.output
baseLibraries.from(project.configurations.detachedConfiguration(baseForgeUniversal))
baseLibraries.from(project.tasks.createJoinedSRG.output)
baseLibraries.from(fmlLibs)
inputJar = project.tasks.reobfJar.output
concreteLibraries.from(PACKED_DEPS.collect { rootProject.tasks.getByPath(it).archiveFile })
commonLibraries.from(project.configurations.minecraftImplementation)
commonLibraries.from(project.configurations.installer)
commonLibraries.from(project.configurations.moduleonly)
}
inputJars.from(project.tasks.named('applyBaseCompatibilityJarBinPatches').flatMap { it.output })
inputJars.from(baseForgeVersionProperty.map { inputVersion ->
def output = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-universal.jar") }.get().asFile
project.rootProject.extensions.download.run {
src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-universal.jar"
dest output
}
return output
})
}
tasks.register('checkJarCompatibility', CheckJarCompatibility) {
jarCompatibilityTaskSetup(it)
dependsOn 'setupCheckJarCompatibility'
baseJar = project.tasks.named('mergeBaseForgeJar').flatMap { it.output }
baseLibraries.from(project.tasks.named('createJoinedSRG').flatMap { it.output })
inputJar = project.tasks.named('reobfJar').flatMap { it.output }
concreteLibraries.from(project.PACKED_DEPS.collect { project.rootProject.tasks.getByPath(it).archiveFile })
commonLibraries.from(project.configurations.minecraftImplementation)
commonLibraries.from(project.configurations.installer)
commonLibraries.from(project.configurations.moduleonly)
}
task checkAll(dependsOn: [checkATs, checkSAS, checkExcs, findFieldInstanceChecks, checkPatches, checkLicenses]){}
task launcherJson(type: LauncherJson) {
packedDependencies = [':fmlloader:jar']
doFirst {
@@ -1510,9 +1514,12 @@ project(':forge') {
from extraTxts
// add crowdin locales
from { crowdin.output.present && crowdin.output.get().asFile.exists() ? zipTree(crowdin.output) : null}
dependsOn crowdin
duplicatesStrategy = 'exclude'
from zipTree(downloadCrowdin.dest).matching {
include 'assets/forge/lang/*.json'
}
dependsOn downloadCrowdin
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
doFirst {
MANIFESTS.each{ pkg, values ->
@@ -1557,7 +1564,7 @@ project(':forge') {
exclude it
}
filter(ReplaceTokens, tokens: [
FORGE_VERSION: project.version,
FORGE_VERSION: FORGE_VERSION,
FORGE_GROUP: project.group,
FORGE_NAME: project.name,
MC_VERSION: MC_VERSION,
+4 -3
View File
@@ -4,7 +4,8 @@ repositories {
}
dependencies {
implementation 'org.ow2.asm:asm:9.3'
implementation 'org.ow2.asm:asm-tree:9.3'
implementation 'net.minecraftforge:srgutils:0.4.+'
implementation 'org.ow2.asm:asm:9.5'
implementation 'org.ow2.asm:asm-tree:9.5'
implementation 'net.minecraftforge:srgutils:0.5.+'
implementation 'commons-io:commons-io:2.12.0'
}
@@ -4,7 +4,7 @@ import groovy.json.JsonBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.Opcodes
@@ -17,7 +17,9 @@ import java.util.zip.ZipInputStream
abstract class BytecodeFinder extends DefaultTask {
@InputFile abstract RegularFileProperty getJar()
@OutputFile abstract RegularFileProperty getOutput()
// It should be fine to mark the output as internal as we want to control when we run it anyways.
// This also shuts Gradle 8 up about implicit task dependencies.
@Internal abstract RegularFileProperty getOutput()
BytecodeFinder() {
output.convention(project.layout.buildDirectory.dir(name).map { it.file("output.json") })
@@ -1,39 +0,0 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.nio.file.Files
abstract class DownloadBaseCompatibilityBinPatches extends DefaultTask {
DownloadBaseCompatibilityBinPatches() {
group = 'jar compatibility'
onlyIf {
inputVersion.getOrNull() != null
}
output.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
}
@TaskAction
void run() {
def dep = project.dependencies.create("net.minecraftforge:forge:${inputVersion.get()}:userdev")
def baseForgeUserdev = project.configurations.detachedConfiguration(dep).resolve().iterator().next()
def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile
Files.copy(joinedLzma.toPath(), output.get().asFile.toPath())
}
@Input
@Optional
abstract Property<String> getInputVersion()
@OutputFile
abstract RegularFileProperty getOutput()
}
@@ -0,0 +1,44 @@
package net.minecraftforge.forge.tasks
import org.apache.commons.io.IOUtils
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
abstract class MergeJars extends DefaultTask {
MergeJars() {
output.convention(project.layout.buildDirectory.dir(name).map { it.file('output.jar') })
}
@TaskAction
void run() {
def jars = inputJars.files
try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.get().asFile))) {
for (def jar : jars) {
try (ZipInputStream zin = new ZipInputStream(new FileInputStream(jar))) {
def entry
while ((entry = zin.getNextEntry()) != null) {
ZipEntry _new = new ZipEntry(entry.getName())
_new.setTime(0) //SHOULD be the same time as the main entry, but NOOOO _new.setTime(entry.getTime()) throws DateTimeException, so you get 0, screw you!
zout.putNextEntry(_new)
IOUtils.copy(zin, zout)
}
}
}
}
}
@InputFiles
abstract ConfigurableFileCollection getInputJars()
@OutputFile
abstract RegularFileProperty getOutput()
}
@@ -0,0 +1,57 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.nio.file.Files
import java.nio.file.StandardCopyOption
abstract class SetupCheckJarCompatibility extends DefaultTask {
SetupCheckJarCompatibility() {
group = 'jar compatibility'
onlyIf {
inputVersion.getOrNull() != null
}
outputs.upToDateWhen { false } // Never up to date, because this setup task should always run
baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') })
}
@TaskAction
void run() {
def inputVersion = inputVersion.get()
def fmlLibs = project.configurations.detachedConfiguration(project.PACKED_DEPS.collect {
def artifactId = it.split(':')[1]
return project.dependencies.create("net.minecraftforge:${artifactId}:${inputVersion}")
}.toArray(Dependency[]::new))
project.tasks.named('checkJarCompatibility') {
baseLibraries.from(project.provider {
fmlLibs.resolvedConfiguration.lenientConfiguration.files
})
}
def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile
project.rootProject.extensions.download.run {
src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-userdev.jar"
dest baseForgeUserdev
}
def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile
Files.copy(joinedLzma.toPath(), baseBinPatchesOutput.get().asFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
@Input
@Optional
abstract Property<String> getInputVersion()
@OutputFile
abstract RegularFileProperty getBaseBinPatchesOutput()
}
@@ -18,17 +18,17 @@ public class Util {
return md.digest().collect {String.format "%02x", it}.join()
}
File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() }
File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) }
File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] }
File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() }
Date.metaClass.iso8601 = { ->
def format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
def result = format.format(delegate)
return result[0..21] + ':' + result[22..-1]
}
String.metaClass.rsplit = { String del, int limit = -1 ->
def lst = new ArrayList()
def x = 0, idx
@@ -41,7 +41,7 @@ public class Util {
return lst
}
}
public static String[] getClasspath(project, libs, artifact) {
def ret = []
artifactTree(project, artifact).each { key, lib ->
@@ -51,7 +51,7 @@ public class Util {
}
return ret
}
public static def getArtifacts(project, config, classifiers) {
def ret = [:]
config.resolvedConfiguration.resolvedArtifacts.each {
@@ -74,14 +74,6 @@ public class Util {
if (!checkExists(url)) {
url = "https://maven.minecraftforge.net/${path}"
}
//TODO remove when Mojang launcher is updated
if (!classifiers && art.classifier != null) {
//Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
// However, keep the path normal so that our mirror system works.
art.version = "${art.version}-${art.classifier}"
art.classifier = null
art.extension = 'jar'
}
ret[key] = [
name: "${art.group}:${art.name}:${art.version}" + (art.classifier == null ? '' : ":${art.classifier}") + (art.extension == 'jar' ? '' : "@${art.extension}"),
downloads: [
@@ -96,14 +88,14 @@ public class Util {
}
return ret
}
public static def getMavenPath(task) {
public static def getMavenPath(task) {
def classifier = task.archiveClassifier.get()
def dep = "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
return "${task.project.group.replace('.', '/')}/${task.project.name}/${task.project.version}/${task.project.name}-${task.project.version}".toString() + (classifier == '' ? '' : '-' + classifier) + '.jar'
}
public static def getMavenDep(task) {
public static def getMavenDep(task) {
def classifier = task.archiveClassifier.get()
return "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
}
@@ -127,7 +119,7 @@ public class Util {
def files = cfg.resolve()
return getArtifacts(project, cfg, true)
}
private static boolean checkExists(url) {
try {
def code = new URL(url).openConnection().with {
@@ -142,4 +134,9 @@ public class Util {
throw e
}
}
public static String getLatestForgeVersion(mcVersion) {
def json = new JsonSlurper().parseText(new URL("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json").getText("UTF-8"))
return json.promos["$mcVersion-latest"]
}
}
+13 -11
View File
@@ -2,16 +2,17 @@
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.19-&query=$.promos["1.19.2-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.19.2-&query=$.promos["1.19.2-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.19.2-&query=$.promos["1.19.2-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)](https://files.minecraftforge.net) [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)](https://discord.gg/UvedJ9m) [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)](https://www.patreon.com/LexManos)
)](https://files.minecraftforge.net) [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)][Discord] [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)](https://www.patreon.com/LexManos)
Forge is a free, open-source modding API all of your favourite mods use!
| Version | Support |
|---------| ------------- |
| 1.19.x | Active |
| 1.18.x | LTS |
| 1.20.x | Active |
| 1.19.4 | Legacy |
| 1.19.2 | Legacy |
* [Download]
* [Forum]
@@ -29,24 +30,24 @@ You can download the installer for the *Recommended Build* or the
into your vanilla launcher environment, where you can then create a new
profile using that version and play the game!
For support and questions, visit [the Support Forum](https://www.minecraftforge.net/forum/forum/18-support-bug-reports/) or [the Forge Discord server](https://discord.gg/forge).
For support and questions, visit [the Support Forum][Support-Forum] or [the Forge Discord server][Discord].
[Here is a short video from Rorax showing how to install and setup Forge.](https://www.youtube.com/watch?v=lB3ArN_-3Oc)
# Creating Mods
[See the "Getting Started" section in the Forge Documentation](https://mcforge.readthedocs.io/en/latest/gettingstarted/).
[See the "Getting Started" section in the Forge Documentation](https://docs.minecraftforge.net/en/1.19.2/gettingstarted/).
# Contribute to Forge
If you wish to actually inspect Forge, submit PRs or otherwise work
with Forge itself, you're in the right place!
[See the guide to setting up a Forge workspace](http://mcforge.readthedocs.io/en/latest/forgedev/).
[See the guide to setting up a Forge workspace](https://docs.minecraftforge.net/en/1.19.2/forgedev/).
### Pull requests
[See the "Making Changes and Pull Requests" section in the Forge documentation](https://mcforge.readthedocs.io/en/latest/forgedev/#making-changes-and-pull-requests).
[See the "Making Changes and Pull Requests" section in the Forge documentation](https://docs.minecraftforge.net/en/1.19.2/forgedev/#making-changes-and-pull-requests).
Please read the contributing guidelines found [here](CONTRIBUTING.md) before making a pull request.
@@ -61,6 +62,7 @@ Please ensure you have a valid email address associated with your GitHub account
[becoming a patron](https://www.patreon.com/LexManos).*
[Download]: https://files.minecraftforge.net/
[Forum]: https://www.minecraftforge.net/forum/
[Discord]: https://discord.gg/UvedJ9m
[Documentation]: https://mcforge.readthedocs.io
[Forum]: https://forums.minecraftforge.net
[Support-Forum]: https://forums.minecraftforge.net/forum/18-support-bug-reports/
[Discord]: https://discord.minecraftforge.net
[Documentation]: https://docs.minecraftforge.net/en/1.19.2/
@@ -95,5 +95,24 @@ public interface IExtensionPoint<T extends Record>
@SuppressWarnings("JavadocReference") // reference to NetworkConstants, ForgeHooksClient
record DisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) implements IExtensionPoint<DisplayTest> {
public static final String IGNORESERVERONLY = "OHNOES\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31";
/**
* Ignores any version information coming from the server - use for server only mods
*/
public static final Supplier<DisplayTest> IGNORE_SERVER_VERSION = () -> new DisplayTest(IGNORESERVERONLY, (remoteVersion, isFromServer) -> true);
/**
* Ignores all information and provides no information
*/
public static final Supplier<DisplayTest> IGNORE_ALL_VERSION = () -> new DisplayTest("", (remoteVersion, isFromServer) -> true);
/**
* An optional alternative to {@link #DisplayTest(Supplier, BiPredicate)} which accepts a constant version string
* instead of a {@link Supplier}.
* <p>Internally, the provided version string is wrapped in a Supplier for you.</p>
*/
public DisplayTest(String version, BiPredicate<String, Boolean> remoteVersionTest) {
this(() -> version, remoteVersionTest);
}
}
}
@@ -20,6 +20,7 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -63,9 +64,9 @@ public abstract class ModContainer
() -> new IExtensionPoint.DisplayTest(() -> this.modInfo.getVersion().toString(),
(incoming, isNetwork) -> Objects.equals(incoming, this.modInfo.getVersion().toString()));
case "IGNORE_SERVER_VERSION" -> // Ignores any version information coming from the server - use for server only mods
() -> new IExtensionPoint.DisplayTest(() -> IExtensionPoint.DisplayTest.IGNORESERVERONLY, (incoming, isNetwork) -> true);
IExtensionPoint.DisplayTest.IGNORE_SERVER_VERSION;
case "IGNORE_ALL_VERSION" -> // Ignores all information and provides no information
() -> new IExtensionPoint.DisplayTest(() -> "", (incoming, isNetwork) -> true);
IExtensionPoint.DisplayTest.IGNORE_ALL_VERSION;
case "NONE" -> null; // NO display test at all - use this if you're going to do your own display test
default -> // any other value throws an exception
throw new IllegalArgumentException("Invalid displayTest value supplied in mods.toml");
@@ -142,6 +143,22 @@ public abstract class ModContainer
extensionPoints.put(point, extension);
}
public void registerDisplayTest(IExtensionPoint.DisplayTest displayTest) {
registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> displayTest);
}
public void registerDisplayTest(Supplier<IExtensionPoint.DisplayTest> displayTest) {
registerExtensionPoint(IExtensionPoint.DisplayTest.class, displayTest);
}
public void registerDisplayTest(String version, BiPredicate<String, Boolean> remoteVersionTest) {
registerDisplayTest(new IExtensionPoint.DisplayTest(version, remoteVersionTest));
}
public void registerDisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) {
registerDisplayTest(new IExtensionPoint.DisplayTest(suppliedVersion, remoteVersionTest));
}
public void addConfig(final ModConfig modConfig) {
configs.put(modConfig.getType(), modConfig);
}
@@ -5,13 +5,19 @@
package net.minecraftforge.fml;
import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.config.IConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.loading.FMLLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
public class ModLoadingContext
{
private static final Logger LOGGER = LogUtils.getLogger();
private static final ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
private Object languageExtension;
private ModLoadingStage stage;
@@ -45,11 +51,63 @@ public class ModLoadingContext
getActiveContainer().registerExtensionPoint(point, extension);
}
/**
* Register a {@link IExtensionPoint.DisplayTest} with the mod container.
* <p>A shorthand for registering a DisplayTest with {@link #registerExtensionPoint(Class, Supplier)}.</p>
* @param displayTest The {@link IExtensionPoint.DisplayTest} to register
*/
public void registerDisplayTest(IExtensionPoint.DisplayTest displayTest) {
getActiveContainer().registerDisplayTest(() -> displayTest);
}
/**
* Register a {@link IExtensionPoint.DisplayTest} with the mod container.
* <p>A shorthand for registering a DisplayTest supplier with {@link #registerExtensionPoint(Class, Supplier)}.</p>
* @param displayTest The {@link Supplier<IExtensionPoint.DisplayTest>} to register
*/
public void registerDisplayTest(Supplier<IExtensionPoint.DisplayTest> displayTest) {
getActiveContainer().registerDisplayTest(displayTest);
}
/**
* Register a {@link IExtensionPoint.DisplayTest} with the mod container.
* <p>A shorthand for registering a DisplayTest with {@link #registerExtensionPoint(Class, Supplier)} that also
* creates the DisplayTest instance for you using the provided parameters.</p>
* @see IExtensionPoint.DisplayTest#DisplayTest(String, BiPredicate)
*/
public void registerDisplayTest(String version, BiPredicate<String, Boolean> remoteVersionTest) {
getActiveContainer().registerDisplayTest(new IExtensionPoint.DisplayTest(version, remoteVersionTest));
}
/**
* Register a {@link IExtensionPoint.DisplayTest} with the mod container.
* <p>A shorthand for registering a DisplayTest with {@link #registerExtensionPoint(Class, Supplier)} that also
* creates the DisplayTest instance for you using the provided parameters.</p>
* @see IExtensionPoint.DisplayTest#DisplayTest(Supplier, BiPredicate)
*/
public void registerDisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) {
getActiveContainer().registerDisplayTest(new IExtensionPoint.DisplayTest(suppliedVersion, remoteVersionTest));
}
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec) {
if (spec.isEmpty())
{
// This handles the case where a mod tries to register a config, without any options configured inside it.
LOGGER.debug("Attempted to register an empty config for type {} on mod {}", type, getActiveContainer().getModId());
return;
}
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer()));
}
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec, String fileName) {
if (spec.isEmpty())
{
// This handles the case where a mod tries to register a config, without any options configured inside it.
LOGGER.debug("Attempted to register an empty config for type {} on mod {} using file name {}", type, getActiveContainer().getModId(), fileName);
return;
}
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer(), fileName));
}
@@ -8,6 +8,7 @@ package net.minecraftforge.fml.loading;
import com.mojang.logging.LogUtils;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
@@ -53,4 +54,16 @@ public class FileUtils
return "";
}
}
public static boolean matchFileName(String path, String... matches) {
// Extract file name from path
String name = path.substring(Math.min(path.lastIndexOf(File.separatorChar) + 1, path.length()));
// Check if it contains any of the desired keywords
for (String match : matches) {
if (name.contains(match)) {
return true;
}
}
return false;
}
}
@@ -6,21 +6,27 @@
package net.minecraftforge.fml.loading;
import com.mojang.logging.LogUtils;
import cpw.mods.jarhandling.SecureJar;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import cpw.mods.modlauncher.api.NamedPath;
import cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.lang.module.ModuleDescriptor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipFile;
import java.util.Set;
public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Set<String> SERVICES = Set.of(
"cpw.mods.modlauncher.api.ITransformationService",
"net.minecraftforge.forgespi.locating.IModLocator",
"net.minecraftforge.forgespi.locating.IDependencyLocator"
);
@Override
public List<NamedPath> candidates(final Path gameDirectory) {
@@ -51,14 +57,11 @@ public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService
if (!Files.isRegularFile(path)) return;
if (!path.toString().endsWith(".jar")) return;
if (LamdbaExceptionUtils.uncheck(() -> Files.size(path)) == 0) return;
try (ZipFile zf = new ZipFile(new File(path.toUri()))) {
if (zf.getEntry("META-INF/services/cpw.mods.modlauncher.api.ITransformationService") != null) {
found.add(new NamedPath(zf.getName(), path));
} else if (zf.getEntry("META-INF/services/net.minecraftforge.forgespi.locating.IModLocator") != null) {
found.add(new NamedPath(zf.getName(), path));
}
} catch (IOException ioe) {
LOGGER.error("Zip Error when loading jar file {}", path, ioe);
}
SecureJar jar = SecureJar.from(path);
jar.moduleDataProvider().descriptor().provides().stream()
.map(ModuleDescriptor.Provides::service)
.filter(SERVICES::contains)
.forEach(s -> found.add(new NamedPath(s, path)));
}
}
@@ -210,10 +210,24 @@ public class ModSorter
if (!missingVersions.isEmpty()) {
if (mandatoryMissing > 0) {
LOGGER.error(LOADING, "Missing mandatory dependencies: {}", missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
LOGGER.error(
LOADING,
"Missing or unsupported mandatory dependencies:\n{}",
missingVersions.stream()
.filter(IModInfo.ModVersion::isMandatory)
.map(ver -> formatDependencyError(ver, modVersions))
.collect(Collectors.joining("\n"))
);
}
if (missingVersions.size() - mandatoryMissing > 0) {
LOGGER.error(LOADING, "Unsupported installed optional dependencies: {}", missingVersions.stream().filter(ver -> !ver.isMandatory()).map(IModInfo.ModVersion::getModId).collect(Collectors.joining(", ")));
LOGGER.error(
LOADING,
"Unsupported installed optional dependencies:\n{}",
missingVersions.stream()
.filter(ver -> !ver.isMandatory())
.map(ver -> formatDependencyError(ver, modVersions))
.collect(Collectors.joining("\n"))
);
}
return missingVersions.stream()
@@ -225,6 +239,18 @@ public class ModSorter
return Collections.emptyList();
}
private static String formatDependencyError(IModInfo.ModVersion dependency, Map<String, ArtifactVersion> modVersions)
{
ArtifactVersion installed = modVersions.get(dependency.getModId());
return String.format(
"\tMod ID: '%s', Requested by: '%s', Expected range: '%s', Actual version: '%s'",
dependency.getModId(),
dependency.getOwner().getModId(),
dependency.getVersionRange(),
installed != null ? installed.toString() : "[MISSING]"
);
}
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
{
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
@@ -11,11 +11,17 @@ import net.minecraftforge.forgespi.language.IModInfo;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.slf4j.Logger;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class UniqueModListBuilder
{
@@ -66,28 +72,34 @@ public class UniqueModListBuilder
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
// We can't handle this
final List<IModInfo> dupedMods = modIds.values().stream()
final List<String> dupedModErrors = modIds.values().stream()
.filter(modInfos -> modInfos.size() > 1)
.map(modInfos -> modInfos.get(0))
.toList();
.map(mods -> String.format("\tMod ID: '%s' from mod files: %s",
mods.get(0).getModId(),
mods.stream()
.map(modInfo -> modInfo.getOwningFile().getFile().getFileName()).collect(joining(", "))
)).toList();
if (!dupedMods.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm, Objects.toString(dm)))
.toList();
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
if (!dupedModErrors.isEmpty()) {
LOGGER.error(LOADING, "Found duplicate mods:\n{}", dupedModErrors.stream().collect(joining("\n")));
throw new EarlyLoadingException("Duplicate mods found", null, dupedModErrors.stream()
.map(s -> new EarlyLoadingException.ExceptionData(s))
.toList());
}
final List<ModFile> dupedLibs = versionedLibIds.values().stream()
final List<String> dupedLibErrors = versionedLibIds.values().stream()
.filter(modFiles -> modFiles.size() > 1)
.map(modFiles -> modFiles.get(0))
.toList();
.map(mods -> String.format("\tLibrary: '%s' from files: %s",
getModId(mods.get(0)),
mods.stream()
.map(modFile -> modFile.getFileName()).collect(joining(", "))
)).toList();
if (!dupedLibs.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> duplicateLibErrors = dupedLibs.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedlib.versioned", dm, Objects.toString(dm)))
.toList();
throw new EarlyLoadingException("Duplicate plugins or libraries found", null, duplicateLibErrors);
if (!dupedLibErrors.isEmpty()) {
LOGGER.error(LOADING, "Found duplicate plugins or libraries:\n{}", dupedLibErrors.stream().collect(joining("\n")));
throw new EarlyLoadingException("Duplicate plugins or libraries found", null, dupedLibErrors.stream()
.map(s -> new EarlyLoadingException.ExceptionData(s))
.toList());
}
// Collect unique mod files by module name. This will be used for deduping purposes
@@ -38,7 +38,7 @@ public abstract class AbstractModProvider implements IModProvider
var sj = SecureJar.from(
Manifest::new,
jar -> jar.moduleDataProvider().findFile(MODS_TOML).isPresent() ? mjm : JarMetadata.from(jar, path),
(root, p) -> true,
null,
path
);
@@ -34,7 +34,7 @@ public class ExplodedDirectoryLocator implements IModLocator {
explodedMods.forEach(explodedMod ->
ModJarMetadata.buildFile(this,
jar->jar.moduleDataProvider().findFile("/META-INF/mods.toml").isPresent(),
(a,b) -> true,
null,
explodedMod.paths().toArray(Path[]::new))
.ifPresentOrElse(f->mods.put(explodedMod, f), () -> LOGGER.warn(LogMarkers.LOADING, "Failed to find exploded resource mods.toml in directory {}", explodedMod.paths().get(0).toString())));
return mods.values().stream().map(mf->new IModLocator.ModFileOrException(mf, null)).toList();
@@ -69,7 +69,9 @@ public class ModInfo implements IModInfo, IConfigurable
.map(s -> StringSubstitutor.replace(s, ownFile.map(ModFileInfo::getFile).orElse(null)))
.map(DefaultArtifactVersion::new).orElse(DEFAULT_VERSION);
this.displayName = config.<String>getConfigElement("displayName").orElse(this.modId);
this.description = config.<String>getConfigElement("description").orElse("MISSING DESCRIPTION");
this.description = config.<String>getConfigElement("description")
.orElse("MISSING DESCRIPTION")
.replace("\r\n", "\n").stripIndent();
this.logoFile = Optional.ofNullable(config.<String>getConfigElement("logoFile")
.orElseGet(() -> ownFile.flatMap(mf -> mf.<String>getConfigElement("logoFile")).orElse(null)));
@@ -196,7 +198,7 @@ public class ModInfo implements IModInfo, IConfigurable
private final boolean mandatory;
private final Ordering ordering;
private final DependencySide side;
private Optional<URL> referralUrl;
private final Optional<URL> referralUrl;
public ModVersion(final IModInfo owner, final IConfigurable config) {
this.owner = owner;
@@ -31,7 +31,7 @@ public final class ModJarMetadata implements JarMetadata {
// TODO: Remove helper functions to cleanup api
@Deprecated(forRemoval = true, since="1.18")
static IModFile buildFile(IModLocator locator, Path... files) {
return buildFile(locator, j->true, (a,b) -> true, files).orElseThrow(()->new IllegalArgumentException("Failed to find valid JAR file"));
return buildFile(locator, j->true, null, files).orElseThrow(()->new IllegalArgumentException("Failed to find valid JAR file"));
}
// TODO: Remove helper functions to cleanup api
@@ -43,7 +43,7 @@ public abstract class CommonClientLaunchHandler extends CommonLaunchHandler {
var lowcodelang = LibraryFinder.findPathForMaven(vers.forgeGroup(), "lowcodelanguage", "", "", vers.mcAndForgeVersion());
var mclang = LibraryFinder.findPathForMaven(vers.forgeGroup(), "mclanguage", "", "", vers.mcAndForgeVersion());
return new LocatedPaths(mcstream.build().toList(), (a,b) -> true, modstream.build().toList(), List.of(fmlcore, javafmllang, lowcodelang, mclang));
return new LocatedPaths(mcstream.build().toList(), null, modstream.build().toList(), List.of(fmlcore, javafmllang, lowcodelang, mclang));
}
protected abstract void processMCStream(VersionInfo versionInfo, Stream.Builder<Path> mc, Stream.Builder<List<Path>> mods);
@@ -6,6 +6,7 @@
package net.minecraftforge.fml.loading.targets;
import cpw.mods.jarhandling.SecureJar;
import net.minecraftforge.fml.loading.FileUtils;
import java.io.File;
import java.nio.file.Path;
@@ -29,7 +30,7 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
// The extra jar is on the classpath, so try and pull it out of the legacy classpath
var legacyCP = Objects.requireNonNull(System.getProperty("legacyClassPath"), "Missing legacyClassPath, cannot find client-extra").split(File.pathSeparator);
var extra = Paths.get(Arrays.stream(legacyCP).filter(e -> e.contains("client-extra")).findFirst().orElseThrow(() -> new IllegalStateException("Could not find client-extra in legacy classpath")));
var extra = findJarOnClasspath(legacyCP, "client-extra");
mcstream.add(extra);
// The MC code/Patcher edits are in exploded directories
@@ -77,11 +78,18 @@ public abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
protected List<Path> getFmlStuff(String[] classpath) {
// We also want the FML things, fmlcore, javafmllanguage, mclanguage, I don't like hard coding these, but hey whatever works for now.
return Arrays.stream(classpath)
.filter(e -> e.contains("fmlcore") || e.contains("javafmllanguage") || e.contains("lowcodelanguage") || e.contains("mclanguage"))
.filter(e -> FileUtils.matchFileName(e, "fmlcore", "javafmllanguage", "lowcodelanguage", "mclanguage"))
.map(Paths::get)
.toList();
}
protected static Path findJarOnClasspath(String[] classpath, String match) {
return Paths.get(Arrays.stream(classpath)
.filter(e -> FileUtils.matchFileName(e, match))
.findFirst()
.orElseThrow(() -> new IllegalStateException("Could not find " + match + " in classpath")));
}
protected BiPredicate<String, String> getMcFilter(Path extra, List<Path> minecraft, Stream.Builder<List<Path>> mods) {
final var packages = getPackages();
final var extraPath = extra.toString().replace('\\', '/');
@@ -43,12 +43,18 @@ public abstract class CommonServerLaunchHandler extends CommonLaunchHandler {
}, mcextra
);
BiPredicate<String, String> filter = (path, base) -> true;
final BiPredicate<String, String> alwaysTrueFilter = filter;
var mcstream = Stream.<Path>builder().add(mc).add(mcextra_filtered.getRootPath());
var modstream = Stream.<List<Path>>builder();
filter = processMCStream(vers, mcstream, filter, modstream);
// Ensure backwards compatibility if anything overrides processMCStream()
// and expects the default always true filter by only changing it to null afterwards if left unchanged.
if (filter == alwaysTrueFilter)
filter = null;
var fmlcore = LibraryFinder.findPathForMaven(vers.forgeGroup(), "fmlcore", "", "", vers.mcAndForgeVersion());
var javafmllang = LibraryFinder.findPathForMaven(vers.forgeGroup(), "javafmllanguage", "", "", vers.mcAndForgeVersion());
var lowcodelang = LibraryFinder.findPathForMaven(vers.forgeGroup(), "lowcodelanguage", "", "", vers.mcAndForgeVersion());
@@ -10,8 +10,6 @@ import net.minecraftforge.fml.loading.VersionInfo;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -41,8 +39,4 @@ public abstract class CommonUserdevLaunchHandler extends CommonDevLaunchHandler
}
protected abstract void processStreams(String[] classpath, VersionInfo versionInfo, Stream.Builder<Path> mc, Stream.Builder<List<Path>> mods);
protected static Path findJarOnClasspath(String[] classpath, String match) {
return Paths.get(Arrays.stream(classpath).filter(e -> e.contains(match)).findFirst().orElseThrow(() -> new IllegalStateException("Could not find " + match + " in classpath")));
}
}
+1
View File
@@ -13,6 +13,7 @@
<MarkerFilter marker="REGISTRIES" onMatch="${sys:forge.logging.marker.registries:-DENY}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="REGISTRYDUMP" onMatch="${sys:forge.logging.marker.registrydump:-DENY}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="SPLASH" onMatch="${sys:forge.logging.marker.splash:-DENY}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="RESOURCE-CACHE" onMatch="${sys:forge.logging.marker.resource.cache:-DENY}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="FORGEMOD" onMatch="${sys:forge.logging.marker.forgemod:-ACCEPT}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="LOADING" onMatch="${sys:forge.logging.marker.loading:-ACCEPT}" onMismatch="NEUTRAL"/>
<MarkerFilter marker="CORE" onMatch="${sys:forge.logging.marker.core:-ACCEPT}" onMismatch="NEUTRAL"/>
Binary file not shown.
+2 -1
View File
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+12 -7
View File
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,10 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -143,12 +140,16 @@ fi
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
Vendored
+1
View File
@@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -21,6 +21,8 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import java.util.Optional;
public class FMLModContainer extends ModContainer
@@ -70,6 +72,11 @@ public class FMLModContainer extends ModContainer
}
catch (Throwable e)
{
// When a mod constructor throws an exception, it's wrapped in an InvocationTargetException which hides the
// actual exception from the mod loading error screen.
if (e instanceof InvocationTargetException wrapped)
e = Objects.requireNonNullElse(wrapped.getCause(), e); // unwrap the exception
LOGGER.error(LOADING,"Failed to create mod instance. ModID: {}, class {}", getModId(), modClass.getName(), e);
throw new ModLoadingException(modInfo, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadmod", e, modClass);
}
@@ -51,7 +51,7 @@ public class LowCodeModLanguageProvider implements IModLanguageProvider
throw new ModLoadingException(info, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadmodclass", e);
}
} catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
LOGGER.fatal(LOADING, "Unable to load FMLModContainer, wut?", e);
LOGGER.fatal(LOADING, "Unable to load LowCodeModContainer, wut?", e);
final Class<RuntimeException> mle = (Class<RuntimeException>) LamdbaExceptionUtils.uncheck(() -> Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(() -> Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
throw LamdbaExceptionUtils.uncheck(() -> LamdbaExceptionUtils.uncheck(() -> mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
+6 -6
View File
@@ -16,14 +16,14 @@ Step 1: Open your command-line and browse to the folder where you extracted the
Step 2: You're left with a choice.
If you prefer to use Eclipse:
1. Run the following command: `gradlew genEclipseRuns` (`./gradlew genEclipseRuns` if you are on Mac/Linux)
1. Run the following command: `./gradlew genEclipseRuns`
2. Open Eclipse, Import > Existing Gradle Project > Select Folder
or run `gradlew eclipse` to generate the project.
If you prefer to use IntelliJ:
1. Open IDEA, and import project.
2. Select your build.gradle file and have it import.
3. Run the following command: `gradlew genIntellijRuns` (`./gradlew genIntellijRuns` if you are on Mac/Linux)
3. Run the following command: `./gradlew genIntellijRuns`
4. Refresh the Gradle Project in IDEA if required.
If at any point you are missing libraries in your IDE, or you've run into problems you can
@@ -40,7 +40,7 @@ https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
Additional Resources:
=========================
Community Documentation: https://mcforge.readthedocs.io/en/latest/gettingstarted/
LexManos' Install Video: https://www.youtube.com/watch?v=8VEdtQLuLO0
Forge Forum: https://forums.minecraftforge.net/
Forge Discord: https://discord.gg/UvedJ9m
Community Documentation: https://docs.minecraftforge.net/en/1.19.2/gettingstarted/
LexManos' Install Video: https://youtu.be/8VEdtQLuLO0
Forge Forums: https://forums.minecraftforge.net/
Forge Discord: https://discord.minecraftforge.net/
+95 -71
View File
@@ -1,12 +1,16 @@
plugins {
id 'eclipse'
id 'idea'
id 'maven-publish'
id 'net.minecraftforge.gradle' version '5.1.+'
id 'net.minecraftforge.gradle' version '[6.0,6.2)'
}
version = '1.0'
group = 'com.yourname.modid' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'modid'
version = mod_version
group = mod_group_id
base {
archivesName = mod_id
}
// Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17.
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
@@ -26,14 +30,36 @@ minecraft {
//
// 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@'
mappings channel: mapping_channel, version: mapping_version
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default.
// 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
// 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 {
client {
// applies to all the run configs below
configureEach {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
@@ -49,65 +75,38 @@ minecraft {
property 'forge.logging.console.level', 'debug'
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', 'examplemod'
property 'forge.enabledGameTestNamespaces', mod_id
mods {
examplemod {
"${mod_id}" {
source sourceSets.main
}
}
}
client {
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
property 'forge.enabledGameTestNamespaces', mod_id
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
property 'forge.enabledGameTestNamespaces', 'examplemod'
mods {
examplemod {
source sourceSets.main
}
}
property '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 {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
property 'forge.enabledGameTestNamespaces', 'examplemod'
mods {
examplemod {
source sourceSets.main
}
}
property 'forge.enabledGameTestNamespaces', mod_id
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
// example of overriding the workingDirectory set in configureEach above
workingDirectory project.file('run-data')
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods {
examplemod {
source sourceSets.main
}
}
args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
}
}
}
@@ -126,48 +125,73 @@ repositories {
}
dependencies {
// Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed
// that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft '@FORGE_GROUP@:@FORGE_NAME@:@FORGE_VERSION@'
// 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}"
// Real mod deobf dependency examples - these get remapped to your current mappings
// compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
// runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
// implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
// Examples using mod jars from ./libs
// 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...
// For more info:
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
}
// Example for how to get properties into the manifest for reading at runtime.
jar {
manifest {
attributes([
"Specification-Title" : "examplemod",
"Specification-Vendor" : "examplemodsareus",
"Specification-Version" : "1", // We are version 1 of ourselves
"Implementation-Title" : project.name,
"Implementation-Version" : project.jar.archiveVersion,
"Implementation-Vendor" : "examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
// 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 {
var replaceProperties = [
minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range,
forge_version: forge_version, forge_version_range: forge_version_range,
loader_version_range: loader_version_range,
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
filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
expand replaceProperties + [project: project]
}
}
// Example configuration to allow publishing using the maven-publish plugin
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar')
// 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
// publish.dependsOn('reobfJar')
// Example for how to get properties into the manifest for reading at runtime.
tasks.named('jar', Jar).configure {
manifest {
attributes([
'Specification-Title' : mod_id,
'Specification-Vendor' : mod_authors,
'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")
])
}
// This is the preferred method to reobfuscate your jar file
finalizedBy 'reobfJar'
}
// 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'
// }
publishing {
publications {
mavenJava(MavenPublication) {
register('mavenJava', MavenPublication) {
artifact jar
}
}
+56 -1
View File
@@ -1,4 +1,59 @@
# 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.daemon=false
## Environment Properties
# The Minecraft version must agree with the Forge version to get a valid artifact
minecraft_version=@MC_VERSION@
# 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@)
# 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@,)
# The loader version range can only use the major version of Forge/FML as bounds
loader_version_range=[@FORGE_SPEC_VERSION@,)
# The mapping channel to use for mappings.
# The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"].
# Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin.
#
# | 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 Minecraft Forge.
# Additional setup is needed to use their mappings, see https://parchmentmc.org/docs/getting-started
mapping_channel=@MAPPING_CHANNEL@
# The mapping version to query from the mapping channel.
# This must match the format required by the mapping channel.
mapping_version=@MAPPING_VERSION@
## Mod Properties
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
# Must match the String constant located in the main mod class annotated with @Mod.
mod_id=examplemod
# The human-readable display name for the mod.
mod_name=Example Mod
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=All Rights Reserved
# The mod version. See https://semver.org/
mod_version=1.0.0
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
mod_group_id=com.example.examplemod
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
mod_authors=YourNameHere, OtherNameHere
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
mod_description=Example mod description.\nNewline characters can be used and will be replaced properly.
+9 -2
View File
@@ -1,6 +1,13 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven { url = 'https://maven.minecraftforge.net/' }
maven {
name = 'MinecraftForge'
url = 'https://maven.minecraftforge.net/'
}
}
}
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
}
@@ -0,0 +1,64 @@
package com.example.examplemod;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.config.ModConfigEvent;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Forge's config APIs
@Mod.EventBusSubscriber(modid = ExampleMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Config
{
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ForgeConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items
private static final ForgeConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty(Collections.singletonList("items"), () -> List.of("minecraft:iron_ingot"), Config::validateItemName);
static final ForgeConfigSpec SPEC = BUILDER.build();
public static boolean logDirtBlock;
public static int magicNumber;
public static String magicNumberIntroduction;
public static Set<Item> items;
private static boolean validateItemName(final Object obj)
{
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName));
}
@SubscribeEvent
static void onLoad(final ModConfigEvent event)
{
logDirtBlock = LOG_DIRT_BLOCK.get();
magicNumber = MAGIC_NUMBER.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)))
.collect(Collectors.toSet());
}
}
@@ -9,11 +9,14 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.Material;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.InterModComms;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
@@ -57,13 +60,22 @@ public class ExampleMod
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
// Register our mod's ForgeConfigSpec so that Forge can create and load the config file for us
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
private void commonSetup(final FMLCommonSetupEvent event)
{
// Some common setup code
LOGGER.info("HELLO FROM COMMON SETUP");
LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT));
if (Config.logDirtBlock)
LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT));
LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber);
Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString()));
}
// You can use SubscribeEvent and let the Event Bus discover methods to call
@@ -75,7 +87,7 @@ public class ExampleMod
}
// You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent
@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class ClientModEvents
{
@SubscribeEvent
+31 -37
View File
@@ -6,32 +6,30 @@
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader="javafml" #mandatory
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
loaderVersion="[@FORGE_SPEC_VERSION@,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license="All rights reserved"
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
# A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory
# The modid of the mod
modId="examplemod" #mandatory
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
# see the associated build.gradle script for how to populate this completely automatically during a build
version="${file.jarVersion}" #mandatory
# A display name for the mod
displayName="Example Mod" #mandatory
# A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
modId="${mod_id}" #mandatory
# The version number of the mod
version="${mod_version}" #mandatory
# A display name for the mod
displayName="${mod_name}" #mandatory
# A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/
#updateJSONURL="https://change.me.example.invalid/updates.json" #optional
# A URL for the "homepage" for this mod, displayed in the mod UI
#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
# A file name (in the root of the mod JAR) containing a logo for display
logoFile="examplemod.png" #optional
#logoFile="examplemod.png" #optional
# A text field displayed in the mod UI
credits="Thanks for this example mod goes to Java" #optional
#credits="" #optional
# A text field displayed in the mod UI
authors="Love, Cheese and small house plants" #optional
authors="${mod_authors}" #optional
# Display Test controls the display for your mod in the server connection screen
# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
@@ -41,30 +39,26 @@ authors="Love, Cheese and small house plants" #optional
#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional)
# The description text for the mod (multi line!) (#mandatory)
description='''
This is a long form description of the mod. You can write whatever you want here
Have some lorem ipsum.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sagittis luctus odio eu tempus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque volutpat ligula eget lacus auctor sagittis. In hac habitasse platea dictumst. Nunc gravida elit vitae sem vehicula efficitur. Donec mattis ipsum et arcu lobortis, eleifend sagittis sem rutrum. Cras pharetra quam eget posuere fermentum. Sed id tincidunt justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
'''
description='''${mod_description}'''
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
[[dependencies.examplemod]] #optional
# the modid of the dependency
modId="forge" #mandatory
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory
# The version range of the dependency
versionRange="[@FORGE_SPEC_VERSION@,)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
side="BOTH"
[[dependencies.${mod_id}]] #optional
# the modid of the dependency
modId="forge" #mandatory
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory
# The version range of the dependency
versionRange="${forge_version_range}" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory
# BEFORE - This mod is loaded BEFORE the dependency
# AFTER - This mod is loaded AFTER the dependency
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT, or SERVER
side="BOTH"
# Here's another dependency
[[dependencies.examplemod]]
modId="minecraft"
mandatory=true
[[dependencies.${mod_id}]]
modId="minecraft"
mandatory=true
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="[@MC_VERSION@,@MC_NEXT_VERSION@)"
ordering="NONE"
side="BOTH"
versionRange="${minecraft_version_range}"
ordering="NONE"
side="BOTH"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"pack": {
"description": "examplemod resources",
"description": "${mod_id} resources",
"pack_format": 9,
"forge:resource_pack_format": 9,
"forge:data_pack_format": 10
@@ -0,0 +1,11 @@
--- a/com/mojang/blaze3d/vertex/PoseStack.java
+++ b/com/mojang/blaze3d/vertex/PoseStack.java
@@ -11,7 +_,7 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
-public class PoseStack {
+public class PoseStack implements net.minecraftforge.client.extensions.IForgePoseStack {
private final Deque<PoseStack.Pose> f_85834_ = Util.m_137469_(Queues.newArrayDeque(), (p_85848_) -> {
Matrix4f matrix4f = new Matrix4f();
matrix4f.m_27624_();
@@ -1,6 +1,6 @@
--- a/net/minecraft/CrashReport.java
+++ b/net/minecraft/CrashReport.java
@@ -57,14 +_,8 @@
@@ -57,14 +_,9 @@
if (this.f_127506_ != null && this.f_127506_.length > 0) {
p_127520_.append("-- Head --\n");
p_127520_.append("Thread: ").append(Thread.currentThread().getName()).append("\n");
@@ -12,6 +12,7 @@
- }
-
- p_127520_.append("\n");
+ p_127520_.append(net.minecraftforge.logging.CrashReportAnalyser.appendSuspectedMods(this.f_127501_, this.f_127506_));
+ p_127520_.append("Stacktrace:");
+ p_127520_.append(net.minecraftforge.logging.CrashReportExtender.generateEnhancedStackTrace(this.f_127506_));
}
@@ -21,3 +21,13 @@
if (SharedConstants.f_136183_) {
throw illegalargumentexception;
}
@@ -692,7 +_,8 @@
public static <T, R> Function<T, R> m_143827_(final Function<T, R> p_143828_) {
return new Function<T, R>() {
- private final Map<T, R> f_211548_ = Maps.newHashMap();
+ // FORGE: Allow using memoized functions from multiple threads.
+ private final Map<T, R> f_211548_ = Maps.newConcurrentMap();
public R apply(T p_214691_) {
return this.f_211548_.computeIfAbsent(p_214691_, p_143828_);
@@ -1,5 +1,14 @@
--- a/net/minecraft/client/ClientRecipeBook.java
+++ b/net/minecraft/client/ClientRecipeBook.java
@@ -51,7 +_,7 @@
for(Recipe<?> recipe : p_90643_) {
if (!recipe.m_5598_() && !recipe.m_142505_()) {
RecipeBookCategories recipebookcategories = m_90646_(recipe);
- String s = recipe.m_6076_();
+ String s = recipe.m_6076_().isEmpty() ? recipe.m_6423_().toString() : recipe.m_6076_(); // FORGE: Group value defaults to the recipe's ID if the recipe's explicit group is empty.
if (s.isEmpty()) {
map.computeIfAbsent(recipebookcategories, (p_90645_) -> {
return Lists.newArrayList();
@@ -103,6 +_,8 @@
} else if (recipetype == RecipeType.f_44113_) {
return RecipeBookCategories.SMITHING;
@@ -302,7 +302,7 @@
return;
}
+ if(!this.f_91074_.canInteractWith(entityhitresult.m_82443_(), 0)) return; //Forge: Entity may be traced via attack range, but the player may not have sufficient reach. No padding in client code.
+ if(!this.f_91074_.canInteractWith(entityhitresult.m_82443_(), 0)) break; //Forge: Entity may be traced via attack range, but the player may not have sufficient reach. No padding in client code.
InteractionResult interactionresult = this.f_91072_.m_105230_(this.f_91074_, entity, entityhitresult, interactionhand);
if (!interactionresult.m_19077_()) {
interactionresult = this.f_91072_.m_105226_(this.f_91074_, entity, interactionhand);
@@ -342,6 +342,22 @@
this.f_91026_.m_6180_("gui");
this.f_240378_.m_240688_();
this.f_91065_.m_193832_(this.f_91012_);
@@ -1749,6 +_,7 @@
this.f_91005_.m_120596_();
+ net.minecraftforge.event.ForgeEventFactory.onPreLevelTick(this.f_91073_, () -> true);
try {
this.f_91073_.m_104726_(() -> {
return true;
@@ -1764,6 +_,7 @@
throw new ReportedException(crashreport);
}
+ net.minecraftforge.event.ForgeEventFactory.onPostLevelTick(this.f_91073_, () -> true);
}
this.f_91026_.m_6182_("animateTick");
@@ -1783,6 +_,8 @@
this.f_91026_.m_6182_("keyboard");
this.f_91068_.m_90931_();
@@ -0,0 +1,11 @@
--- a/net/minecraft/client/gui/screens/ConnectScreen.java
+++ b/net/minecraft/client/gui/screens/ConnectScreen.java
@@ -73,6 +_,8 @@
}
if (!optional.isPresent()) {
+ ConnectScreen.f_95683_.error("Couldn't connect to server: Unknown host \"{}\"", p_169266_.m_171863_());
+ net.minecraftforge.network.DualStackUtils.logInitialPreferences();
p_169265_.execute(() -> {
p_169265_.m_91152_(new DisconnectedScreen(ConnectScreen.this.f_95686_, CommonComponents.f_130661_, ConnectScreen.f_169260_));
});
@@ -0,0 +1,14 @@
--- a/net/minecraft/client/gui/screens/PauseScreen.java
+++ b/net/minecraft/client/gui/screens/PauseScreen.java
@@ -77,9 +_,10 @@
this.f_96541_.m_91152_(new SocialInteractionsScreen());
}));
}
+ this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 120 - 16, 204, 20, Component.m_237115_("fml.menu.mods"), modButton -> this.f_96541_.m_91152_(new net.minecraftforge.client.gui.ModListScreen(this))));
Component component = this.f_96541_.m_91090_() ? Component.m_237115_("menu.returnToMenu") : Component.m_237115_("menu.disconnect");
- this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 120 + -16, 204, 20, component, (p_96315_) -> {
+ this.m_142416_(new Button(this.f_96543_ / 2 - 102, this.f_96544_ / 4 + 144 + -16, 204, 20, component, (p_96315_) -> {
boolean flag = this.f_96541_.m_91090_();
boolean flag1 = this.f_96541_.m_91294_();
p_96315_.f_93623_ = false;
@@ -27,7 +27,7 @@
EMPTY(false),
ITEM(false),
BLOCK(false),
@@ -411,10 +_,30 @@
@@ -411,10 +_,29 @@
private ArmPose(boolean p_102896_) {
this.f_102890_ = p_102896_;
@@ -52,8 +52,7 @@
+ }
+
+ public <T extends LivingEntity> void applyTransform(HumanoidModel<T> model, T entity, net.minecraft.world.entity.HumanoidArm arm) {
+ com.google.common.base.Preconditions.checkNotNull(this.forgeArmPose, "applyTransform() must not be called on a vanilla ArmPose!");
+ this.forgeArmPose.applyTransform(model, entity, arm);
+ if (this.forgeArmPose != null) this.forgeArmPose.applyTransform(model, entity, arm);
+ }
+ // FORGE END
}
@@ -19,3 +19,23 @@
this.m_241119_(p_242290_, component);
}
}
@@ -194,7 +_,9 @@
}
boolean m_241171_(ChatType.Bound p_241518_, PlayerChatMessage p_241542_, Component p_241510_) {
- this.f_240348_.f_91065_.m_93076_().m_93785_(p_241510_);
+ Component forgeComponent = net.minecraftforge.client.ForgeHooksClient.onClientChat(p_241518_, p_241510_, p_241542_, p_241542_.m_241067_());
+ if (forgeComponent == null) return false;
+ this.f_240348_.f_91065_.m_93076_().m_93785_(forgeComponent);
this.m_241119_(p_241518_, p_241542_.m_237220_());
this.m_240498_(p_241510_, p_241542_.m_241109_());
this.f_240659_ = Util.m_137550_();
@@ -263,6 +_,8 @@
public void m_240494_(Component p_240522_, boolean p_240642_) {
if (!this.f_240348_.f_91066_.m_231833_().m_231551_() || !this.f_240348_.m_91246_(this.m_240473_(p_240522_))) {
+ p_240522_ = net.minecraftforge.client.ForgeHooksClient.onClientSystemChat(p_240522_, p_240642_);
+ if (p_240522_ == null) return;
if (p_240642_) {
this.f_240348_.f_91065_.m_93063_(p_240522_, false);
} else {
@@ -0,0 +1,11 @@
--- a/net/minecraft/client/multiplayer/resolver/AddressCheck.java
+++ b/net/minecraft/client/multiplayer/resolver/AddressCheck.java
@@ -16,7 +_,7 @@
boolean m_142408_(ServerAddress p_171830_);
static AddressCheck m_171828_() {
- final ImmutableList<Predicate<String>> immutablelist = Streams.stream(ServiceLoader.load(BlockListSupplier.class)).map(BlockListSupplier::createBlockList).filter(Objects::nonNull).collect(ImmutableList.toImmutableList());
+ final ImmutableList<Predicate<String>> immutablelist = Streams.stream(ServiceLoader.load(BlockListSupplier.class, net.minecraftforge.fml.loading.FMLLoader.class.getClassLoader())).map(BlockListSupplier::createBlockList).filter(Objects::nonNull).collect(ImmutableList.toImmutableList());
return new AddressCheck() {
public boolean m_142649_(ResolvedServerAddress p_171835_) {
String s = p_171835_.m_142727_();
@@ -109,7 +109,7 @@
+ BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers);
+ }
+
+ public static void setRenderLayer(Fluid fluid, RenderType type) {
+ public static synchronized void setRenderLayer(Fluid fluid, RenderType type) {
+ com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers().");
+ checkClientLoading();
+ FLUID_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(fluid), type);
@@ -30,3 +30,28 @@
InputStream inputstream = resource.m_215507_();
try {
@@ -232,11 +_,11 @@
private final Set<String> f_173369_ = Sets.newHashSet();
public String m_142138_(boolean p_173374_, String p_173375_) {
- p_173375_ = FileUtil.m_179924_((p_173374_ ? s1 : "shaders/include/") + p_173375_);
- if (!this.f_173369_.add(p_173375_)) {
+ // FORGE: use the mod's namespace to look up resources if specified
+ ResourceLocation resourcelocation = net.minecraftforge.client.ForgeHooksClient.getShaderImportLocation(s1, p_173374_, p_173375_);
+ if (!this.f_173369_.add(resourcelocation.toString())) {
return null;
} else {
- ResourceLocation resourcelocation = new ResourceLocation(p_173375_);
try {
Reader reader = p_173341_.m_215597_(resourcelocation);
@@ -262,7 +_,8 @@
return s2;
} catch (IOException ioexception) {
- ShaderInstance.f_173323_.error("Could not open GLSL import {}: {}", p_173375_, ioexception.getMessage());
+ // FORGE: specify the namespace of the failed import in case of duplicates from multiple mods
+ ShaderInstance.f_173323_.error("Could not open GLSL import {}: {}", resourcelocation, ioexception.getMessage());
return "#error " + ioexception.getMessage();
}
}
@@ -9,7 +9,7 @@
this.f_110901_ = new LiquidBlockRenderer();
}
@@ -45,19 +_,27 @@
@@ -45,19 +_,30 @@
return this.f_110899_;
}
@@ -31,11 +31,14 @@
+ renderBatched(p_234356_, p_234357_, p_234358_, p_234359_, p_234360_, p_234361_, p_234362_, net.minecraftforge.client.model.data.ModelData.EMPTY, null);
+ }
+ public void renderBatched(BlockState p_234356_, BlockPos p_234357_, BlockAndTintGetter p_234358_, PoseStack p_234359_, VertexConsumer p_234360_, boolean p_234361_, RandomSource p_234362_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) {
+ renderBatched(p_234356_, p_234357_, p_234358_, p_234359_, p_234360_, p_234361_, p_234362_, modelData, renderType, true);
+ }
+ public void renderBatched(BlockState p_234356_, BlockPos p_234357_, BlockAndTintGetter p_234358_, PoseStack p_234359_, VertexConsumer p_234360_, boolean p_234361_, RandomSource p_234362_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType, boolean queryModelSpecificData) { // TODO 1.20: Move to the signature above
try {
RenderShape rendershape = p_234356_.m_60799_();
if (rendershape == RenderShape.MODEL) {
- this.f_110900_.m_234379_(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_);
+ this.f_110900_.tesselateBlock(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_, modelData, renderType);
+ this.f_110900_.tesselateBlock(p_234358_, this.m_110910_(p_234356_), p_234356_, p_234357_, p_234359_, p_234360_, p_234361_, p_234362_, p_234356_.m_60726_(p_234357_), OverlayTexture.f_118083_, modelData, renderType, queryModelSpecificData); // TODO 1.20: Remove last argument
}
} catch (Throwable throwable) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/renderer/block/ModelBlockRenderer.java
+++ b/net/minecraft/client/renderer/block/ModelBlockRenderer.java
@@ -40,72 +_,85 @@
@@ -40,72 +_,88 @@
this.f_110995_ = p_110999_;
}
@@ -12,10 +12,13 @@
+ tesselateBlock(p_234380_, p_234381_, p_234382_, p_234383_, p_234384_, p_234385_, p_234386_, p_234387_, p_234388_, p_234389_, net.minecraftforge.client.model.data.ModelData.EMPTY, null);
+ }
+ public void tesselateBlock(BlockAndTintGetter p_111048_, BakedModel p_111049_, BlockState p_111050_, BlockPos p_111051_, PoseStack p_111052_, VertexConsumer p_111053_, boolean p_111054_, RandomSource p_111055_, long p_111056_, int p_111057_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) {
+ tesselateBlock(p_111048_, p_111049_, p_111050_, p_111051_, p_111052_, p_111053_, p_111054_, p_111055_, p_111056_, p_111057_, modelData, renderType, true);
+ }
+ public void tesselateBlock(BlockAndTintGetter p_111048_, BakedModel p_111049_, BlockState p_111050_, BlockPos p_111051_, PoseStack p_111052_, VertexConsumer p_111053_, boolean p_111054_, RandomSource p_111055_, long p_111056_, int p_111057_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType, boolean queryModelSpecificData) { // TODO 1.20: Move to the signature above
+ boolean flag = Minecraft.m_91086_() && p_111050_.getLightEmission(p_111048_, p_111051_) == 0 && p_111049_.useAmbientOcclusion(p_111050_, renderType);
+ Vec3 vec3 = p_111050_.m_60824_(p_111048_, p_111051_);
+ p_111052_.m_85837_(vec3.f_82479_, vec3.f_82480_, vec3.f_82481_);
+ modelData = p_111049_.getModelData(p_111048_, p_111051_, p_111050_, modelData);
+ if (queryModelSpecificData) modelData = p_111049_.getModelData(p_111048_, p_111051_, p_111050_, modelData); // TODO 1.20: Remove this line entirely
try {
if (flag) {
@@ -111,6 +114,14 @@
}
}
@@ -113,6 +_,7 @@
private void m_111012_(BlockAndTintGetter p_111013_, BlockState p_111014_, BlockPos p_111015_, PoseStack p_111016_, VertexConsumer p_111017_, List<BakedQuad> p_111018_, float[] p_111019_, BitSet p_111020_, ModelBlockRenderer.AmbientOcclusionFace p_111021_, int p_111022_) {
for(BakedQuad bakedquad : p_111018_) {
this.m_111039_(p_111013_, p_111014_, p_111015_, bakedquad.m_111303_(), bakedquad.m_111306_(), p_111019_, p_111020_);
+ if (!net.minecraftforge.client.ForgeHooksClient.calculateFaceWithoutAO(p_111013_, p_111014_, p_111015_, bakedquad, p_111020_.get(0), p_111021_.f_111149_, p_111021_.f_111150_))
p_111021_.m_111167_(p_111013_, p_111014_, p_111015_, bakedquad.m_111306_(), p_111019_, p_111020_, bakedquad.m_111307_());
this.m_111023_(p_111013_, p_111014_, p_111015_, p_111017_, p_111016_.m_85850_(), bakedquad, p_111021_.f_111149_[0], p_111021_.f_111149_[1], p_111021_.f_111149_[2], p_111021_.f_111149_[3], p_111021_.f_111150_[0], p_111021_.f_111150_[1], p_111021_.f_111150_[2], p_111021_.f_111150_[3], p_111022_);
}
@@ -217,17 +_,21 @@
}
@@ -0,0 +1,32 @@
--- a/net/minecraft/client/renderer/block/model/BakedQuad.java
+++ b/net/minecraft/client/renderer/block/model/BakedQuad.java
@@ -12,13 +_,19 @@
protected final Direction f_111294_;
protected final TextureAtlasSprite f_111295_;
private final boolean f_111296_;
+ private final boolean hasAmbientOcclusion;
public BakedQuad(int[] p_111298_, int p_111299_, Direction p_111300_, TextureAtlasSprite p_111301_, boolean p_111302_) {
+ this(p_111298_, p_111299_, p_111300_, p_111301_, p_111302_, true);
+ }
+
+ public BakedQuad(int[] p_111298_, int p_111299_, Direction p_111300_, TextureAtlasSprite p_111301_, boolean p_111302_, boolean hasAmbientOcclusion) {
this.f_111292_ = p_111298_;
this.f_111293_ = p_111299_;
this.f_111294_ = p_111300_;
this.f_111295_ = p_111301_;
this.f_111296_ = p_111302_;
+ this.hasAmbientOcclusion = hasAmbientOcclusion;
}
public TextureAtlasSprite m_173410_() {
@@ -43,5 +_,9 @@
public boolean m_111307_() {
return this.f_111296_;
+ }
+
+ public boolean hasAmbientOcclusion() {
+ return this.hasAmbientOcclusion;
}
}
@@ -1,25 +1,31 @@
--- a/net/minecraft/client/renderer/block/model/BlockElementFace.java
+++ b/net/minecraft/client/renderer/block/model/BlockElementFace.java
@@ -19,12 +_,18 @@
@@ -19,12 +_,24 @@
public final int f_111355_;
public final String f_111356_;
public final BlockFaceUV f_111357_;
+ public final int emissivity;
+ public final boolean hasAmbientOcclusion;
public BlockElementFace(@Nullable Direction p_111359_, int p_111360_, String p_111361_, BlockFaceUV p_111362_) {
+ this(p_111359_, p_111360_, p_111361_, p_111362_, 0);
+ this(p_111359_, p_111360_, p_111361_, p_111362_, 0, true);
+ }
+
+ public BlockElementFace(@Nullable Direction p_111359_, int p_111360_, String p_111361_, BlockFaceUV p_111362_, int emissivity) {
+ this(p_111359_, p_111360_, p_111361_, p_111362_, emissivity, true);
+ }
+
+ public BlockElementFace(@Nullable Direction p_111359_, int p_111360_, String p_111361_, BlockFaceUV p_111362_, int emissivity, boolean hasAmbientOcclusion) {
this.f_111354_ = p_111359_;
this.f_111355_ = p_111360_;
this.f_111356_ = p_111361_;
this.f_111357_ = p_111362_;
+ this.emissivity = emissivity;
+ this.hasAmbientOcclusion = hasAmbientOcclusion;
}
@OnlyIn(Dist.CLIENT)
@@ -37,7 +_,10 @@
@@ -37,7 +_,11 @@
int i = this.m_111368_(jsonobject);
String s = this.m_111370_(jsonobject);
BlockFaceUV blockfaceuv = p_111367_.deserialize(jsonobject, BlockFaceUV.class);
@@ -27,7 +33,8 @@
+ int emissivity = GsonHelper.m_13824_(jsonobject, "emissivity", 0);
+ if (emissivity != net.minecraft.util.Mth.m_14045_(emissivity, 0, 15))
+ throw new JsonParseException("The emissivity value must be between 0 and 15. Found: " + emissivity);
+ return new BlockElementFace(direction, i, s, blockfaceuv, emissivity);
+ boolean hasAmbientOcclusion = GsonHelper.m_13855_(jsonobject, "ambientocclusion", true);
+ return new BlockElementFace(direction, i, s, blockfaceuv, emissivity, hasAmbientOcclusion);
}
protected int m_111368_(JsonObject p_111369_) {
@@ -49,7 +49,7 @@
for(BlockElement blockelement : this.m_111436_()) {
for(BlockElementFace blockelementface : blockelement.f_111310_.values()) {
Material material = this.m_111480_(blockelementface.f_111356_);
@@ -181,11 +_,17 @@
@@ -181,11 +_,18 @@
return set1;
}
@@ -62,20 +62,12 @@
+ return net.minecraftforge.client.model.geometry.UnbakedGeometryHelper.bake(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_, p_111455_);
+ }
+
+ @Deprecated //Forge: exposed for our callbacks only. Use the above function.
+ @Deprecated(forRemoval = true, since = "1.19.2") // TODO: We cannot remove it since it's vanilla code, but make it private in 1.20
+ public BakedModel bakeVanilla(ModelBakery p_111450_, BlockModel p_111451_, Function<Material, TextureAtlasSprite> p_111452_, ModelState p_111453_, ResourceLocation p_111454_, boolean p_111455_, net.minecraftforge.client.RenderTypeGroup renderTypes) {
+ if (true) return net.minecraftforge.client.model.geometry.UnbakedGeometryHelper.bakeVanilla(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_); // Redirected, in case anyone actually uses this
TextureAtlasSprite textureatlassprite = p_111452_.apply(this.m_111480_("particle"));
if (this.m_111490_() == ModelBakery.f_119233_) {
return new BuiltInModel(this.m_111491_(), this.m_111446_(p_111450_, p_111451_), textureatlassprite, this.m_111479_().m_111526_());
@@ -204,7 +_,7 @@
}
}
- return simplebakedmodel$builder.m_119533_();
+ return simplebakedmodel$builder.build(renderTypes);
}
}
@@ -268,7 +_,18 @@
ItemTransform itemtransform5 = this.m_111444_(ItemTransforms.TransformType.GUI);
ItemTransform itemtransform6 = this.m_111444_(ItemTransforms.TransformType.GROUND);
@@ -6,7 +6,7 @@
- return new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_);
+ net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction);
+ var quad = new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_);
+ var quad = new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_, p_111603_.hasAmbientOcclusion);
+ net.minecraftforge.client.model.QuadTransformers.settingEmissivity(p_111603_.emissivity).processInPlace(quad);
+ return quad;
}
@@ -1,10 +1,11 @@
--- a/net/minecraft/client/renderer/block/model/ItemModelGenerator.java
+++ b/net/minecraft/client/renderer/block/model/ItemModelGenerator.java
@@ -39,6 +_,7 @@
@@ -39,6 +_,8 @@
map.put("particle", p_111672_.m_111477_("particle") ? Either.left(p_111672_.m_111480_("particle")) : map.get("layer0"));
BlockModel blockmodel = new BlockModel((ResourceLocation)null, list, map, false, p_111672_.m_111479_(), p_111672_.m_111491_(), p_111672_.m_111484_());
blockmodel.f_111416_ = p_111672_.f_111416_;
+ blockmodel.customData.copyFrom(p_111672_.customData);
+ blockmodel.customData.setGui3d(false);
return blockmodel;
}
@@ -88,7 +88,7 @@
if (blockstate.m_60799_() != RenderShape.INVISIBLE) {
- RenderType rendertype2 = ItemBlockRenderTypes.m_109282_(blockstate);
+ var model = blockrenderdispatcher.m_110910_(blockstate);
+ var modelData = getModelData(blockpos2);
+ var modelData = model.getModelData(renderchunkregion, blockpos2, blockstate, getModelData(blockpos2));
+ randomsource.m_188584_(blockstate.m_60726_(blockpos2));
+ for (RenderType rendertype2 : model.getRenderTypes(blockstate, randomsource, modelData)) {
BufferBuilder bufferbuilder2 = p_234471_.m_108839_(rendertype2);
@@ -99,7 +99,7 @@
posestack.m_85836_();
posestack.m_85837_((double)(blockpos2.m_123341_() & 15), (double)(blockpos2.m_123342_() & 15), (double)(blockpos2.m_123343_() & 15));
- blockrenderdispatcher.m_234355_(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource);
+ blockrenderdispatcher.renderBatched(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource, modelData, rendertype2);
+ blockrenderdispatcher.renderBatched(blockstate, blockpos2, renderchunkregion, posestack, bufferbuilder2, true, randomsource, modelData, rendertype2, false);
posestack.m_85849_();
+ }
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/renderer/chunk/RenderChunkRegion.java
+++ b/net/minecraft/client/renderer/chunk/RenderChunkRegion.java
@@ -66,4 +_,9 @@
@@ -66,4 +_,14 @@
public int m_141928_() {
return this.f_112908_.m_141928_();
}
@@ -8,5 +8,10 @@
+ @Override
+ public float getShade(float normalX, float normalY, float normalZ, boolean shade) {
+ return this.f_112908_.getShade(normalX, normalY, normalZ, shade);
+ }
+
+ @Override
+ public net.minecraftforge.client.model.data.ModelDataManager getModelDataManager() {
+ return f_112908_.getModelDataManager();
+ }
}
@@ -8,4 +8,4 @@
+public class CommandSourceStack implements SharedSuggestionProvider, net.minecraftforge.common.extensions.IForgeCommandSourceStack {
public static final SimpleCommandExceptionType f_81286_ = new SimpleCommandExceptionType(Component.m_237115_("permissions.requires.player"));
public static final SimpleCommandExceptionType f_81287_ = new SimpleCommandExceptionType(Component.m_237115_("permissions.requires.entity"));
private final CommandSource f_81288_;
public final CommandSource f_81288_;
@@ -1,5 +1,14 @@
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -343,7 +_,7 @@
DispensibleContainerItem dispensiblecontaineritem = (DispensibleContainerItem)p_123562_.m_41720_();
BlockPos blockpos = p_123561_.m_7961_().m_121945_(p_123561_.m_6414_().m_61143_(DispenserBlock.f_52659_));
Level level = p_123561_.m_7727_();
- if (dispensiblecontaineritem.m_142073_((Player)null, level, blockpos, (BlockHitResult)null)) {
+ if (dispensiblecontaineritem.emptyContents((Player)null, level, blockpos, (BlockHitResult)null, p_123562_)) {
dispensiblecontaineritem.m_142131_((Player)null, level, p_123562_, blockpos);
return new ItemStack(Items.f_42446_);
} else {
@@ -402,9 +_,10 @@
level.m_46597_(blockpos, BaseFireBlock.m_49245_(level, blockpos));
level.m_142346_((Entity)null, GameEvent.f_157797_, blockpos);
@@ -42,8 +42,9 @@
if (!list1.isEmpty()) {
throw new IllegalArgumentException(String.format(Locale.ROOT, "Couldn't define tag %s as it is missing following references: %s", p_236449_, list1.stream().map(Objects::toString).collect(Collectors.joining(","))));
} else {
JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, false)).getOrThrow(false, f_126541_::error);
- JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, false)).getOrThrow(false, f_126541_::error);
- Path path = this.f_236439_.m_236048_(p_236449_);
+ JsonElement jsonelement = TagFile.f_215958_.encodeStart(JsonOps.INSTANCE, new TagFile(list, p_236450_.isReplace())).getOrThrow(false, f_126541_::error);
+ Path path = this.getPath(p_236449_);
+ if (path == null) return; // Forge: Allow running this data provider without writing it. Recipe provider needs valid tags.
@@ -51,5 +51,5 @@
+
+ @Override public int getIndex() { return Integer.MAX_VALUE; }
+ @Override public ResourceLocation getName() { return m_132042_(); }
+ @org.jetbrains.annotations.Nullable @Override public FriendlyByteBuf getInternalData() { return this.f_132030_; }
+ @Override public FriendlyByteBuf getInternalData() { return m_132045_(); }
}
@@ -1,5 +1,14 @@
--- a/net/minecraft/resources/RegistryLoader.java
+++ b/net/minecraft/resources/RegistryLoader.java
@@ -26,7 +_,7 @@
Map<ResourceKey<E>, RegistryResourceAccess.EntryThunk<E>> map = this.f_206750_.m_214030_(p_206764_);
DataResult<WritableRegistry<E>> dataresult = DataResult.success(p_206763_, Lifecycle.stable());
- for(Map.Entry<ResourceKey<E>, RegistryResourceAccess.EntryThunk<E>> entry : map.entrySet()) {
+ for(Map.Entry<ResourceKey<E>, RegistryResourceAccess.EntryThunk<E>> entry : net.minecraftforge.common.ForgeHooks.filterThunks(map)) {
dataresult = dataresult.flatMap((p_214227_) -> {
return this.m_214228_(p_214227_, p_206764_, p_206765_, entry.getKey(), Optional.of(entry.getValue()), p_206766_).map((p_206761_) -> {
return p_214227_;
@@ -48,7 +_,12 @@
if (dataresult != null) {
return dataresult;
@@ -20,11 +20,26 @@
boolean flag = false;
AdvancementProgress advancementprogress = this.m_135996_(p_135989_);
boolean flag1 = advancementprogress.m_8193_();
@@ -248,6 +_,7 @@
@@ -243,11 +_,14 @@
this.m_136008_(p_135989_);
this.f_135967_.add(p_135989_);
flag = true;
+ net.minecraftforge.event.ForgeEventFactory.onAdvancementProgressedEvent(this.f_135968_, p_135989_, advancementprogress, p_135990_, net.minecraftforge.event.entity.player.AdvancementEvent.AdvancementProgressEvent.ProgressType.GRANT);
if (!flag1 && advancementprogress.m_8193_()) {
p_135989_.m_138321_().m_9989_(this.f_135968_);
if (p_135989_.m_138320_() != null && p_135989_.m_138320_().m_14996_() && this.f_135968_.f_19853_.m_46469_().m_46207_(GameRules.f_46153_)) {
this.f_135962_.m_240416_(Component.m_237110_("chat.type.advancement." + p_135989_.m_138320_().m_14992_().m_15548_(), this.f_135968_.m_5446_(), p_135989_.m_138330_()), false);
}
+ net.minecraftforge.common.ForgeHooks.onAdvancement(this.f_135968_, p_135989_);
+ net.minecraftforge.event.ForgeEventFactory.onAdvancementEarnedEvent(this.f_135968_, p_135989_);
}
}
@@ -265,6 +_,7 @@
this.m_136004_(p_135999_);
this.f_135967_.add(p_135999_);
flag = true;
+ net.minecraftforge.event.ForgeEventFactory.onAdvancementProgressedEvent(this.f_135968_, p_135999_, advancementprogress, p_136000_, net.minecraftforge.event.entity.player.AdvancementEvent.AdvancementProgressEvent.ProgressType.REVOKE);
}
if (!advancementprogress.m_8206_()) {
@@ -0,0 +1,10 @@
--- a/net/minecraft/server/commands/SummonCommand.java
+++ b/net/minecraft/server/commands/SummonCommand.java
@@ -55,6 +_,7 @@
throw f_138810_.create();
} else {
if (p_138825_ && entity instanceof Mob) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn((Mob)entity, p_138821_.m_81372_(), (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), null, MobSpawnType.COMMAND))
((Mob)entity).m_6518_(p_138821_.m_81372_(), p_138821_.m_81372_().m_6436_(entity.m_20183_()), MobSpawnType.COMMAND, (SpawnGroupData)null, (CompoundTag)null);
}
@@ -76,7 +76,7 @@
return !component.equals(p_238202_) ? p_238202_ : null;
});
completablefuture.thenAcceptAsync((p_242747_) -> {
@@ -1532,11 +_,13 @@
@@ -1532,9 +_,10 @@
return;
}
@@ -87,11 +87,16 @@
+ if(!ServerGamePacketListenerImpl.this.f_9743_.canInteractWith(entity, 1.5D)) return; //Forge: If the entity cannot be reached, do nothing. Original check was dist < 6, range is 4.5, so vanilla used padding=1.5
ItemStack itemstack = ServerGamePacketListenerImpl.this.f_9743_.m_21120_(p_143679_).m_41777_();
InteractionResult interactionresult = p_143680_.m_143694_(ServerGamePacketListenerImpl.this.f_9743_, entity, p_143679_);
+ if (net.minecraftforge.common.ForgeHooks.onInteractEntityAt(f_9743_, entity, entity.m_20182_(), p_143679_) != null) return;
if (interactionresult.m_19077_()) {
CriteriaTriggers.f_10565_.m_61494_(ServerGamePacketListenerImpl.this.f_9743_, itemstack, entity);
if (interactionresult.m_19080_()) {
@@ -1558,6 +_,8 @@
@@ -1552,12 +_,16 @@
public void m_142143_(InteractionHand p_143682_, Vec3 p_143683_) {
this.m_143678_(p_143682_, (p_143686_, p_143687_, p_143688_) -> {
+ InteractionResult onInteractEntityAtResult = net.minecraftforge.common.ForgeHooks.onInteractEntityAt(f_9743_, entity, p_143683_, p_143682_);
+ if (onInteractEntityAtResult != null) return onInteractEntityAtResult;
return p_143687_.m_7111_(p_143686_, p_143683_, p_143688_);
});
}
public void m_141994_() {
if (!(entity instanceof ItemEntity) && !(entity instanceof ExperienceOrb) && !(entity instanceof AbstractArrow) && entity != ServerGamePacketListenerImpl.this.f_9743_) {
@@ -54,7 +54,7 @@
};
+ }
+
+ private final net.minecraftforge.resource.ResourceCacheManager cacheManager = new net.minecraftforge.resource.ResourceCacheManager(false, net.minecraftforge.common.ForgeConfig.COMMON.indexVanillaPackCachesOnThread, (packType, namespace) -> f_182296_.get(packType).resolve(namespace));
+ private final net.minecraftforge.resource.ResourceCacheManager cacheManager = new net.minecraftforge.resource.ResourceCacheManager(false, "indexVanillaPackCachesOnThread", (packType, namespace) -> f_182296_.get(packType).resolve(namespace));
+
+ @Override
+ public void initForNamespace(final String nameSpace) {
@@ -5,7 +5,7 @@
public PackRepository(Pack.PackConstructor p_10502_, RepositorySource... p_10503_) {
this.f_10500_ = p_10502_;
- this.f_10497_ = ImmutableSet.copyOf(p_10503_);
+ this.f_10497_ = new java.util.HashSet<>(java.util.Arrays.asList(p_10503_));
+ this.f_10497_ = new java.util.LinkedHashSet<>(List.of(p_10503_)); //Forge: This needs to be a mutable set, so that we can add to it later on.
}
public PackRepository(PackType p_143890_, RepositorySource... p_143891_) {
@@ -1,12 +0,0 @@
--- a/net/minecraft/server/packs/resources/FallbackResourceManager.java
+++ b/net/minecraft/server/packs/resources/FallbackResourceManager.java
@@ -53,6 +_,9 @@
private void m_215395_(String p_215396_, @Nullable PackResources p_215397_, @Nullable Predicate<ResourceLocation> p_215398_) {
this.f_10599_.add(new FallbackResourceManager.PackEntry(p_215396_, p_215397_, p_215398_));
+ if (p_215397_ != null) {
+ p_215397_.initForNamespace(this.f_10602_);
+ }
}
public Set<String> m_7187_() {
@@ -19,7 +19,7 @@
private final List<TagEntry> f_215897_ = new ArrayList<>();
public static TagBuilder m_215899_() {
@@ -34,5 +_,16 @@
@@ -34,5 +_,21 @@
public TagBuilder m_215909_(ResourceLocation p_215910_) {
return this.m_215902_(TagEntry.m_215953_(p_215910_));
@@ -34,5 +34,10 @@
+ // FORGE: Shorthand version of replace(true)
+ public TagBuilder replace() {
+ return replace(true);
+ }
+
+ // FORGE: Is this tag set to replace or not?
+ public boolean isReplace() {
+ return this.replace;
}
}
@@ -0,0 +1,12 @@
--- a/net/minecraft/util/SpawnUtil.java
+++ b/net/minecraft/util/SpawnUtil.java
@@ -24,7 +_,8 @@
if (p_216406_.m_6857_().m_61937_(blockpos$mutableblockpos) && m_216398_(p_216406_, p_216410_, blockpos$mutableblockpos, p_216411_)) {
T t = p_216404_.m_20655_(p_216406_, (CompoundTag)null, (Component)null, (Player)null, blockpos$mutableblockpos, p_216405_, false, false);
if (t != null) {
- if (t.m_5545_(p_216406_, p_216405_) && t.m_6914_(p_216406_)) {
+ int res = net.minecraftforge.common.ForgeHooks.canEntitySpawn(t, p_216406_, t.m_20185_(), t.m_20186_(), t.m_20189_(), null, p_216405_);
+ if (res == 1 || (res == 0 && t.m_5545_(p_216406_, p_216405_) && t.m_6914_(p_216406_))) {
p_216406_.m_47205_(t);
return Optional.of(t);
}
@@ -33,14 +33,14 @@
}
@Nullable
@@ -326,6 +_,7 @@
public T m_20600_(ServerLevel p_20601_, @Nullable CompoundTag p_20602_, @Nullable Component p_20603_, @Nullable Player p_20604_, BlockPos p_20605_, MobSpawnType p_20606_, boolean p_20607_, boolean p_20608_) {
T t = this.m_20655_(p_20601_, p_20602_, p_20603_, p_20604_, p_20605_, p_20606_, p_20607_, p_20608_);
if (t != null) {
+ if (t instanceof net.minecraft.world.entity.Mob && net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn((net.minecraft.world.entity.Mob) t, p_20601_, p_20605_.m_123341_(), p_20605_.m_123342_(), p_20605_.m_123343_(), null, p_20606_)) return null;
p_20601_.m_47205_(t);
}
@@ -351,6 +_,7 @@
Mob mob = (Mob)t;
mob.f_20885_ = mob.m_146908_();
mob.f_20883_ = mob.m_146908_();
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_20656_, (float) mob.m_20185_(), (float) mob.m_20186_(), (float) mob.m_20189_(), null, p_20661_))
mob.m_6518_(p_20656_, p_20656_.m_6436_(mob.m_20183_()), p_20661_, (SpawnGroupData)null, p_20657_);
mob.m_8032_();
}
@@ -543,14 +_,23 @@
}
@@ -209,6 +209,15 @@
}
}
@@ -1175,7 +_,7 @@
for(InteractionHand interactionhand : InteractionHand.values()) {
ItemStack itemstack1 = this.m_21120_(interactionhand);
- if (itemstack1.m_150930_(Items.f_42747_)) {
+ if (itemstack1.m_150930_(Items.f_42747_) && net.minecraftforge.common.ForgeHooks.onLivingUseTotem(this, p_21263_, itemstack1, interactionhand)) {
itemstack = itemstack1.m_41777_();
itemstack1.m_41774_(1);
break;
@@ -1185,7 +_,7 @@
if (itemstack != null) {
if (this instanceof ServerPlayer) {
@@ -699,7 +708,7 @@
+
+ @Override
+ public <T> net.minecraftforge.common.util.LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
+ if (this.m_6084_() && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
+ if (capability == net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER && this.m_6084_()) {
+ if (facing == null) return handlers[2].cast();
+ else if (facing.m_122434_().m_122478_()) return handlers[0].cast();
+ else if (facing.m_122434_().m_122479_()) return handlers[1].cast();
@@ -1,13 +1,52 @@
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -211,6 +_,7 @@
@@ -116,6 +_,8 @@
private CompoundTag f_21359_;
private BlockPos f_21360_ = BlockPos.f_121853_;
private float f_21341_ = -1.0F;
+ @Nullable
+ private MobSpawnType spawnType;
protected Mob(EntityType<? extends Mob> p_21368_, Level p_21369_) {
super(p_21368_, p_21369_);
@@ -210,7 +_,11 @@
}
public void m_6710_(@Nullable LivingEntity p_21544_) {
this.f_21362_ = p_21544_;
+ net.minecraftforge.common.ForgeHooks.onLivingSetAttackTarget(this, p_21544_);
- this.f_21362_ = p_21544_;
+ net.minecraftforge.event.entity.living.LivingChangeTargetEvent changeTargetEvent = net.minecraftforge.common.ForgeHooks.onLivingChangeTarget(this, p_21544_, net.minecraftforge.event.entity.living.LivingChangeTargetEvent.LivingTargetType.MOB_TARGET);
+ if(!changeTargetEvent.isCanceled()) {
+ this.f_21362_ = changeTargetEvent.getNewTarget();
+ net.minecraftforge.common.ForgeHooks.onLivingSetAttackTarget(this, this.f_21362_); // TODO: Remove in 1.20
+ }
}
public boolean m_6549_(EntityType<?> p_21399_) {
@@ -408,6 +_,9 @@
p_21484_.m_128379_("NoAI", this.m_21525_());
}
+ if (this.spawnType != null) {
+ p_21484_.m_128359_("forge:spawn_type", this.spawnType.name());
+ }
}
public void m_7378_(CompoundTag p_21450_) {
@@ -460,6 +_,14 @@
}
this.m_21557_(p_21450_.m_128471_("NoAI"));
+
+ if (p_21450_.m_128441_("forge:spawn_type")) {
+ try {
+ this.spawnType = MobSpawnType.valueOf(p_21450_.m_128461_("forge:spawn_type"));
+ } catch (Exception ex) {
+ p_21450_.m_128473_("forge:spawn_type");
+ }
+ }
}
protected void m_7625_(DamageSource p_21389_, boolean p_21390_) {
@@ -499,9 +_,9 @@
public void m_8107_() {
super.m_8107_();
@@ -34,7 +73,26 @@
if (entity != null) {
double d0 = entity.m_20280_(this);
int i = this.m_6095_().m_20674_().m_21611_();
@@ -1374,13 +_,23 @@
@@ -990,6 +_,10 @@
}
+ /**
+ * <p>Calls to this method should be accompanied by firing the {@link net.minecraftforge.event.entity.living.LivingSpawnEvent.SpecialSpawn SpecialSpawn} event via {@link net.minecraftforge.event.ForgeEventFactory#doSpecialSpawn}.</p>
+ * Additionally, if you override this method, you should ensure you either call super, or manually set {@link #spawnType} from your override.
+ */
@Nullable
public SpawnGroupData m_6518_(ServerLevelAccessor p_21434_, DifficultyInstance p_21435_, MobSpawnType p_21436_, @Nullable SpawnGroupData p_21437_, @Nullable CompoundTag p_21438_) {
RandomSource randomsource = p_21434_.m_213780_();
@@ -1000,6 +_,7 @@
this.m_21559_(false);
}
+ this.spawnType = p_21436_;
return p_21437_;
}
@@ -1374,15 +_,25 @@
return false;
}
@@ -51,11 +109,30 @@
this.m_20256_(this.m_20184_().m_82520_(0.0D, 0.3D, 0.0D));
}
+ }
+
}
+ @Override
+ public void jumpInFluid(net.minecraftforge.fluids.FluidType type) {
+ this.jumpInLiquidInternal(() -> super.jumpInFluid(type));
}
+ }
+
public void m_147272_() {
this.f_21345_.m_148096_();
this.m_6274_().m_147343_();
@@ -1404,5 +_,16 @@
public Iterable<BlockPos> m_238383_() {
return ImmutableSet.of(new BlockPos(this.m_20191_().f_82288_, (double)this.m_146904_(), this.m_20191_().f_82290_), new BlockPos(this.m_20191_().f_82288_, (double)this.m_146904_(), this.m_20191_().f_82293_), new BlockPos(this.m_20191_().f_82291_, (double)this.m_146904_(), this.m_20191_().f_82290_), new BlockPos(this.m_20191_().f_82291_, (double)this.m_146904_(), this.m_20191_().f_82293_));
+ }
+
+ /**
+ * {@return the type of spawn that created this mob, if applicable}
+ * If it could not be determined, this will return null.
+ * <p>
+ * This is set via {@link Mob#finalizeSpawn}, so you should not call this from within that method, and instead use the parameter.
+ */
+ @Nullable
+ public final MobSpawnType getSpawnType() {
+ return this.spawnType;
}
}
@@ -1,6 +1,14 @@
--- a/net/minecraft/world/entity/SpawnPlacements.java
+++ b/net/minecraft/world/entity/SpawnPlacements.java
@@ -156,10 +_,26 @@
@@ -42,6 +_,7 @@
public class SpawnPlacements {
private static final Map<EntityType<?>, SpawnPlacements.Data> f_21750_ = Maps.newHashMap();
+ @Deprecated // FORGE: use SpawnPlacementRegisterEvent to register and modify spawn placements
public static <T extends Mob> void m_21754_(EntityType<T> p_21755_, SpawnPlacements.Type p_21756_, Heightmap.Types p_21757_, SpawnPlacements.SpawnPredicate<T> p_21758_) {
SpawnPlacements.Data spawnplacements$data = f_21750_.put(p_21755_, new SpawnPlacements.Data(p_21757_, p_21756_, p_21758_));
if (spawnplacements$data != null) {
@@ -156,10 +_,35 @@
boolean m_217080_(EntityType<T> p_217081_, ServerLevelAccessor p_217082_, MobSpawnType p_217083_, BlockPos p_217084_, RandomSource p_217085_);
}
@@ -26,5 +34,14 @@
+ if (predicate == null) return net.minecraft.world.level.NaturalSpawner.canSpawnAtBody(this, world, pos, type);
+ return predicate.test(world, pos, type);
+ }
+ }
+
+ // ******* FORGE START. INTERNAL USE ONLY! ****** //
+ public static void fireSpawnPlacementEvent()
+ {
+ Map<EntityType<?>, net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.MergedSpawnPredicate<?>> map = Maps.newHashMap();
+ f_21750_.forEach((type, data) -> map.put(type, new net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.MergedSpawnPredicate<>(data.f_21769_, data.f_21768_, data.f_21767_)));
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.event.entity.SpawnPlacementRegisterEvent(map));
+ map.forEach(((entityType, merged) -> f_21750_.put(entityType, new SpawnPlacements.Data(merged.getHeightmapType(), merged.getSpawnType(), merged.build()))));
}
}
@@ -0,0 +1,16 @@
--- a/net/minecraft/world/entity/ai/behavior/StartAttacking.java
+++ b/net/minecraft/world/entity/ai/behavior/StartAttacking.java
@@ -46,7 +_,11 @@
}
public static <E extends Mob> void m_24213_(E p_24214_, LivingEntity p_24215_) {
- p_24214_.m_6274_().m_21879_(MemoryModuleType.f_26372_, p_24215_);
- p_24214_.m_6274_().m_21936_(MemoryModuleType.f_26326_);
+ net.minecraftforge.event.entity.living.LivingChangeTargetEvent changeTargetEvent = net.minecraftforge.common.ForgeHooks.onLivingChangeTarget(p_24214_, p_24215_, net.minecraftforge.event.entity.living.LivingChangeTargetEvent.LivingTargetType.BEHAVIOR_TARGET);
+ if(!changeTargetEvent.isCanceled()) {
+ p_24214_.m_6274_().m_21879_(MemoryModuleType.f_26372_, changeTargetEvent.getNewTarget());
+ p_24214_.m_6274_().m_21936_(MemoryModuleType.f_26326_);
+ net.minecraftforge.common.ForgeHooks.onLivingSetAttackTarget(p_24214_, changeTargetEvent.getNewTarget(), net.minecraftforge.event.entity.living.LivingChangeTargetEvent.LivingTargetType.BEHAVIOR_TARGET); // TODO: Remove in 1.20
+ }
}
}
@@ -1,11 +1,12 @@
--- a/net/minecraft/world/entity/animal/Cat.java
+++ b/net/minecraft/world/entity/animal/Cat.java
@@ -366,7 +_,7 @@
@@ -365,8 +_,8 @@
if (this.m_21830_(p_28153_)) {
if (!(item instanceof DyeItem)) {
if (item.m_41472_() && this.m_6898_(itemstack) && this.m_21223_() < this.m_21233_()) {
+ this.m_5634_((float)itemstack.getFoodProperties(this).m_38744_());
this.m_142075_(p_28153_, p_28154_, itemstack);
- this.m_5634_((float)item.m_41473_().m_38744_());
+ this.m_5634_((float)itemstack.getFoodProperties(this).m_38744_());
return InteractionResult.CONSUME;
}
@@ -1,11 +1,15 @@
--- a/net/minecraft/world/entity/animal/Wolf.java
+++ b/net/minecraft/world/entity/animal/Wolf.java
@@ -329,7 +_,8 @@
@@ -325,11 +_,12 @@
} else {
if (this.m_21824_()) {
if (this.m_6898_(itemstack) && this.m_21223_() < this.m_21233_()) {
+ this.m_5634_((float)itemstack.getFoodProperties(this).m_38744_());
if (!p_30412_.m_150110_().f_35937_) {
itemstack.m_41774_(1);
}
- this.m_5634_((float)item.m_41473_().m_38744_());
+ this.m_5634_((float)itemstack.getFoodProperties(this).m_38744_());
+ this.m_146852_(GameEvent.f_157806_, this);
return InteractionResult.SUCCESS;
}
@@ -38,7 +38,7 @@
+
+ @Override
+ public <T> net.minecraftforge.common.util.LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.core.Direction facing) {
+ if (this.m_6084_() && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY && itemHandler != null)
+ if (capability == net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER && itemHandler != null && this.m_6084_())
+ return itemHandler.cast();
+ return super.getCapability(capability, facing);
+ }
@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
@@ -418,6 +_,7 @@
private SpawnGroupData m_33881_(ServerLevelAccessor p_33882_, DifficultyInstance p_33883_, Mob p_33884_, @Nullable SpawnGroupData p_33885_) {
p_33884_.m_7678_(this.m_20185_(), this.m_20186_(), this.m_20189_(), this.m_146908_(), 0.0F);
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(p_33884_, p_33882_, (float)p_33884_.m_20185_(), (float)p_33884_.m_20186_(), (float)p_33884_.m_20189_(), null, MobSpawnType.JOCKEY))
p_33884_.m_6518_(p_33882_, p_33883_, MobSpawnType.JOCKEY, p_33885_, (CompoundTag)null);
p_33884_.m_7998_(this, true);
return new AgeableMob.AgeableMobGroupData(0.0F);
@@ -1,11 +1,13 @@
--- a/net/minecraft/world/entity/npc/CatSpawner.java
+++ b/net/minecraft/world/entity/npc/CatSpawner.java
@@ -86,8 +_,9 @@
@@ -86,8 +_,11 @@
if (cat == null) {
return 0;
} else {
+ cat.m_20035_(p_35334_, 0.0F, 0.0F); // Fix MC-147659: Some witch huts spawn the incorrect cat
+ if(net.minecraftforge.common.ForgeHooks.canEntitySpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL) == -1) return 0;
+ // Note: This call to canEntitySpawn is erroneous, it is only provided for backwards compatibility.
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL) == -1) return 0;
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(cat, p_35335_, p_35334_.m_123341_(), p_35334_.m_123342_(), p_35334_.m_123343_(), null, MobSpawnType.NATURAL))
cat.m_6518_(p_35335_, p_35335_.m_6436_(p_35334_), MobSpawnType.NATURAL, (SpawnGroupData)null, (CompoundTag)null);
- cat.m_20035_(p_35334_, 0.0F, 0.0F);
p_35335_.m_47205_(cat);
@@ -1,5 +1,14 @@
--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -129,7 +_,7 @@
for(int k = 0; k < 9; ++k) {
int l = (this.f_35977_ + k) % 9;
- if (!this.f_35974_.get(l).m_41793_()) {
+ if (!this.f_35974_.get(l).isNotReplaceableByPickAction(this.f_35978_, l)) {
return l;
}
}
@@ -177,7 +_,8 @@
int i = p_36049_.m_41613_();
ItemStack itemstack = this.m_8020_(p_36048_);
@@ -215,7 +215,11 @@
if (p_36347_.m_6097_()) {
if (!p_36347_.m_7313_(this)) {
float f = (float)this.m_21133_(Attributes.f_22281_);
@@ -1086,7 +_,7 @@
@@ -1082,11 +_,10 @@
float f2 = this.m_36403_(0.5F);
f *= 0.2F + f2 * f2 * 0.8F;
f1 *= f2;
- this.m_36334_();
if (f > 0.0F || f1 > 0.0F) {
boolean flag = f2 > 0.9F;
boolean flag1 = false;
@@ -276,6 +280,14 @@
this.m_21008_(InteractionHand.MAIN_HAND, ItemStack.f_41583_);
}
}
@@ -1212,6 +_,7 @@
}
}
}
+ this.m_36334_(); // FORGE: Moved from beginning of attack() so that getAttackStrengthScale() returns an accurate value during all attack events
}
}
@@ -1228,7 +_,7 @@
}
@@ -431,7 +443,7 @@
+
+ @Override
+ public <T> net.minecraftforge.common.util.LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
+ if (this.m_6084_() && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
+ if (capability == net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER && this.m_6084_()) {
+ if (facing == null) return playerJoinedHandler.cast();
+ else if (facing.m_122434_().m_122478_()) return playerMainHandler.cast();
+ else if (facing.m_122434_().m_122479_()) return playerEquipmentHandler.cast();
@@ -5,7 +5,7 @@
if (!this.f_19853_.f_46443_) {
Entity entity = this.m_37282_();
- if (!(entity instanceof Mob) || this.f_19853_.m_46469_().m_46207_(GameRules.f_46132_)) {
+ if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.f_19853_, this)) {
+ if (!(entity instanceof Mob) || net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.f_19853_, entity)) {
BlockPos blockpos = p_37384_.m_82425_().m_121945_(p_37384_.m_82434_());
if (this.f_19853_.m_46859_(blockpos)) {
this.f_19853_.m_46597_(blockpos, BaseFireBlock.m_49245_(this.f_19853_, blockpos));
@@ -4,7 +4,7 @@
if (entity instanceof ServerPlayer) {
ServerPlayer serverplayer = (ServerPlayer)entity;
if (serverplayer.f_8906_.m_6198_().m_129536_() && serverplayer.f_19853_ == this.f_19853_ && !serverplayer.m_5803_()) {
+ net.minecraftforge.event.entity.EntityTeleportEvent.EnderPearl event = net.minecraftforge.event.ForgeEventFactory.onEnderPearlLand(serverplayer, this.m_20185_(), this.m_20186_(), this.m_20189_(), this, 5.0F);
+ net.minecraftforge.event.entity.EntityTeleportEvent.EnderPearl event = net.minecraftforge.event.ForgeEventFactory.onEnderPearlLand(serverplayer, this.m_20185_(), this.m_20186_(), this.m_20189_(), this, 5.0F, p_37504_);
+ if (!event.isCanceled()) { // Don't indent to lower patch size
if (this.f_19796_.m_188501_() < 0.05F && this.f_19853_.m_46469_().m_46207_(GameRules.f_46134_)) {
Endermite endermite = EntityType.f_20567_.m_20615_(this.f_19853_);
@@ -110,7 +110,7 @@
}
}
@@ -390,7 +_,8 @@
@@ -390,18 +_,19 @@
d1 = (double)p_38156_.m_123342_();
boolean flag = false;
boolean flag1 = false;
@@ -120,7 +120,11 @@
flag = p_38157_.m_61143_(PoweredRailBlock.f_55215_);
flag1 = !flag;
}
@@ -401,22 +_,22 @@
- double d3 = 0.0078125D;
+ double d3 = getSlopeAdjustment();
if (this.m_20069_()) {
d3 *= 0.2D;
}
Vec3 vec31 = this.m_20184_();
@@ -128,26 +132,7 @@
+ RailShape railshape = ((BaseRailBlock)p_38157_.m_60734_()).getRailDirection(p_38157_, this.f_19853_, p_38156_, this);
switch (railshape) {
case ASCENDING_EAST:
- this.m_20256_(vec31.m_82520_(-d3, 0.0D, 0.0D));
+ this.m_20256_(vec31.m_82520_(-1 * getSlopeAdjustment(), 0.0D, 0.0D));
++d1;
break;
case ASCENDING_WEST:
- this.m_20256_(vec31.m_82520_(d3, 0.0D, 0.0D));
+ this.m_20256_(vec31.m_82520_(getSlopeAdjustment(), 0.0D, 0.0D));
++d1;
break;
case ASCENDING_NORTH:
- this.m_20256_(vec31.m_82520_(0.0D, 0.0D, d3));
+ this.m_20256_(vec31.m_82520_(0.0D, 0.0D, getSlopeAdjustment()));
++d1;
break;
case ASCENDING_SOUTH:
- this.m_20256_(vec31.m_82520_(0.0D, 0.0D, -d3));
+ this.m_20256_(vec31.m_82520_(0.0D, 0.0D, -1 * getSlopeAdjustment()));
++d1;
}
this.m_20256_(vec31.m_82520_(-d3, 0.0D, 0.0D));
@@ -447,7 +_,7 @@
}
}
@@ -236,8 +221,8 @@
+ private float currentSpeedCapOnRail = getMaxCartSpeedOnRail();
+ @Override public float getCurrentCartSpeedCapOnRail() { return currentSpeedCapOnRail; }
+ @Override public void setCurrentCartSpeedCapOnRail(float value) { currentSpeedCapOnRail = Math.min(value, getMaxCartSpeedOnRail()); }
+ private float maxSpeedAirLateral = DEFAULT_MAX_SPEED_AIR_LATERAL;
+ @Override public float getMaxSpeedAirLateral() { return maxSpeedAirLateral; }
+ @org.jetbrains.annotations.Nullable private Float maxSpeedAirLateral = null;
+ @Override public float getMaxSpeedAirLateral() { return maxSpeedAirLateral == null ? (float) this.m_7097_() : maxSpeedAirLateral; }
+ @Override public void setMaxSpeedAirLateral(float value) { maxSpeedAirLateral = value; }
+ private float maxSpeedAirVertical = DEFAULT_MAX_SPEED_AIR_VERTICAL;
+ @Override public float getMaxSpeedAirVertical() { return maxSpeedAirVertical; }
@@ -19,7 +19,7 @@
+
+ @Override
+ public <T> net.minecraftforge.common.util.LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.core.Direction facing) {
+ if (this.m_6084_() && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
+ if (capability == net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER && this.m_6084_())
+ return itemHandler.cast();
+ return super.getCapability(capability, facing);
+ }
@@ -10,7 +10,7 @@
+
+ @Override
+ public <T> net.minecraftforge.common.util.LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable net.minecraft.core.Direction facing) {
+ if (this.m_6084_() && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
+ if (capability == net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER && this.m_6084_())
+ return itemHandler.cast();
+ return super.getCapability(capability, facing);
+ }
@@ -12,6 +12,14 @@
for(ContainerListener containerlistener : this.f_38848_) {
containerlistener.m_7934_(this, p_150408_, itemstack1);
}
@@ -400,6 +_,7 @@
ItemStack itemstack11 = this.m_142621_();
p_150434_.m_141945_(itemstack11, slot7.m_7993_(), clickaction);
if (!itemstack11.m_150926_(slot7, clickaction, p_150434_) && !itemstack10.m_150932_(itemstack11, slot7, clickaction, p_150434_, this.m_150446_())) {
+ if (!net.minecraftforge.common.ForgeHooks.onItemStackedOn(itemstack11, itemstack10, slot7, clickaction, p_150434_, m_150446_()))
if (itemstack10.m_41619_()) {
if (!itemstack11.m_41619_()) {
int l2 = clickaction == ClickAction.PRIMARY ? itemstack11.m_41613_() : 1;
@@ -601,14 +_,15 @@
ItemStack itemstack = slot.m_7993_();
if (!itemstack.m_41619_() && ItemStack.m_150942_(p_38904_, itemstack)) {
@@ -1,5 +1,53 @@
--- a/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -34,6 +_,7 @@
}
};
private final ContainerLevelAccess f_39561_;
+ private int xp = -1;
public GrindstoneMenu(int p_39563_, Inventory p_39564_) {
this(p_39563_, p_39564_, ContainerLevelAccess.f_39287_);
@@ -44,12 +_,12 @@
this.f_39561_ = p_39568_;
this.m_38897_(new Slot(this.f_39560_, 0, 49, 19) {
public boolean m_5857_(ItemStack p_39607_) {
- return p_39607_.m_41763_() || p_39607_.m_150930_(Items.f_42690_) || p_39607_.m_41793_();
+ return true; //Allow all items in the slot, not just repairable
}
});
this.m_38897_(new Slot(this.f_39560_, 1, 49, 40) {
public boolean m_5857_(ItemStack p_39616_) {
- return p_39616_.m_41763_() || p_39616_.m_150930_(Items.f_42690_) || p_39616_.m_41793_();
+ return true; //Allow all items in the slot, not just repairable
}
});
this.m_38897_(new Slot(this.f_39559_, 2, 129, 34) {
@@ -58,6 +_,7 @@
}
public void m_142406_(Player p_150574_, ItemStack p_150575_) {
+ if (net.minecraftforge.common.ForgeHooks.onGrindstoneTake(GrindstoneMenu.this.f_39560_, p_39568_, this::m_39631_)) return;
p_39568_.m_39292_((p_39634_, p_39635_) -> {
if (p_39634_ instanceof ServerLevel) {
ExperienceOrb.m_147082_((ServerLevel)p_39634_, Vec3.m_82512_(p_39635_), this.m_39631_(p_39634_));
@@ -70,6 +_,7 @@
}
private int m_39631_(Level p_39632_) {
+ if (xp > -1) return xp;
int l = 0;
l += this.m_39636_(GrindstoneMenu.this.f_39560_.m_8020_(0));
l += this.m_39636_(GrindstoneMenu.this.f_39560_.m_8020_(1));
@@ -122,6 +_,8 @@
ItemStack itemstack1 = this.f_39560_.m_8020_(1);
boolean flag = !itemstack.m_41619_() || !itemstack1.m_41619_();
boolean flag1 = !itemstack.m_41619_() && !itemstack1.m_41619_();
+ this.xp = net.minecraftforge.common.ForgeHooks.onGrindstoneChange(itemstack, itemstack1, this.f_39559_, -1);
+ if (this.xp == Integer.MIN_VALUE)
if (!flag) {
this.f_39559_.m_6836_(0, ItemStack.f_41583_);
} else {
@@ -143,12 +_,13 @@
}
@@ -19,6 +67,17 @@
if (!ItemStack.m_41728_(itemstack, itemstack1)) {
this.f_39559_.m_6836_(0, ItemStack.f_41583_);
this.m_38946_();
@@ -163,6 +_,10 @@
itemstack2 = flag3 ? itemstack : itemstack1;
}
+ // Forge: Skip the repair if the result would give an item stack with a count not normally obtainable
+ if (j > itemstack2.m_41741_())
+ this.f_39559_.m_6836_(0, ItemStack.f_41583_);
+ else
this.f_39559_.m_6836_(0, this.m_39579_(itemstack2, i, j));
}
@@ -175,7 +_,7 @@
for(Map.Entry<Enchantment, Integer> entry : map.entrySet()) {
@@ -38,15 +38,44 @@
p_40704_.m_5496_(p_150709_, 1.0F, 1.0F);
});
p_40703_.m_142346_(p_40704_, GameEvent.f_157816_, blockpos);
@@ -72,7 +_,7 @@
@@ -72,8 +_,8 @@
return InteractionResultHolder.m_19100_(itemstack);
} else {
BlockState blockstate = p_40703_.m_8055_(blockpos);
- BlockPos blockpos2 = blockstate.m_60734_() instanceof LiquidBlockContainer && this.f_40687_ == Fluids.f_76193_ ? blockpos : blockpos1;
- if (this.m_142073_(p_40704_, p_40703_, blockpos2, blockhitresult)) {
+ BlockPos blockpos2 = canBlockContainFluid(p_40703_, blockpos, blockstate) ? blockpos : blockpos1;
if (this.m_142073_(p_40704_, p_40703_, blockpos2, blockhitresult)) {
+ if (this.emptyContents(p_40704_, p_40703_, blockpos2, blockhitresult, itemstack)) {
this.m_142131_(p_40704_, p_40703_, itemstack, blockpos2);
if (p_40704_ instanceof ServerPlayer) {
CriteriaTriggers.f_10591_.m_59469_((ServerPlayer)p_40704_, blockpos2, itemstack);
@@ -98,7 +_,12 @@
public void m_142131_(@Nullable Player p_150711_, Level p_150712_, ItemStack p_150713_, BlockPos p_150714_) {
}
+ @Deprecated //Forge: use the ItemStack sensitive version
public boolean m_142073_(@Nullable Player p_150716_, Level p_150717_, BlockPos p_150718_, @Nullable BlockHitResult p_150719_) {
+ return this.emptyContents(p_150716_, p_150717_, p_150718_, p_150719_, null);
+ }
+
+ public boolean emptyContents(@Nullable Player p_150716_, Level p_150717_, BlockPos p_150718_, @Nullable BlockHitResult p_150719_, @Nullable ItemStack container) {
if (!(this.f_40687_ instanceof FlowingFluid)) {
return false;
} else {
@@ -107,8 +_,12 @@
Material material = blockstate.m_60767_();
boolean flag = blockstate.m_60722_(this.f_40687_);
boolean flag1 = blockstate.m_60795_() || flag || block instanceof LiquidBlockContainer && ((LiquidBlockContainer)block).m_6044_(p_150717_, p_150718_, blockstate, this.f_40687_);
+ java.util.Optional<net.minecraftforge.fluids.FluidStack> containedFluidStack = java.util.Optional.ofNullable(container).flatMap(net.minecraftforge.fluids.FluidUtil::getFluidContained);
if (!flag1) {
- return p_150719_ != null && this.m_142073_(p_150716_, p_150717_, p_150719_.m_82425_().m_121945_(p_150719_.m_82434_()), (BlockHitResult)null);
+ return p_150719_ != null && this.emptyContents(p_150716_, p_150717_, p_150719_.m_82425_().m_121945_(p_150719_.m_82434_()), (BlockHitResult)null, container);
+ } else if (containedFluidStack.isPresent() && this.f_40687_.getFluidType().isVaporizedOnPlacement(p_150717_, p_150718_, containedFluidStack.get())) {
+ this.f_40687_.getFluidType().onVaporize(p_150716_, p_150717_, p_150718_, containedFluidStack.get());
+ return true;
} else if (p_150717_.m_6042_().f_63857_() && this.f_40687_.m_205067_(FluidTags.f_13131_)) {
int i = p_150718_.m_123341_();
int j = p_150718_.m_123342_();
@@ -120,7 +_,7 @@
}
@@ -78,7 +107,7 @@
+ private final java.util.function.Supplier<? extends Fluid> fluidSupplier;
+ public Fluid getFluid() { return fluidSupplier.get(); }
+
+ private boolean canBlockContainFluid(Level worldIn, BlockPos posIn, BlockState blockstate)
+ protected boolean canBlockContainFluid(Level worldIn, BlockPos posIn, BlockState blockstate)
+ {
+ return blockstate.m_60734_() instanceof LiquidBlockContainer && ((LiquidBlockContainer)blockstate.m_60734_()).m_6044_(worldIn, posIn, blockstate, this.f_40687_);
}
@@ -0,0 +1,19 @@
--- a/net/minecraft/world/item/BundleItem.java
+++ b/net/minecraft/world/item/BundleItem.java
@@ -40,7 +_,7 @@
}
public boolean m_142207_(ItemStack p_150733_, Slot p_150734_, ClickAction p_150735_, Player p_150736_) {
- if (p_150735_ != ClickAction.SECONDARY) {
+ if (p_150733_.m_41613_() != 1 || p_150735_ != ClickAction.SECONDARY) {
return false;
} else {
ItemStack itemstack = p_150734_.m_7993_();
@@ -62,6 +_,7 @@
}
public boolean m_142305_(ItemStack p_150742_, ItemStack p_150743_, Slot p_150744_, ClickAction p_150745_, Player p_150746_, SlotAccess p_150747_) {
+ if (p_150742_.m_41613_() != 1) return false;
if (p_150745_ == ClickAction.SECONDARY && p_150744_.m_150651_(p_150746_)) {
if (p_150743_.m_41619_()) {
m_150780_(p_150742_).ifPresent((p_186347_) -> {
@@ -0,0 +1,14 @@
--- a/net/minecraft/world/item/DispensibleContainerItem.java
+++ b/net/minecraft/world/item/DispensibleContainerItem.java
@@ -6,9 +_,10 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.BlockHitResult;
-public interface DispensibleContainerItem {
+public interface DispensibleContainerItem extends net.minecraftforge.common.extensions.IForgeDispensibleContainerItem {
default void m_142131_(@Nullable Player p_150817_, Level p_150818_, ItemStack p_150819_, BlockPos p_150820_) {
}
+ @Deprecated //Forge: use the ItemStack sensitive version
boolean m_142073_(@Nullable Player p_150821_, Level p_150822_, BlockPos p_150823_, @Nullable BlockHitResult p_150824_);
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/world/level/BaseSpawner.java
+++ b/net/minecraft/world/level/BaseSpawner.java
@@ -127,11 +_,15 @@
@@ -127,10 +_,15 @@
entity.m_7678_(entity.m_20185_(), entity.m_20186_(), entity.m_20189_(), randomsource.m_188501_() * 360.0F, 0.0F);
if (entity instanceof Mob) {
Mob mob = (Mob)entity;
@@ -11,11 +11,11 @@
continue;
}
+ // Fire this early so mods can react to mobs that vanilla normally ignores.
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_151312_, (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), this, MobSpawnType.SPAWNER))
if (this.f_45444_.m_186567_().m_128440_() == 1 && this.f_45444_.m_186567_().m_128425_("id", 8)) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, (LevelAccessor)p_151312_, (float)entity.m_20185_(), (float)entity.m_20186_(), (float)entity.m_20189_(), this, MobSpawnType.SPAWNER))
((Mob)entity).m_6518_(p_151312_, p_151312_.m_6436_(entity.m_20183_()), MobSpawnType.SPAWNER, (SpawnGroupData)null, (CompoundTag)null);
}
}
@@ -275,4 +_,12 @@
public double m_45474_() {
return this.f_45446_;
@@ -23,8 +23,8 @@
mob.m_7678_(d0, (double)i, d1, p_47040_.f_46441_.m_188501_() * 360.0F, 0.0F);
- if (m_46991_(p_47040_, mob, d2)) {
+ int canSpawn = net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_47040_, d0, i, d1, null, MobSpawnType.NATURAL);
+ if (canSpawn != -1 && (canSpawn == 1 || m_46991_(p_47040_, mob, d2))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, (LevelAccessor) p_47040_, (float)d0, (float)i, (float)d1, null, MobSpawnType.NATURAL))
+ if (canSpawn == 1 || (canSpawn == 0 && m_46991_(p_47040_, mob, d2))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_47040_, (float)d0, (float)i, (float)d1, null, MobSpawnType.NATURAL))
spawngroupdata = mob.m_6518_(p_47040_, p_47040_.m_6436_(mob.m_20183_()), MobSpawnType.NATURAL, spawngroupdata, (CompoundTag)null);
++j;
++l1;
@@ -75,11 +75,14 @@
}
}
@@ -370,6 +_,7 @@
@@ -370,7 +_,9 @@
entity.m_7678_(d0, (double)blockpos.m_123342_(), d1, p_220454_.m_188501_() * 360.0F, 0.0F);
if (entity instanceof Mob) {
Mob mob = (Mob)entity;
+ if (net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_220451_, d0, blockpos.m_123342_(), d1, null, MobSpawnType.CHUNK_GENERATION) == -1) continue;
if (mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_)) {
- if (mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_)) {
+ int res = net.minecraftforge.common.ForgeHooks.canEntitySpawn(mob, p_220451_, d0, blockpos.m_123342_(), d1, null, MobSpawnType.CHUNK_GENERATION);
+ if (res == 1 || (res == 0 && mob.m_5545_(p_220451_, MobSpawnType.CHUNK_GENERATION) && mob.m_6914_(p_220451_))) {
+ if (!net.minecraftforge.event.ForgeEventFactory.doSpecialSpawn(mob, p_220451_, (float) d0, blockpos.m_123342_(), (float) d1, null, MobSpawnType.CHUNK_GENERATION))
spawngroupdata = mob.m_6518_(p_220451_, p_220451_.m_6436_(mob.m_20183_()), MobSpawnType.CHUNK_GENERATION, spawngroupdata, (CompoundTag)null);
p_220451_.m_47205_(mob);
flag = true;
@@ -8,3 +8,12 @@
if (optional.isPresent()) {
optional.get().m_77743_();
return;
@@ -170,7 +_,7 @@
boolean flag = false;
for(Direction direction : Direction.values()) {
- if (p_49270_.m_8055_(blockpos$mutableblockpos.m_122190_(p_49271_).m_122173_(direction)).m_60713_(Blocks.f_50080_)) {
+ if (p_49270_.m_8055_(blockpos$mutableblockpos.m_122190_(p_49271_).m_122173_(direction)).isPortalFrame(p_49270_, blockpos$mutableblockpos)) {
flag = true;
break;
}
Loaded 100 of 265 files, more files were not shown because too many files have changed in this diff. Show more