Compare commits

..
27 Commits
Author SHA1 Message Date
LexManos 041084d1da Minecraft 1.21.4 2024-12-05 10:22:55 -08:00
LexManos e643d0a11f Remove debug code. Closes #10182 2024-11-21 11:57:00 -08:00
LexManos 5efb8d3f12 Pass the Holder<Enchantment> to Item.canApplyAtEnchantingTable. Closes #10181 2024-11-21 09:52:32 -08:00
LexManos 70537542d1 Fix incorrect patch 2024-11-20 21:04:24 -08:00
LexManos bd4b059c2b Change vanilla registry order to last-seen. Closes #10179 2024-11-20 19:32:28 -08:00
LexManos e0d2c68c5b Call IUnbakedGeometry.bake from BlockModel Closes #10178 2024-11-18 12:30:22 -08:00
LexManos 86d4bda32e Cleanup some warnings 2024-11-18 12:27:16 -08:00
LexManos 98b90f26bc Fix not being able to swim in lava 2024-11-14 23:12:26 -08:00
LexManos 4e7c471fa3 Move mdk back to com/example/examplemod to align with what people expect. 2024-11-14 23:12:11 -08:00
LexManos ec6f9fc6e7 Move MDK example to test sourceset and fix Item/Block registration example. Closes #10139 2024-11-14 14:24:21 -08:00
LexManos 427fef1d4b Added support for using optional tags on Forge registries
Add DeferredRegister.key(name) helper function to make ResourceKey creation easier
Fix TagManager not binding tags
Fix Unbound Tag Exception when modders register tags during Register events Closes #10154
2024-11-14 14:23:00 -08:00
LexManos 83594b0b0a Fix empty tag conditional recipe test 2024-11-14 14:08:00 -08:00
LexManos b76064e57a Fixed missed call to getFriction hook in AbstractBoat 2024-11-12 09:33:05 -08:00
Martijn van den Brand b2bf70c7f1 Pass player argument when firing OnDatapackSyncEvent (#10170) 2024-11-11 20:39:55 -08:00
LexManos 384286a453 Cleanup lifecycle transitions
Fix mod ordering for multi-mod jars
Make dependency resolution issues easier to debug/diagnose
2024-11-11 03:04:23 -08:00
Jonathing d93b7db69a Bump CoreMods to 5.2 (#10156)
Full Changelog:
https://gist.github.com/Jonathing/c3ad28b2a048ac839a7baba5417ee870

The key features are:
- ES6 language support
- Thoroughly updated ASMAPI, with full documentation
- Bug fixes (some optional for backwards-compatibility)
- Partial internal code cleanup
2024-11-08 12:28:39 -08:00
StavWasPlayZ bdbde4bb0f Fix PlayerRenderer#render invoking RenderLivingEvent and not RenderPlayerEvent (#10167) 2024-11-07 20:03:37 -08:00
LexManos e2a68ad903 Fix Powered Rails acting like Activator Rails due to misaligned patch 2024-11-06 23:38:09 -08:00
LexManos 46cfe50108 Properly allow normal mods.toml mods to specify the module names and use a full module-info.
Make FMLModContainer read and apply Add-Opens and Add-Exports manifest entries from mod files.
Forge is now the `net.minecraftforge.forge` module instead of `forge`

https://forums.minecraftforge.net/topic/153333-proper-java-module-support-in-forge-mods/
2024-11-04 16:55:10 -08:00
LexManos 4b423a3087 Fix LootTableLoadEvent not being fired. Closes #10144 2024-10-28 16:08:03 -07:00
LexManos 7d0b07e858 Fix items with use durations of 0 being repeatedly used when use button is held down. Fixed #10150 2024-10-28 14:54:39 -07:00
yurisuika 40220600b0 Add AT for BlockEntityType constructor. (#10149) 2024-10-27 18:05:19 -07:00
Jonathing 0c7a0e927c Add c:stripped_logs and c:stripped_woods tags (#10146) 2024-10-27 02:36:36 +00:00
Jonathing 60e8157b9a Bump CoreMods and ASM (#10145)
CoreMods 5.1.13 changelog: https://gist.github.com/Jonathing/905d142447ecef670526ae27243adbba
2024-10-27 02:34:06 +00:00
Paint_Ninja b8f5e4553b Remove redundant rendering options (#10140) 2024-10-26 20:24:18 +01:00
Ven de587eb50a Fix pause menu having a black background, reverts PR #10115 2024-10-26 12:22:19 -07:00
LexManos 086bcb7148 1.21.3 update 2024-10-25 18:04:34 -07:00
944 changed files with 8672 additions and 15611 deletions

No files matched your search

+1 -12
View File
@@ -26,7 +26,6 @@
/projects/mcp/
/projects/clean/
/projects/forge/
#/patches/*
#occupational hazards
/projects/**/build/
@@ -35,20 +34,10 @@
/projects/**/*.launch
/repo/
src/*/generated/**/.cache/
# Generated by gradle every import
**/src/main/resources/META-INF/MANIFEST.MF
/fmlloader/src/main/resources/forge_version.json
#Patch rejects
#/patches-/
#*.patch.rej
#/projects/*/rejects/
# FML changelog
changelog.txt
*.py
*.7z
/logs/
/ForgeRoot.ipr
/ForgeRoot.iws
@@ -27,6 +27,6 @@ abstract class BytecodePredicateFinder extends BytecodeFinder {
@Internal
@Override
protected Object getData() {
return matches.toSorted(Comparator.<String>naturalOrder()) ?: {throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.')}()
return matches.toSorted(Comparator.naturalOrder()) ?: {throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.')}()
}
}
+6 -2
View File
@@ -47,6 +47,7 @@ jarSigner.autoDetect('forge')
applyPatches {
level 'WARNING'
failOnError = UPDATING != 'true'
rejects = rootProject.layout.projectDirectory.dir('rejects').asFile
}
sourceSets {
@@ -117,7 +118,7 @@ dependencies {
bootstrap(libs.unsafe) // Needed by securemodules
bootstrap(libs.bundles.asm) // Needed by securemodules
implementation(libs.jopt.simple)
implementation(libs.jopt.simple) { version { strictly '5.0.4' } }
installer(libs.bootstrap)
installer(libs.bootstrap.api) // Needed by securemodules
@@ -387,7 +388,7 @@ tasks.register("findFinalizeSpawnTargets", BytecodePredicateFinder) {
return 'net/minecraft/world/level/BaseSpawner' != parent.name // Ignore this class as we special case it.
&& insn.getOpcode().equals(Opcodes.INVOKEVIRTUAL)
&& insn.name == 'm_6518_'
&& insn.desc == '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;';
&& insn.desc == '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;';
}
}
tasks.register('validateDeprecations', ValidateDeprecations) {
@@ -922,6 +923,9 @@ tasks.register('mdkZip', Zip) {
rename 'gitignore\\.txt', '.gitignore'
rename 'gitattributes\\.txt', '.gitattributes'
}
from(rootProject.file('src/test/java/com/example/examplemod/')) {
into('src/main/java/com/example/examplemod/')
}
from(rootProject.file('src/test/generated/mdk_datagen/')) {
into('src/main/resources/')
exclude '**/.cache/'
+6 -25
View File
@@ -2,15 +2,16 @@
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.21.1-&query=$.promos["1.21.1-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.21.1-&query=$.promos["1.21.1-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.20.6-&query=$.promos["1.20.6-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.20.6-&query=$.promos["1.20.6-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)][Download] [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)][Discord] [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)][Patreon]
Forge is a free, open-source modding API all of your favourite mods use!
| Version | Support |
|--------------|-----------------------------|
| All versions | [Supported][Support-Policy] |
| Version | Support |
|---------| ------------- |
| 1.20.x | Active |
| 1.19.x | Legacy |
* [Download]
* [Forum]
@@ -30,19 +31,6 @@ You can download the installer for the *Recommended Build* or the
For support and questions, visit [the Support Forum][Support-Forum] or [the Forge Discord server][Discord].
## Required Java Versions
We require the version of Java that Minecraft requires, which is currently:
| Minecraft | Java |
|---------------|-------------------|
| 1.20.6+ | [21][Adoptium-21] |
| 1.18 - 1.20.4 | [17][Adoptium-17] |
| 1.17.1 | [16][Adoptium-16] |
| 1.16.5- | [8][Adoptium-8] |
**If you are on Windows and have difficulty using Java to launch JAR files, consider using [Jarfix by Johann Löfflmann][Jarfix].**
# Creating Mods
[See the "Getting Started" section in the Forge Documentation][Getting-Started].
@@ -75,15 +63,8 @@ Please ensure you have a valid email address associated with your GitHub account
[Download]: https://files.minecraftforge.net/
[Adoptium-21]: https://adoptium.net/temurin/releases/?version=21
[Adoptium-17]: https://adoptium.net/temurin/releases/?version=17
[Adoptium-16]: https://adoptium.net/temurin/releases/?version=16
[Adoptium-8]: https://adoptium.net/temurin/releases/?version=8
[Jarfix]: https://johann.loefflmann.net/en/software/jarfix/index.html
[Forum]: https://forums.minecraftforge.net/
[Support-Forum]: https://forums.minecraftforge.net/forum/18-support-bug-reports/
[Support-Policy]: https://forums.minecraftforge.net/topic/144690-new-tiered-support-policy
[Discord]: https://discord.minecraftforge.net/
@@ -68,13 +68,15 @@ public interface IModLoadingState {
* @return a transition task for this state
* @see #buildTransition(Executor, Executor, ProgressMeter, Function, Function)
*/
default <T extends Event & IModBusEvent>
Optional<CompletableFuture<Void>> buildTransition(final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar) {
default <T extends Event & IModBusEvent> Optional<CompletableFuture<Void>> buildTransition(
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar
) {
return buildTransition(syncExecutor, parallelExecutor, progressBar,
e -> CompletableFuture.runAsync(() -> {}, e),
e -> CompletableFuture.runAsync(() -> {}, e));
e -> CompletableFuture.completedFuture(null),
e -> CompletableFuture.completedFuture(null)
);
}
/**
@@ -9,8 +9,6 @@ import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
@@ -18,103 +16,67 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
@SuppressWarnings("unchecked")
import org.jetbrains.annotations.Nullable;
public interface IModStateTransition {
/** Magic value to allow me to optimize the futures list by ignoring the default value without making old methods nullable. */
public static final BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> NULL_HOOK = (e, g) -> CompletableFuture.completedFuture(null);
static IModStateTransition buildNoopTransition() {
return new NoopTransition();
return ModStateTransitionHelper.NOOP;
}
default <T extends Event & IModBusEvent>
CompletableFuture<Void> build(final String name,
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
final Function<Executor, CompletableFuture<Void>> preSyncTask,
final Function<Executor, CompletableFuture<Void>> postSyncTask) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
this.eventFunctionStream().get()
.map(f -> (EventGenerator<T>) f)
.reduce((head, tail) -> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, futures, progressBar, head, ModLoadingStage::currentState, tail))
.ifPresent(last -> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, futures, progressBar, last, nextModLoadingStage(), null));
final CompletableFuture<Void> preSyncTaskCF = preSyncTask.apply(syncExecutor);
final CompletableFuture<Void> eventDispatchCF = ModList.gather(futures).thenCompose(ModList::completableFutureFromExceptionList);
final CompletableFuture<Void> postEventDispatchCF = preSyncTaskCF
.thenApplyAsync(n -> {
progressBar.label(progressBar.name() + ": dispatching "+name);
return null;
}, parallelExecutor)
.thenComposeAsync(n -> eventDispatchCF, parallelExecutor)
.thenApply(r -> {
postSyncTask.apply(syncExecutor);
return null;
});
return this.finalActivityGenerator().apply(syncExecutor, postEventDispatchCF);
default CompletableFuture<Void> build(
final String name,
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
final Function<Executor, CompletableFuture<Void>> preSyncTask,
final Function<Executor, CompletableFuture<Void>> postSyncTask
) {
return ModStateTransitionHelper.build(this, name, syncExecutor, parallelExecutor, progressBar, preSyncTask, postSyncTask);
}
default BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextModLoadingStage() {
return ModLoadingStage::nextState;
}
private <T extends Event & IModBusEvent>
EventGenerator<T> addCompletableFutureTaskForModDispatch(final Executor syncExecutor,
final Executor parallelExecutor,
final List<CompletableFuture<Void>> completableFutures,
final ProgressMeter progressBar,
final EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextState,
final EventGenerator<T> nextGenerator) {
final Executor selectedExecutor = threadSelector().apply(syncExecutor, parallelExecutor);
var preDispatchHook = (BiFunction<Executor, EventGenerator<T>, CompletableFuture<Void>>) preDispatchHook();
completableFutures.add(preDispatchHook.apply(selectedExecutor, eventGenerator));
completableFutures.add(ModList.get().futureVisitor(eventGenerator, progressBar, nextState).apply(threadSelector().apply(syncExecutor, parallelExecutor)));
var postDispatchHook = (BiFunction<Executor, EventGenerator<T>, CompletableFuture<Void>>) postDispatchHook();
completableFutures.add(postDispatchHook.apply(selectedExecutor, eventGenerator));
return nextGenerator;
/**
* This used to allow you to fire multiple events during the transition. However, in doing so it would cause issues with the default
* ModContainer's event handlers causing issues such as mod classes being constructed multiple times.
*/
@Deprecated(since = "1.21.3", forRemoval = true)
default Supplier<Stream<EventGenerator<?>>> eventFunctionStream() {
return () -> Stream.ofNullable(eventFunction());
}
@Nullable
default <T extends Event & IModBusEvent> EventGenerator<T> eventFunction() {
return null;
}
Supplier<Stream<EventGenerator<?>>> eventFunctionStream();
ThreadSelector threadSelector();
BiFunction<Executor, CompletableFuture<Void>, CompletableFuture<Void>> finalActivityGenerator();
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> preDispatchHook();
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> postDispatchHook();
/**
* I think this was meant as a way to do some things for each mod container beforge/after the transition had been sent to the container.
* However, the Future returned by this was never linked to the main transition future in any way. Which means that it was run
* in parallel and couldn't guarantee the state of the ModContainer.
* <p>
* Plus all existing code that I could find returned a completedFuture, so I don't think anyone ever used this.
* <p>
* If I were to add this back it would be a CompletableFuture wrap(ModContainer, CompletableFuture)
* <p>
* Added magic value NULL_HOOK to allow me to optimize the futures list by ignoring the default value without making this method nullable.
*/
@Deprecated(since = "1.21.3", forRemoval = true)
default BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> preDispatchHook() { return NULL_HOOK; }
@Deprecated(since = "1.21.3", forRemoval = true)
default BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> postDispatchHook() { return NULL_HOOK; }
interface EventGenerator<T extends Event & IModBusEvent> extends Function<ModContainer, T> {
static <FN extends Event & IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
return fn::apply;
}
}
}
record NoopTransition() implements IModStateTransition {
@Override
public Supplier<Stream<EventGenerator<?>>> eventFunctionStream() {
return Stream::of;
}
@Override
public ThreadSelector threadSelector() {
return ThreadSelector.SYNC;
}
@Override
public BiFunction<Executor, CompletableFuture<Void>, CompletableFuture<Void>> finalActivityGenerator() {
return (e, t) -> t.thenApplyAsync(Function.identity(), e);
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> preDispatchHook() {
return (t, f)-> CompletableFuture.completedFuture(null);
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> postDispatchHook() {
return (t, f)-> CompletableFuture.completedFuture(null);
}
}
@@ -9,18 +9,15 @@ import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -33,13 +30,8 @@ import java.util.function.Supplier;
* a mechanism by which we can wrap actual mod code so that the loader and other
* facilities can treat mods at arms length.
* </p>
*
* @author cpw
*
*/
public abstract class ModContainer
{
public abstract class ModContainer {
protected final String modId;
protected final String namespace;
protected final IModInfo modInfo;
@@ -48,11 +40,14 @@ public abstract class ModContainer
protected final Map<ModLoadingStage, Runnable> activityMap = new EnumMap<>(ModLoadingStage.class);
protected final Map<Class<? extends IExtensionPoint<?>>, Supplier<?>> extensionPoints = new IdentityHashMap<>();
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
final Set<ModContainer> dependencies = new HashSet<>();
/**
* If you want to handle the event, override {@link #dispatchConfigEvent(IConfigEvent)}
*/
@Deprecated(since = "1.21.3", forRemoval = true)
protected Optional<Consumer<IConfigEvent>> configHandler = Optional.empty();
public ModContainer(IModInfo info)
{
public ModContainer(IModInfo info) {
this.modId = info.getModId();
// TODO: Currently not reading namespace from configuration..
this.namespace = this.modId;
@@ -82,58 +77,35 @@ public abstract class ModContainer
/**
* Errored container state, used for filtering. Does nothing.
*/
ModContainer()
{
ModContainer() {
this.modLoadingStage = ModLoadingStage.ERROR;
modId = "BROKEN";
namespace = "BROKEN";
modInfo = null;
}
/**
* @return the modid for this mod
*/
public final String getModId()
{
public final String getModId() {
return modId;
}
/**
* @return the resource prefix for the mod
*/
public final String getNamespace()
{
public final String getNamespace() {
return namespace;
}
/**
* @return The current loading stage for this mod
*/
public ModLoadingStage getCurrentState()
{
public ModLoadingStage getCurrentState() {
return modLoadingStage;
}
public static <T extends Event & IModBusEvent> CompletableFuture<Void> buildTransitionHandler(
final ModContainer target,
final IModStateTransition.EventGenerator<T> eventGenerator,
final ProgressMeter progressBar,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChangeHandler,
final Executor executor) {
return CompletableFuture
.runAsync(() -> {
ModLoadingContext.get().setActiveContainer(target);
target.activityMap.getOrDefault(target.modLoadingStage, ()->{}).run();
target.acceptEvent(eventGenerator.apply(target));
}, executor)
.whenComplete((mc, exception) -> {
target.modLoadingStage = stateChangeHandler.apply(target.modLoadingStage, exception);
progressBar.increment();
ModLoadingContext.get().setActiveContainer(null);
});
}
public IModInfo getModInfo()
{
public IModInfo getModInfo() {
return modInfo;
}
@@ -142,8 +114,7 @@ public abstract class ModContainer
return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get());
}
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension)
{
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension) {
extensionPoints.put(point, extension);
}
@@ -5,9 +5,6 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
import net.minecraftforge.forgespi.language.IModFileInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.ModFileScanData;
@@ -15,27 +12,15 @@ import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -45,27 +30,25 @@ import java.util.stream.Stream;
* Master list of all mods - game-side version. This is classloaded in the game scope and
* can dispatch game level events as a result.
*/
public class ModList
{
//private static final Logger LOGGER = LogManager.getLogger();
public class ModList {
private static ModList INSTANCE;
private final List<IModFileInfo> modFiles;
private final List<IModInfo> sortedList;
private final Map<String, ModFileInfo> fileById;
private final Map<String, IModFileInfo> fileById;
private List<ModContainer> mods;
private Map<String, ModContainer> indexedMods;
private List<ModFileScanData> modFileScanData;
private List<ModContainer> sortedContainers;
private ModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
{
this.modFiles = modFiles.stream().map(ModFile::getModFileInfo).map(ModFileInfo.class::cast).collect(Collectors.toList());
this.sortedList = sortedList.stream().
map(ModInfo.class::cast).
collect(Collectors.toList());
this.fileById = this.modFiles.stream().map(IModFileInfo::getMods).flatMap(Collection::stream).
map(ModInfo.class::cast).
collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile));
private ModList(final List<ModFile> modFiles, final List<ModInfo> sortedList) {
this.modFiles = modFiles.stream().map(ModFile::getModFileInfo).toList();
this.sortedList = sortedList.stream().map(IModInfo.class::cast).toList();
var byId = new HashMap<String, IModFileInfo>();
for (var file : this.modFiles) {
for (var mod : file.getMods())
byId.put(mod.getModId(), mod.getOwningFile());
}
this.fileById = Collections.unmodifiableMap(byId);
CrashReportCallables.registerCrashCallable("Mod List", this::crashReport);
}
@@ -82,12 +65,12 @@ public class ModList
getModContainerState(mainMod.getModId()),
((ModFileInfo)mf.getModFileInfo()).getCodeSigningFingerprint().orElse("NOSIGNATURE"));
}
private String crashReport() {
return "\n"+applyForEachModFile(this::fileToLine).collect(Collectors.joining("\n\t\t", "\t\t", ""));
}
public static ModList of(List<ModFile> modFiles, List<ModInfo> sortedList)
{
public static ModList of(List<ModFile> modFiles, List<ModInfo> sortedList) {
INSTANCE = new ModList(modFiles, sortedList);
return INSTANCE;
}
@@ -96,103 +79,47 @@ public class ModList
return INSTANCE;
}
public List<IModFileInfo> getModFiles()
{
public List<IModFileInfo> getModFiles() {
return modFiles;
}
public IModFileInfo getModFileById(String modid)
{
public IModFileInfo getModFileById(String modid) {
return this.fileById.get(modid);
}
<T extends Event & IModBusEvent> Function<Executor, CompletableFuture<Void>> futureVisitor(
final IModStateTransition.EventGenerator<T> eventGenerator,
final ProgressMeter progressBar,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChange) {
return executor -> gather(
this.mods.stream()
.map(mod -> ModContainer.buildTransitionHandler(mod, eventGenerator, progressBar, stateChange, executor))
.toList()
).thenComposeAsync(ModList::completableFutureFromExceptionList, executor);
}
static CompletionStage<Void> completableFutureFromExceptionList(List<? extends Map.Entry<?, Throwable>> t) {
if (t.stream().noneMatch(e->e.getValue()!=null)) {
return CompletableFuture.completedFuture(null);
} else {
final List<Throwable> throwables = t.stream().filter(e -> e.getValue() != null).map(Map.Entry::getValue).toList();
CompletableFuture<Void> cf = new CompletableFuture<>();
final RuntimeException accumulator = new RuntimeException();
cf.completeExceptionally(accumulator);
for (Throwable exception : throwables) {
if (exception instanceof CompletionException) {
exception = exception.getCause();
}
if (exception.getSuppressed().length != 0) {
for (Throwable throwable : exception.getSuppressed()) {
accumulator.addSuppressed(throwable);
}
} else {
accumulator.addSuppressed(exception);
}
}
return cf;
}
}
static <V> CompletableFuture<List<Map.Entry<V, Throwable>>> gather(List<? extends CompletableFuture<? extends V>> futures) {
List<Map.Entry<V, Throwable>> list = new ArrayList<>(futures.size());
CompletableFuture<?>[] results = new CompletableFuture[futures.size()];
for (var future : futures) {
int i = list.size();
list.add(null);
results[i] = future.whenComplete((result, exception) -> list.set(i, new AbstractMap.SimpleImmutableEntry<>(result, exception)));
}
return CompletableFuture.allOf(results).handle((r, th)->null).thenApply(res -> list);
}
void setLoadedMods(final List<ModContainer> modContainers)
{
void setLoadedMods(final List<ModContainer> modContainers) {
this.mods = modContainers;
this.sortedContainers = modContainers.stream().sorted(Comparator.comparingInt(c->sortedList.indexOf(c.getModInfo()))).toList();
this.sortedContainers = modContainers.stream().sorted(Comparator.comparingInt(c -> sortedList.indexOf(c.getModInfo()))).toList();
this.indexedMods = modContainers.stream().collect(Collectors.toMap(ModContainer::getModId, Function.identity()));
}
@SuppressWarnings("unchecked")
public <T> Optional<T> getModObjectById(String modId)
{
public <T> Optional<T> getModObjectById(String modId) {
return getModContainerById(modId).map(ModContainer::getMod).map(o -> (T) o);
}
public Optional<? extends ModContainer> getModContainerById(String modId)
{
public Optional<? extends ModContainer> getModContainerById(String modId) {
return Optional.ofNullable(this.indexedMods.get(modId));
}
public Optional<? extends ModContainer> getModContainerByObject(Object obj)
{
public Optional<? extends ModContainer> getModContainerByObject(Object obj) {
return mods.stream().filter(mc -> mc.getMod() == obj).findFirst();
}
public List<IModInfo> getMods()
{
public List<IModInfo> getMods() {
return this.sortedList;
}
public boolean isLoaded(String modTarget)
{
public boolean isLoaded(String modTarget) {
return this.indexedMods.containsKey(modTarget);
}
public int size()
{
public int size() {
return mods.size();
}
public List<ModFileScanData> getAllScanData()
{
if (modFileScanData == null)
{
public List<ModFileScanData> getAllScanData() {
if (modFileScanData == null) {
modFileScanData = this.sortedList.stream().
map(IModInfo::getOwningFile).
filter(Objects::nonNull).
@@ -205,8 +132,7 @@ public class ModList
}
public void forEachModFile(Consumer<IModFile> fileConsumer)
{
public void forEachModFile(Consumer<IModFile> fileConsumer) {
modFiles.stream().map(IModFileInfo::getFile).forEach(fileConsumer);
}
@@ -222,13 +148,11 @@ public class ModList
this.sortedContainers.forEach(containerConsumer);
}
public List<ModContainer> getLoadedMods() {
return this.sortedContainers;
}
public <T> Stream<T> applyForEachModContainer(Function<ModContainer, T> function) {
return indexedMods.values().stream().map(function);
}
private static class UncaughtModLoadingException extends ModLoadingException {
public UncaughtModLoadingException(ModLoadingStage stage, Throwable originalException) {
super(null, stage, "fml.modloading.uncaughterror", originalException);
}
}
}
@@ -6,7 +6,6 @@
package net.minecraftforge.fml;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.FMLEnvironment;
@@ -33,8 +32,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.LOADING;
@@ -74,8 +71,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
* and completes the mod loading sequence.</dd>
* </dl>
*/
public class ModLoader
{
public class ModLoader {
private static final Logger LOGGER = LogManager.getLogger();
private final LoadingModList loadingModList;
@@ -84,17 +80,15 @@ public class ModLoader
private final List<ModLoadingWarning> loadingWarnings;
private final ModStateManager stateManager;
private static boolean loadingStateValid;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private final Optional<Consumer<String>> statusConsumer = StartupNotificationManager.modLoaderConsumer();
private final Consumer<String> statusConsumer = StartupNotificationManager.modLoaderConsumer().orElse(msg -> {});
private final Set<IModLoadingState> completedStates = new HashSet<>();
private ModList modList;
private ModLoader()
{
private ModLoader() {
this.loadingModList = FMLLoader.getLoadingModList();
this.loadingExceptions = this.loadingModList.getErrors().stream()
.flatMap(ModLoadingException::fromEarlyException)
.collect(Collectors.toList());
.toList();
this.loadingWarnings = this.loadingModList.getBrokenFiles().stream()
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
.collect(Collectors.toList());
@@ -156,7 +150,7 @@ public class ModLoader
loadingModList.getMods());
if (!this.loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.getFirst());
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
statusConsumer.accept("ERROR DURING MOD LOADING");
modList.setLoadedMods(Collections.emptyList());
loadingStateValid = false;
throw new LoadingFailedException(loadingExceptions);
@@ -169,7 +163,7 @@ public class ModLoader
if (!failedBounds.isEmpty()) {
LOGGER.fatal(CORE, "Failed to validate feature bounds for mods: {}", failedBounds);
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
statusConsumer.accept("ERROR DURING MOD LOADING");
modList.setLoadedMods(Collections.emptyList());
loadingStateValid = false;
throw new LoadingFailedException(failedBounds.stream()
@@ -177,19 +171,42 @@ public class ModLoader
.toList());
}
final List<ModContainer> modContainers = loadingModList.getModFiles().stream()
.map(ModFileInfo::getFile)
.map(this::buildMods)
.flatMap(List::stream)
.toList();
final var modContainers = new HashMap<String, ModContainer>();
for (var file : loadingModList.getModFiles()) {
var containers = this.buildMods(file.getFile());
for (var container : containers)
modContainers.put(container.getModId(), container);
}
if (!loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.getFirst());
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
statusConsumer.accept("ERROR DURING MOD LOADING");
modList.setLoadedMods(Collections.emptyList());
loadingStateValid = false;
throw new LoadingFailedException(loadingExceptions);
}
modList.setLoadedMods(modContainers);
// Gather all dependencies, so we can make sure they have finished their transition events before we fire ours
for (var mod : modContainers.values()) {
for (var dep : mod.getModInfo().getDependencies()) {
var target = modContainers.get(dep.getModId());
if (target == null)
continue;
switch (dep.getOrdering()) {
case AFTER:
mod.dependencies.add(target);
break;
case BEFORE:
target.dependencies.add(mod);
break;
default:
break;
}
}
}
modList.setLoadedMods(modContainers.values().stream().toList());
this.modList = modList;
var stateList = stateManager.getStates(ModLoadingPhase.GATHER);
var progress = StartupMessageManager.addProgressBar("Mod Gather", stateList.stream().mapToInt(mls -> mls.size().applyAsInt(this.modList)).sum());
@@ -214,7 +231,7 @@ public class ModLoader
for (IModLoadingState mls : stateList) {
dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask, progress);
}
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", this.modList.size())));
statusConsumer.accept(String.format("Mod loading complete - %d mods loaded", this.modList.size()));
progress.complete();
}
@@ -243,10 +260,12 @@ public class ModLoader
pb.complete();
syncExecutor.drive(ticker);
}
private void waitForTransition(final IModLoadingState state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<Void> transition) {
while (!transition.isDone()) {
syncExecutor.drive(ticker);
}
try {
transition.join();
} catch (CompletionException e) {
@@ -256,36 +275,38 @@ public class ModLoader
.anyMatch(obj -> !(obj instanceof ModLoadingException));
if (hasNotModLoadingEx) {
LOGGER.fatal("Encountered non-modloading exceptions!", e);
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
statusConsumer.accept("ERROR DURING MOD LOADING");
throw e;
}
final List<ModLoadingException> modLoadingExceptions = Arrays.stream(t.getSuppressed())
.filter(ModLoadingException.class::isInstance)
.map(ModLoadingException.class::cast)
.collect(Collectors.toList());
.toList();
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", state.name(), modLoadingExceptions.size());
statusConsumer.ifPresent(c->c.accept("ERROR DURING MOD LOADING"));
statusConsumer.accept("ERROR DURING MOD LOADING");
throw new LoadingFailedException(modLoadingExceptions);
}
}
private List<ModContainer> buildMods(final IModFile modFile)
{
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
private List<ModContainer> buildMods(final IModFile modFile) {
final Map<String, IModInfo> modInfoMap = new HashMap<>();
for (var mod : modFile.getModFileInfo().getMods())
modInfoMap.put(mod.getModId(), mod);
LOGGER.trace(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
final List<ModContainer> containers = modFile.getScanResult().getTargets()
.entrySet()
.stream()
.map(e -> buildModContainerFromTOML(modFile, modInfoMap, e))
.filter(Objects::nonNull)
.toList();
final List<ModContainer> containers = new ArrayList<>();
for (var entry : modFile.getScanResult().getTargets().entrySet()) {
var container = buildModContainerFromTOML(modFile, modInfoMap, entry.getKey(), entry.getValue());
if (container != null)
containers.add(container);
}
if (containers.size() != modInfoMap.size()) {
var modIds = modInfoMap.values().stream().map(IModInfo::getModId).sorted().toList();
var containerIds = containers.stream().map(c -> c != null ? c.getModId() : "(null)").sorted().toList();
LOGGER.fatal(LOADING,"File {} constructed {} mods: {}, but had {} mods specified: {}",
LOGGER.fatal(LOADING, "File {} constructed {} mods: {}, but had {} mods specified: {}",
modFile.getFilePath(),
containers.size(), containerIds,
modInfoMap.size(), modIds);
@@ -300,15 +321,15 @@ public class ModLoader
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
}
// remove errored mod containers
return containers.stream().filter(mc -> mc.modLoadingStage != ModLoadingStage.ERROR).toList();
}
private ModContainer buildModContainerFromTOML(final IModFile modFile, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
private ModContainer buildModContainerFromTOML(final IModFile modFile, final Map<String, IModInfo> modInfoMap,
final String modId, final IModLanguageProvider.IModLanguageLoader languageLoader
) {
try {
final String modId = idToProviderEntry.getKey();
final IModLanguageProvider.IModLanguageLoader languageLoader = idToProviderEntry.getValue();
IModInfo info = modInfoMap.get(modId);
// throw a missing metadata error if there is no matching modid in the modInfoMap from the mods.toml file
if (info == null)
@@ -351,6 +372,7 @@ public class ModLoader
}
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(e));
}
public <T extends Event & IModBusEvent> T postEventWithReturn(T e) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
@@ -359,9 +381,15 @@ public class ModLoader
ModList.get().forEachModInOrder(mc -> mc.acceptEvent(e));
return e;
}
@SuppressWarnings("removal")
public <T extends Event & IModBusEvent> void postEventWrapContainerInModOrder(T event) {
postEventWithWrapInModOrder(event, (mc, e) -> ModLoadingContext.get().setActiveContainer(mc), (mc, e) -> ModLoadingContext.get().setActiveContainer(null));
postEventWithWrapInModOrder(event,
(mc, e) -> ModLoadingContext.get().setActiveContainer(mc),
(mc, e) -> ModLoadingContext.get().setActiveContainer(null)
);
}
public <T extends Event & IModBusEvent> void postEventWithWrapInModOrder(T e, BiConsumer<ModContainer, T> pre, BiConsumer<ModContainer, T> post) {
if (!loadingStateValid) {
LOGGER.error("Cowardly refusing to send event {} to a broken mod state", e.getClass().getName());
@@ -374,13 +402,11 @@ public class ModLoader
});
}
public List<ModLoadingWarning> getWarnings()
{
public List<ModLoadingWarning> getWarnings() {
return ImmutableList.copyOf(this.loadingWarnings);
}
public void addWarning(ModLoadingWarning warning)
{
public void addWarning(ModLoadingWarning warning) {
this.loadingWarnings.add(warning);
}
@@ -8,20 +8,15 @@ 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
{
public class ModLoadingContext {
private static final Logger LOGGER = LogUtils.getLogger();
private static final ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
private ModContainer activeContainer;
private Object languageExtension;
private ModLoadingStage stage;
/**
* @deprecated Use the context provided by your language loader in your mod's constructor
@@ -26,19 +26,23 @@ import java.util.function.ToIntFunction;
* @param inlineRunnable an optional runnable, which runs before starting the transition from this state to the next
* @param transition optional state transition information
*/
public record ModLoadingState(String name, String previous,
Function<ModList, String> message,
ToIntFunction<ModList> size,
ModLoadingPhase phase,
Optional<Consumer<ModList>> inlineRunnable,
Optional<IModStateTransition> transition) implements IModLoadingState {
public record ModLoadingState(
String name,
String previous,
Function<ModList, String> message,
ToIntFunction<ModList> size,
ModLoadingPhase phase,
Optional<Consumer<ModList>> inlineRunnable,
Optional<IModStateTransition> transition
) implements IModLoadingState {
@Override
public <T extends Event & IModBusEvent>
Optional<CompletableFuture<Void>> buildTransition(final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
final Function<Executor, CompletableFuture<Void>> preSyncTask,
final Function<Executor, CompletableFuture<Void>> postSyncTask) {
public <T extends Event & IModBusEvent> Optional<CompletableFuture<Void>> buildTransition(
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
final Function<Executor, CompletableFuture<Void>> preSyncTask,
final Function<Executor, CompletableFuture<Void>> postSyncTask
) {
var transition = this.transition.orElse(null);
return transition == null
? Optional.empty()
@@ -52,9 +56,12 @@ public record ModLoadingState(String name, String previous,
* @param name the name of the state
* @param previous the name of the immediately previous state to this state
* @param phase the mod loading phase the state belongs to
*
* @deprecated Use the builder
*/
@Deprecated(since = "1.21.3", forRemoval = true)
public static ModLoadingState empty(final String name, final String previous, final ModLoadingPhase phase) {
return new ModLoadingState(name, previous, ml -> "", f->0, phase, Optional.empty(), Optional.empty());
return of(name, phase).after(previous).empty();
}
/**
@@ -65,11 +72,13 @@ public record ModLoadingState(String name, String previous,
* @param previous the name of the immediately previous state to this state
* @param phase the mod loading phase the state belongs to
* @param transition the state transition information
* @return a mod loading state with state transition information and a default message
*
* @deprecated Use the builder
*/
@Deprecated(since = "1.21.3", forRemoval = true)
public static ModLoadingState withTransition(final String name, final String previous, final ModLoadingPhase phase,
final IModStateTransition transition) {
return new ModLoadingState(name, previous, ml -> "Processing transition " + name, ModList::size, phase, Optional.empty(), Optional.of(transition));
return of(name, phase).after(previous).withTransition(transition);
}
/**
@@ -81,11 +90,14 @@ public record ModLoadingState(String name, String previous,
* @param phase the mod loading phase the state belongs to
* @param transition the state transition information
* @return a mod loading state with state transition information and a custom message
*
* @deprecated Use the builder
*/
@Deprecated(since = "1.21.3", forRemoval = true)
public static ModLoadingState withTransition(final String name, final String previous,
final Function<ModList, String> message, final ModLoadingPhase phase,
final IModStateTransition transition) {
return new ModLoadingState(name, previous, message, ModList::size, phase, Optional.empty(), Optional.of(transition));
return of(name, phase).after(previous).message(message).withTransition(transition);
}
/**
@@ -97,9 +109,59 @@ public record ModLoadingState(String name, String previous,
* @param phase the mod loading phase the state belongs to
* @param inline an optional runnable, which runs before starting the transition from this state to the next
* @return a mod loading state with an inline runnable and default message
*
* @deprecated Use the builder
*/
@Deprecated(since = "1.21.3", forRemoval = true)
public static ModLoadingState withInline(final String name, final String previous, final ModLoadingPhase phase,
final Consumer<ModList> inline) {
return new ModLoadingState(name, previous, ml -> "Processing work " + name, ml->0, phase, Optional.of(inline), Optional.empty());
return of(name, phase).after(previous).withInline(inline);
}
public static Builder of(final String name, final ModLoadingPhase phase) {
return new Builder(name, phase);
}
public static class Builder {
private final String name;
private final ModLoadingPhase phase;
private String after;
private Function<ModList, String> message = null;
private ToIntFunction<ModList> size = null;
private Builder(final String name, final ModLoadingPhase phase) {
this.name = name;
this.phase = phase;
}
public Builder after(final ModLoadingState value) { return after(value.name()); }
public Builder after(final String value) {
this.after = value;
return this;
}
public Builder message(final String value) { return message(ml -> value); }
public Builder message(final Function<ModList, String> value) {
this.message = value;
return this;
}
public Builder size(final int value) { return size(ml -> value); }
public Builder size(final ToIntFunction<ModList> value) {
this.size = value;
return this;
}
public ModLoadingState empty() {
return new ModLoadingState(name, after, message != null ? message : ml -> "", size != null ? size : ml -> 0, phase, Optional.empty(), Optional.empty());
}
public ModLoadingState withTransition(final IModStateTransition transition) {
return new ModLoadingState(name, after, message != null ? message : ml -> "Processing transition " + name, size != null ? size : ModList::size, phase, Optional.empty(), Optional.of(transition));
}
public ModLoadingState withInline(final Consumer<ModList> inline) {
return new ModLoadingState(name, after, message != null ? message : ml -> "Processing work " + name, size != null ? size : ml -> 0, phase, Optional.of(inline), Optional.empty());
}
}
}
@@ -0,0 +1,181 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.fml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jetbrains.annotations.ApiStatus;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.IModStateTransition.EventGenerator;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.progress.ProgressMeter;
@ApiStatus.Internal
class ModStateTransitionHelper {
static final IModStateTransition NOOP = new NoopTransition();
record NoopTransition() implements IModStateTransition {
@Override
public ThreadSelector threadSelector() {
return ThreadSelector.SYNC;
}
@Override
public BiFunction<Executor, CompletableFuture<Void>, CompletableFuture<Void>> finalActivityGenerator() {
return (e, t) -> t.thenApplyAsync(Function.identity(), e);
}
}
static <V> CompletionStage<Void> completableFutureFromExceptionList(List<FutureResult<V>> t) {
if (t.stream().noneMatch(e -> e.exception() != null)) {
return CompletableFuture.completedFuture(null);
} else {
final var throwables = t.stream().map(FutureResult::exception).filter(e -> e != null).toList();
CompletableFuture<Void> cf = new CompletableFuture<>();
final RuntimeException accumulator = new RuntimeException();
cf.completeExceptionally(accumulator);
for (Throwable exception : throwables) {
if (exception instanceof CompletionException) {
exception = exception.getCause();
}
if (exception.getSuppressed().length != 0) {
for (Throwable throwable : exception.getSuppressed()) {
accumulator.addSuppressed(throwable);
}
} else {
accumulator.addSuppressed(exception);
}
}
return cf;
}
}
record FutureResult<V>(V value, Throwable exception){}
static <V> CompletableFuture<List<FutureResult<V>>> gather(Collection<? extends CompletableFuture<? extends V>> futures) {
var list = new ArrayList<FutureResult<V>>(futures.size());
var results = new CompletableFuture[futures.size()];
for (var future : futures) {
int i = list.size();
list.add(null);
results[i] = future.whenComplete((result, exception) -> list.set(i, new FutureResult<>(result, exception)));
}
return CompletableFuture.allOf(results).handle((r, th)->null).thenApply(res -> list);
}
private static <T extends Event & IModBusEvent> void addCompletableFutureTaskForModDispatch(
final IModStateTransition transition,
final Executor executor,
final List<CompletableFuture<Void>> completableFutures,
final ProgressMeter progressBar,
final EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextState
) {
@SuppressWarnings("removal")
var preDispatchHook = getHook(transition.preDispatchHook(), executor, eventGenerator);
if (preDispatchHook != null)
completableFutures.add(preDispatchHook);
var modFutures = new LinkedHashMap<String, CompletableFuture<Void>>();
for (var mod : ModList.get().getLoadedMods()) {
CompletableFuture<Void> parent = null;
if (mod.dependencies.isEmpty()) {
parent = CompletableFuture.allOf();
} else {
var deps = new CompletableFuture[mod.dependencies.size()];
int idx = 0;
for (var depContainer : mod.dependencies) {
var future = modFutures.get(depContainer.getModId());
if (future == null)
throw new IllegalStateException("Could not find dependency future " + depContainer.getModId() + " for " + mod.getModId());
deps[idx++] = future;
}
parent = CompletableFuture.allOf(deps);
}
@SuppressWarnings("removal")
var dispatch = parent
.thenRunAsync(() -> {
ModLoadingContext.get().setActiveContainer(mod);
var handler = mod.activityMap.get(mod.modLoadingStage);
if (handler != null)
handler.run();
mod.acceptEvent(eventGenerator.apply(mod));
}, executor)
.whenComplete((mc, exception) -> {
mod.modLoadingStage = nextState.apply(mod.modLoadingStage, exception);
progressBar.increment();
ModLoadingContext.get().setActiveContainer(null);
});
modFutures.put(mod.getModId(), dispatch);
}
var dispatch = gather(modFutures.values()).thenComposeAsync(ModStateTransitionHelper::completableFutureFromExceptionList, executor);
completableFutures.add(dispatch);
@SuppressWarnings("removal")
var postDispatchHook = getHook(transition.preDispatchHook(), executor, eventGenerator);
if (postDispatchHook != null)
completableFutures.add(postDispatchHook);
}
private static <T extends Event & IModBusEvent> CompletableFuture<Void> getHook(BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<Void>> hook, Executor executor, EventGenerator<T> eventGenerator) {
if (hook == null || hook == IModStateTransition.NULL_HOOK) return null;
@SuppressWarnings("unchecked")
var hookTyped = (BiFunction<Executor, EventGenerator<T>, CompletableFuture<Void>>)hook;
return hookTyped.apply(executor, eventGenerator);
}
static <T extends Event & IModBusEvent> CompletableFuture<Void> build(
final IModStateTransition transition,
final String name,
final Executor syncExecutor,
final Executor parallelExecutor,
final ProgressMeter progressBar,
final Function<Executor, CompletableFuture<Void>> preSyncTask,
final Function<Executor, CompletableFuture<Void>> postSyncTask
) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
final var executor = transition.threadSelector().apply(syncExecutor, parallelExecutor);
@SuppressWarnings({ "removal", "unchecked" })
var events = transition.eventFunctionStream().get().map(f -> (EventGenerator<T>)f).toList();
for (int x = 0; x < events.size(); x++) {
var gen = events.get(x);
BiFunction<ModLoadingStage, Throwable, ModLoadingStage> state = x == events.size() - 1
? transition.nextModLoadingStage()
: ModLoadingStage::currentState;
addCompletableFutureTaskForModDispatch(transition, executor, futures, progressBar, gen, state);
}
final CompletableFuture<Void> preSyncTaskCF = preSyncTask.apply(syncExecutor);
final CompletableFuture<Void> eventDispatchCF = gather(futures).thenCompose(ModStateTransitionHelper::completableFutureFromExceptionList);
final CompletableFuture<Void> postEventDispatchCF = preSyncTaskCF
.thenApplyAsync(n -> {
progressBar.label(progressBar.name() + ": dispatching " + name);
return null;
}, parallelExecutor)
.thenComposeAsync(n -> eventDispatchCF, parallelExecutor)
.thenApply(r -> {
postSyncTask.apply(syncExecutor);
return null;
});
return transition.finalActivityGenerator().apply(syncExecutor, postEventDispatchCF);
}
}
@@ -14,7 +14,6 @@ import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.FMLPaths;
import org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import java.io.IOException;
@@ -26,66 +25,9 @@ import static net.minecraftforge.fml.config.ConfigTracker.CONFIG;
public class ConfigFileTypeHandler {
private static final Logger LOGGER = LogUtils.getLogger();
static final ConfigFileTypeHandler TOML = new ConfigFileTypeHandler();
private static final Path defaultConfigPath = FMLPaths.GAMEDIR.get().resolve(FMLConfig.getConfigValue(FMLConfig.ConfigValue.DEFAULT_CONFIG_PATH));
private static final ConfigFileTypeHandler CLIENT = new ConfigFileTypeHandler(ModConfig.Type.CLIENT);
private static final ConfigFileTypeHandler COMMON = new ConfigFileTypeHandler(ModConfig.Type.COMMON);
private static final ConfigFileTypeHandler SERVER = new ConfigFileTypeHandler(ModConfig.Type.SERVER);
private final @Nullable ModConfig.Type type;
private @Nullable FileWatcher watcher;
// exists for bin compat
public ConfigFileTypeHandler() {
this(null);
}
private ConfigFileTypeHandler(@Nullable ModConfig.Type type) {
this.type = type;
}
/**
* Gets the handler for the given {@link ModConfig.Type}.
*
* @param type The type to get the handler for
* @return The handler
*/
static ConfigFileTypeHandler get(ModConfig.Type type) {
return switch (type) {
case CLIENT -> CLIENT;
case COMMON -> COMMON;
case SERVER -> SERVER;
};
}
/**
* Gets the {@link FileWatcher} for this handler, creating it if it doesn't exist and/or has been stopped.
*
* @return The watcher
*
* @apiNote This is package-private so modders can't just call {@link FileWatcher#stop()} and fuck up everything.
*/
FileWatcher getWatcher() {
if (this.watcher == null) {
LOGGER.debug(CONFIG, "Starting watcher for handler: {}", this);
this.watcher = new FileWatcher();
}
return this.watcher;
}
/**
* Stops the {@link FileWatcher} for this handler, and sets it to null afterward. Use this instead of
* {@link FileWatcher#stop()}.
*/
void stopWatcher() {
if (this.watcher == null) return;
LOGGER.debug(CONFIG, "Stopping watcher for hander: {}", this);
this.watcher.stop();
this.watcher = null;
}
public Function<ModConfig, CommentedFileConfig> reader(Path configBasePath) {
return (c) -> {
final Path configPath = configBasePath.resolve(c.getFileName());
@@ -95,7 +37,7 @@ public class ConfigFileTypeHandler {
onFileNotFound((newfile, configFormat)-> setupConfigFile(c, newfile, configFormat)).
writingMode(WritingMode.REPLACE).
build();
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath);
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath.toString());
try
{
configData.load();
@@ -104,9 +46,9 @@ public class ConfigFileTypeHandler {
{
throw new ConfigLoadingException(c, ex);
}
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath);
this.getWatcher().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath);
LOGGER.debug(CONFIG, "Loaded TOML config file {}", configPath.toString());
FileWatcher.defaultInstance().addWatch(configPath, new ConfigWatcher(c, configData, Thread.currentThread().getContextClassLoader()));
LOGGER.debug(CONFIG, "Watching TOML config file {} for changes", configPath.toString());
return configData;
};
}
@@ -114,9 +56,9 @@ public class ConfigFileTypeHandler {
public void unload(Path configBasePath, ModConfig config) {
Path configPath = configBasePath.resolve(config.getFileName());
try {
this.getWatcher().removeWatch(configPath);
FileWatcher.defaultInstance().removeWatch(configBasePath.resolve(config.getFileName()));
} catch (RuntimeException e) {
LOGGER.error("Failed to remove config {} from tracker!", configPath, e);
LOGGER.error("Failed to remove config {} from tracker!", configPath.toString(), e);
}
}
@@ -167,11 +109,6 @@ public class ConfigFileTypeHandler {
}
}
@Override
public String toString() {
return "ConfigFileTypeHandler[" + (type != null ? type : "UNKNOWN") + "]";
}
private record ConfigWatcher(
ModConfig modConfig,
CommentedFileConfig commentedFileConfig,
@@ -8,9 +8,6 @@ package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.mojang.logging.LogUtils;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.loading.FMLPaths;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
@@ -55,24 +52,11 @@ public class ConfigTracker {
}
}
// TODO: [FML] This is only called for the server (outside of forceUnload)
// rethink config implementation for eventual FML rewrite
public void unloadConfigs(ModConfig.Type type, Path configBasePath) {
LOGGER.debug(CONFIG, "Unloading configs type {}", type);
for (ModConfig config : this.configSets.get(type)) {
closeConfig(config, configBasePath);
}
ConfigFileTypeHandler.get(type).stopWatcher();
}
// If there is a better way to do this, please tell me. Because this is FUCKED
public void forceUnload() {
// This is how ModStateProvider handles loading configs. So we're doing the same but with unloadConfigs instead
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> this.unloadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
this.unloadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
// just in case server watcher is still alive somehow...
ConfigFileTypeHandler.get(ModConfig.Type.SERVER).stopWatcher();
}
private static void openConfig(final ModConfig config, final Path configBasePath) {
@@ -30,7 +30,7 @@ public class ModConfig
this.spec = spec;
this.fileName = fileName;
this.container = container;
this.configHandler = ConfigFileTypeHandler.get(type);
this.configHandler = ConfigFileTypeHandler.TOML;
ConfigTracker.INSTANCE.trackConfig(this);
}
@@ -85,6 +85,7 @@ public class DisplayWindow implements ImmediateWindowProvider {
private ScheduledFuture<?> initializationFuture;
private PerformanceInfo performanceInfo;
@SuppressWarnings("unused")
private ScheduledFuture<?> performanceTick;
// The GL ID of the window. Used for all operations
private long window;
@@ -257,7 +258,11 @@ public class DisplayWindow implements ImmediateWindowProvider {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
this.elements.removeIf(element -> !element.render(context, framecount));
for (var itr = this.elements.iterator(); itr.hasNext(); ) {
var element = itr.next();
if (!element.render(context, framecount))
itr.remove();
}
if (animationTimerTrigger.compareAndSet(true, false)) // we only increment the framecount on a periodic basis
framecount++;
}
@@ -488,10 +493,6 @@ public class DisplayWindow implements ImmediateWindowProvider {
glfwPollEvents();
}
private void badWindowHandler(final int code, final long desc) {
LOGGER.error("Got error from GLFW window init: "+code+ " "+MemoryUtil.memUTF8(desc));
}
private void winResize(long window, int width, int height) {
if (window == this.window && width != 0 && height != 0) {
this.winWidth = width;
@@ -640,7 +641,6 @@ public class DisplayWindow implements ImmediateWindowProvider {
public void addMojangTexture(final int textureId) {
this.elements.add(0, RenderElement.mojang(textureId, framecount));
// this.elements.get(0).retire(framecount + 1);
}
public void close() {
@@ -13,10 +13,10 @@ import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
public class PerformanceInfo {
private static final MemoryMXBean MEMORY_BEAN = ManagementFactory.getMemoryMXBean();
private final boolean showCPUUsage;
private final OperatingSystemMXBean osBean;
private final MemoryMXBean memoryBean;
private float memory;
private String text;
@@ -24,14 +24,15 @@ public class PerformanceInfo {
PerformanceInfo() {
showCPUUsage = FMLConfig.getBoolConfigValue(FMLConfig.ConfigValue.EARLY_WINDOW_SHOW_CPU);
osBean = showCPUUsage ? ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class) : null;
memoryBean = ManagementFactory.getMemoryMXBean();
}
void update() {
final MemoryUsage heapusage = MEMORY_BEAN.getHeapMemoryUsage();
final MemoryUsage heapusage = memoryBean.getHeapMemoryUsage();
memory = (float) heapusage.getUsed() / heapusage.getMax();
if (!showCPUUsage) {
text = "Memory: %d/%dMB (%.1f%%)".formatted(heapusage.getUsed() >>> 20, heapusage.getMax() >>> 20, memory * 100f);
text = "Heap: %d/%d MB (%.1f%%) OffHeap: %d MB".formatted(heapusage.getUsed() >> 20, heapusage.getMax() >> 20, memory * 100.0, memoryBean.getNonHeapMemoryUsage().getUsed() >> 20);
return;
}
@@ -43,7 +44,7 @@ public class PerformanceInfo {
cpuText = "CPU: %.1f%%".formatted(cpuLoad * 100f);
}
text = "Memory: %d/%dMB (%.1f%%) %s".formatted(heapusage.getUsed() >>> 20, heapusage.getMax() >>> 20, memory * 100f, cpuText);
text = "Heap: %d/%d MB (%.1f%%) OffHeap: %d MB %s".formatted(heapusage.getUsed() >> 20, heapusage.getMax() >> 20, memory * 100.0, memoryBean.getNonHeapMemoryUsage().getUsed() >> 20, cpuText);
}
String text() {
@@ -11,8 +11,6 @@ import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTTPackContext;
import org.lwjgl.stb.STBTTPackRange;
import org.lwjgl.stb.STBTTPackedchar;
import org.lwjgl.system.MemoryStack;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -50,14 +50,7 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
if (internalName.startsWith("net/minecraft/") || internalName.startsWith("com/mojang/"))
return NAY;
return YAY;
return isEmpty ? NAY : YAY;
}
@Override
@@ -8,7 +8,6 @@ package net.minecraftforge.fml.common.asm;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -36,9 +35,6 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
new VanillaObjectHolderData("net.minecraft.core.particles.ParticleTypes", "particle_type", "net.minecraft.core.particles.ParticleType"),
new VanillaObjectHolderData("net.minecraft.sounds.SoundEvents", "sound_event", "net.minecraft.sounds.SoundEvent")
).collect(Collectors.toUnmodifiableMap(VanillaObjectHolderData::holderClass, Function.identity()));
private static final Set<String> VANILLA_OBJECT_HOLDER_CLASSES = VANILLA_OBJECT_HOLDERS.keySet().stream()
.map(it -> it.replace('.', '/'))
.collect(Collectors.toUnmodifiableSet());
private static final String OBJECT_HOLDER = "Lnet/minecraftforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading.
private static final int PUBLIC_STATIC_FINAL_FLAGS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
@@ -51,26 +47,9 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
// Let's skip processing classes that definitely don't have object holders
String internalName = classType.getInternalName();
// Forge classes that aren't in the debug package (that package is used for tests)
if (internalName.startsWith("net/minecraftforge/") && !internalName.substring(18).contains("debug"))
return NAY;
// Vanilla classes that don't have object holders
if (internalName.startsWith("com/mojang/"))
return NAY;
// ...except specific ones we added to the VANILLA_OBJECT_HOLDERS map
if (internalName.startsWith("net/minecraft/") && !VANILLA_OBJECT_HOLDER_CLASSES.contains(internalName))
return NAY;
return YAY;
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
{
return isEmpty ? NAY : YAY;
}
private static boolean hasHolder(List<AnnotationNode> lst) {
@@ -48,15 +48,9 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
if (internalName.startsWith("net/minecraftforge/") || internalName.startsWith("com/mojang/"))
return NAY;
return YAY;
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
{
return isEmpty ? NAY : YAY;
}
@Override
@@ -65,14 +59,15 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
if ((classNode.access & Opcodes.ACC_ENUM) == 0)
return ComputeFlags.NO_REWRITE;
if (!classNode.interfaces.contains(MARKER_IFACE.getInternalName()))
return ComputeFlags.NO_REWRITE;
Type array = Type.getType("[" + classType.getDescriptor());
String arrayDesc = array.getDescriptor();
FieldNode values = classNode.fields.stream().filter(f -> f.desc.equals(arrayDesc) && ((f.access & FLAGS) == FLAGS)).findFirst().orElse(null);
if (!classNode.interfaces.contains(MARKER_IFACE.getInternalName())) {
return ComputeFlags.NO_REWRITE;
}
//Static methods named "create" with first argument as a string
List<MethodNode> candidates = classNode.methods.stream()
.filter(m -> ((m.access & Opcodes.ACC_STATIC) != 0) && m.name.equals("create"))
@@ -6,14 +6,13 @@
package net.minecraftforge.fml.loading;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class BackgroundWaiter {
private static final ExecutorService runner = Executors.newSingleThreadExecutor();
public static void runAndTick(Runnable r, Runnable tick) {
var runner = Executors.newSingleThreadExecutor();
ImmediateWindowHandler.updateProgress("Loading bootstrap resources");
final Future<?> work = runner.submit(r);
do {
@@ -54,9 +54,6 @@ public class FMLLoader {
LOGGER.debug(CORE, "Detected version data : {}", versionInfo);
LOGGER.debug(CORE, "FML {} loading", LauncherVersion.getVersion());
// Allows us to communicate properties with other services through ModLauncher
setupBlackboardKeys();
checkPackage(ITransformationService.class, "4.0", "ModLauncher");
accessTransformer = getPlugin(env, "accesstransformer", "1.0", "AccessTransformer");
/*eventBus =*/ getPlugin(env, "eventbus", "1.0", "EventBus");
@@ -121,12 +118,6 @@ public class FMLLoader {
return providers.get(0);
}
private static void setupBlackboardKeys() {
LOGGER.debug(CORE, "Requesting CoreMods to not apply the fix for ASMAPI.findFirstInstructionBefore by default");
var blackboardKey = TypesafeMap.Key.getOrCreate(Launcher.INSTANCE.blackboard(), "coremods.use_old_findFirstInstructionBefore", Boolean.class);
Launcher.INSTANCE.blackboard().<Boolean>computeIfAbsent(blackboardKey, k -> true);
}
static void setupLaunchHandler(final IEnvironment environment, final Map<String, Object> arguments) {
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
arguments.put("launchTarget", launchTarget);
@@ -5,31 +5,25 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.locating.IModFile;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
/**
* Master list of all mods <em>in the loading context. This class cannot refer outside the
* loading package</em>
*/
public class LoadingModList
{
public class LoadingModList {
private static LoadingModList INSTANCE;
private final List<ModFileInfo> modFiles;
private final List<ModInfo> sortedList;
@@ -37,15 +31,14 @@ public class LoadingModList
private final List<EarlyLoadingException> preLoadErrors;
private List<IModFile> brokenFiles;
private LoadingModList(final List<ModFile> modFiles, final List<ModInfo> sortedList)
{
private LoadingModList(final List<ModFile> modFiles, final List<ModInfo> sortedList) {
this.modFiles = modFiles.stream()
.map(ModFile::getModFileInfo)
.map(ModFileInfo.class::cast)
.collect(Collectors.toList());
.toList();
this.sortedList = sortedList.stream()
.map(ModInfo.class::cast)
.collect(Collectors.toList());
.toList();
this.fileById = this.modFiles.stream()
.map(ModFileInfo::getMods)
.flatMap(Collection::stream)
@@ -54,21 +47,18 @@ public class LoadingModList
this.preLoadErrors = new ArrayList<>();
}
public static LoadingModList of(List<ModFile> modFiles, List<ModInfo> sortedList, final EarlyLoadingException earlyLoadingException)
{
public static LoadingModList of(List<ModFile> modFiles, List<ModInfo> sortedList, final EarlyLoadingException earlyLoadingException) {
INSTANCE = new LoadingModList(modFiles, sortedList);
if (earlyLoadingException != null)
{
INSTANCE.preLoadErrors.add(earlyLoadingException);
}
return INSTANCE;
}
public static LoadingModList get() {
return INSTANCE;
}
public void addCoreMods()
{
public void addCoreMods() {
modFiles.stream()
.map(ModFileInfo::getFile)
.map(ModFile::getCoreMods)
@@ -76,8 +66,7 @@ public class LoadingModList
.forEach(FMLLoader.getCoreModProvider()::addCoreMod);
}
public void addAccessTransformers()
{
public void addAccessTransformers() {
for (ModFileInfo modFile : modFiles) {
ModFile mod = modFile.getFile();
var at = mod.getAccessTransformer().orElse(null);
@@ -87,21 +76,18 @@ public class LoadingModList
}
}
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
{
public void addForScanning(BackgroundScanHandler backgroundScanHandler) {
backgroundScanHandler.setLoadingModList(this);
modFiles.stream()
.map(ModFileInfo::getFile)
.forEach(backgroundScanHandler::submitForScanning);
}
public List<ModFileInfo> getModFiles()
{
public List<ModFileInfo> getModFiles() {
return modFiles;
}
public Path findResource(final String className)
{
public Path findResource(final String className) {
for (ModFileInfo mf : modFiles) {
final Path resource = mf.getFile().findResource(className);
if (Files.exists(resource)) return resource;
@@ -109,55 +95,11 @@ public class LoadingModList
return null;
}
public Enumeration<URL> findAllURLsForResource(final String resName) {
final String resourceName;
// strip a leading slash
if (resName.startsWith("/")) {
resourceName = resName.substring(1);
} else {
resourceName = resName;
}
return new Enumeration<URL>() {
private final Iterator<ModFileInfo> modFileIterator = modFiles.iterator();
private URL next;
@Override
public boolean hasMoreElements() {
if (next!=null) return true;
next = findNextURL();
return next != null;
}
@Override
public URL nextElement() {
if (next == null) {
next = findNextURL();
if (next == null) throw new NoSuchElementException();
}
URL result = next;
next = null;
return result;
}
private URL findNextURL() {
while (modFileIterator.hasNext()) {
final ModFileInfo next = modFileIterator.next();
final Path resource = next.getFile().findResource(resourceName);
if (Files.exists(resource)) {
return LamdbaExceptionUtils.uncheck(()->new URL("modjar://" + next.getMods().get(0).getModId() + "/" + resourceName));
}
}
return null;
}
};
}
public ModFileInfo getModFileById(String modid)
{
public ModFileInfo getModFileById(String modid) {
return this.fileById.get(modid);
}
public List<ModInfo> getMods()
{
public List<ModInfo> getMods() {
return this.sortedList;
}
@@ -8,7 +8,7 @@ package net.minecraftforge.fml.loading;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;
import com.mojang.logging.LogUtils;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.IModInfo.ModVersion;
import net.minecraftforge.fml.loading.EarlyLoadingException.ExceptionData;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
@@ -20,235 +20,250 @@ import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class ModSorter
{
public class ModSorter {
private static final Logger LOGGER = LogUtils.getLogger();
private final UniqueModListBuilder uniqueModListBuilder;
private List<ModFile> modFiles;
private List<ModInfo> sortedList;
private Map<String, IModInfo> modIdNameLookup;
private List<ModFile> systemMods;
private ModSorter(final List<ModFile> modFiles)
{
this.uniqueModListBuilder = new UniqueModListBuilder(modFiles);
}
private record State(List<ModFile> files, List<ModInfo> mods) {}
private ModSorter() {}
@SuppressWarnings("removal")
public static LoadingModList sort(List<ModFile> mods, final List<ExceptionData> errors) {
State systemMods = detectSystemMods(mods);
List<ModFile> modFiles;
public static LoadingModList sort(List<ModFile> mods, final List<ExceptionData> errors)
{
final ModSorter ms = new ModSorter(mods);
try {
ms.buildUniqueList();
modFiles = new UniqueModListBuilder(mods).buildUniqueList().modFiles();
} catch (EarlyLoadingException e) {
// We cannot build any list with duped mods. We have to abort immediately and report it
// Note this will never actually throw an error because the duplicate checks are done in ModDiscovererer before we get to this phase
// So all this is really doing is wasting time.
// But i'm leaving it here until I rewrite all of cpw's mod loading code because its such a clusterfuck.
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).toList(), e);
return LoadingModList.of(systemMods.files(), systemMods.mods(), e);
}
var named = new HashMap<String, ModInfo>();
for (var file : modFiles) {
for (var info : file.getModInfos())
named.put(info.getModId(), (ModInfo)info);
}
// try and validate dependencies
final List<ExceptionData> failedList = Stream.concat(ms.verifyDependencyVersions().stream(), errors.stream()).toList();
final List<ExceptionData> failedList = Stream.concat(verifyDependencyVersions(modFiles).stream(), errors.stream()).toList();
// if we miss one or the other, we abort now
if (!failedList.isEmpty()) {
return LoadingModList.of(ms.systemMods, ms.systemMods.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).toList(), new EarlyLoadingException("failure to validate mod list", null, failedList));
return LoadingModList.of(systemMods.files(), systemMods.mods(), new EarlyLoadingException("failure to validate mod list", null, failedList));
} else {
// Otherwise, lets try and sort the modlist and proceed
EarlyLoadingException earlyLoadingException = null;
try {
ms.sort();
var sorted = sort(modFiles, named);
return LoadingModList.of(sorted.files(), sorted.mods(), null);
} catch (EarlyLoadingException e) {
earlyLoadingException = e;
// The only exception that can happen here is a cyclic exception, but fall back to system mods so we can display the nice screen.
return LoadingModList.of(systemMods.files(), systemMods.mods(), e);
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
}
private void sort()
{
// lambdas are identity based, so sorting them is impossible unless you hold reference to them
final MutableGraph<ModFileInfo> graph = GraphBuilder.directed().build();
AtomicInteger counter = new AtomicInteger();
Map<ModFileInfo, Integer> infos = modFiles.stream()
.map(ModFile::getModFileInfo)
.filter(ModFileInfo.class::isInstance)
.map(ModFileInfo.class::cast)
.collect(toMap(Function.identity(), e -> counter.incrementAndGet()));
infos.keySet().forEach(graph::addNode);
modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(List::stream)
.map(IModInfo::getDependencies)
.<IModInfo.ModVersion>flatMap(List::stream)
.forEach(dep -> addDependency(graph, dep));
private static State sort(final List<ModFile> modFiles, final Map<String, ModInfo> named) {
final MutableGraph<ModInfo> graph = GraphBuilder.directed().build();
final List<ModFileInfo> sorted;
try
{
sorted = TopologicalSort.topologicalSort(graph, Comparator.comparing(infos::get));
}
catch (CyclePresentException e)
{
Set<Set<ModFileInfo>> cycles = e.getCycles();
if (LOGGER.isErrorEnabled(LOADING))
{
LOGGER.error(LOADING, "Mod Sorting failed.\nDetected Cycles: {}\n", cycles);
int counter = 0;
var infos = new HashMap<ModInfo, Integer>();
for (var file : modFiles) {
if (file.getModFileInfo() instanceof ModFileInfo info) {
for (var imod : info.getMods()) {
var mod = (ModInfo)imod;
infos.put(mod, counter++);
graph.addNode(mod);
}
}
var dataList = cycles.stream()
.flatMap(Set::stream)
.<IModInfo>mapMulti((mf,c)->mf.getMods().forEach(c))
.map(IModInfo::getModId)
.map(list -> new ExceptionData("fml.modloading.cycle", list))
.toList();
}
for (var file : modFiles) {
for (var info : file.getModInfos()) {
for (var dep : info.getDependencies()) {
// Ordering isn't effected by sides, should it be?
//if (!dep.getSide().isCorrectSide())
// continue;
var target = named.get(dep.getModId());
// soft dep that doesn't exist. No edge required.
if (target == null)
continue;
var self = (ModInfo)dep.getOwner();
switch (dep.getOrdering()) {
case BEFORE -> graph.putEdge(self, target);
case AFTER -> graph.putEdge(target, self);
default -> {}
}
}
}
}
final List<ModInfo> sorted;
try {
sorted = TopologicalSort.topologicalSort(graph, Comparator.comparing(infos::get));
} catch (CyclePresentException e) {
Set<Set<ModInfo>> cycles = e.getCycles();
var buf = new StringBuilder();
buf.append("Mod Sorting failed - Detected Cycles: \n");
var dataList = new ArrayList<ExceptionData>();
for (var cycle : cycles) {
buf.append("\tCycle:\n");
for (var mod : cycle) {
var modDeps = new StringBuilder()
.append(mod.getModId())
.append(' ')
.append(mod.getDependencies().stream()
.filter(v -> cycle.stream().anyMatch(m -> m.getModId().equals(v.getModId())))
.map(dep -> dep.getOrdering().name() + " " + dep.getModId())
.collect(Collectors.joining(", "))
);
dataList.add(new ExceptionData("fml.modloading.cycle", modDeps.toString()));
buf.append("\t\tMod: ").append(modDeps.toString()).append('\n');
}
}
LOGGER.error(LOADING, buf.toString());
throw new EarlyLoadingException("Sorting error", e, dataList);
}
this.sortedList = sorted.stream()
.map(ModFileInfo::getMods)
.flatMap(List::stream)
.map(ModInfo.class::cast)
.collect(toList());
this.modFiles = sorted.stream()
.map(ModFileInfo::getFile)
.collect(toList());
}
private void addDependency(MutableGraph<ModFileInfo> topoGraph, IModInfo.ModVersion dep)
{
final IModInfo targetModInfo = modIdNameLookup.get(dep.getModId());
// soft dep that doesn't exist. Just return. No edge required.
if (targetModInfo == null || !(targetModInfo.getOwningFile() instanceof final ModFileInfo target)) return;
var files = new LinkedHashSet<ModFile>();
var list = new ArrayList<ModInfo>();
final ModFileInfo self = (ModFileInfo)dep.getOwner().getOwningFile();
if (self == target)
return; // in case a jar has two mods that have dependencies between
switch (dep.getOrdering()) {
case BEFORE -> topoGraph.putEdge(self, target);
case AFTER -> topoGraph.putEdge(target, self);
default -> {}
for (var mod : sorted) {
files.add(mod.getOwningFile().getFile());
list.add(mod);
}
return new State(files.stream().toList(), list);
}
private void buildUniqueList()
{
final UniqueModListBuilder.UniqueModListData uniqueModListData = uniqueModListBuilder.buildUniqueList();
this.modFiles = uniqueModListData.modFiles();
detectSystemMods(uniqueModListData.modFilesByFirstId());
modIdNameLookup = uniqueModListData.modFilesByFirstId().entrySet().stream()
.filter(e -> !e.getValue().get(0).getModInfos().isEmpty())
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().get(0).getModInfos().get(0)
));
}
private void detectSystemMods(final Map<String, List<ModFile>> modFilesByFirstId) {
private static State detectSystemMods(final List<ModFile> modFiles) {
// Capture system mods (ex. MC, Forge) here, so we can keep them for later
var systemMods = List.of("minecraft", "forge");
LOGGER.debug("Configured system mods: {}", systemMods);
this.systemMods = new ArrayList<>();
var mods = new ArrayList<ModInfo>();
var files = new ArrayList<ModFile>();
for (var systemMod : systemMods) {
var container = modFilesByFirstId.get(systemMod);
if (container != null && !container.isEmpty()) {
LOGGER.debug("Found system mod: {}", systemMod);
this.systemMods.add(container.getFirst());
} else {
var mod = findMod(modFiles, systemMod);
if (mod == null)
throw new IllegalStateException("Failed to find system mod: " + systemMod);
}
LOGGER.debug("Found system mod: {}", systemMod);
mods.add(mod.info());
files.add(mod.file());
}
return new State(files, mods);
}
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
{
final var modVersions = modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(List::stream)
.collect(toMap(IModInfo::getModId, IModInfo::getVersion));
private record ModPair(ModFile file, ModInfo info) {}
private static ModPair findMod(final List<ModFile> modFiles, String name) {
for (var file : modFiles) {
for (var mod : file.getModFileInfo().getMods()) {
if (name.equals(mod.getModId()))
return new ModPair(file, (ModInfo)mod);
}
}
return null;
}
final var modVersionDependencies = modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(List::stream)
.collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList())));
private static List<ExceptionData> verifyDependencyVersions(final List<ModFile> files) {
final var modVersions = new HashMap<String, ArtifactVersion>();
final var modRequirements = new HashSet<ModVersion>();
int mandatoryRequired = 0;
final var modRequirements = modVersionDependencies.values().stream()
.<IModInfo.ModVersion>flatMap(List::stream)
.filter(mv -> mv.getSide().isCorrectSide())
.collect(toSet());
for (var file : files) {
for (var info : file.getModInfos()) {
modVersions.put(info.getModId(), info.getVersion());
for (var dep : info.getDependencies()) {
if (dep.getSide().isCorrectSide()) {
if (modRequirements.add(dep) && dep.isMandatory())
mandatoryRequired++;
}
}
}
}
final long mandatoryRequired = modRequirements.stream().filter(IModInfo.ModVersion::isMandatory).count();
LOGGER.debug(LOADING, "Found {} mod requirements ({} mandatory, {} optional)", modRequirements.size(), mandatoryRequired, modRequirements.size() - mandatoryRequired);
final var missingVersions = modRequirements.stream()
.filter(mv -> (mv.isMandatory() || modVersions.containsKey(mv.getModId())) && !modVersionContained(mv, modVersions))
.collect(toSet());
final long mandatoryMissing = missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).count();
LOGGER.debug(LOADING, "Found {} mod requirements missing ({} mandatory, {} optional)", missingVersions.size(), mandatoryMissing, missingVersions.size() - mandatoryMissing);
if (!missingVersions.isEmpty()) {
if (mandatoryMissing > 0) {
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:\n{}",
missingVersions.stream()
.filter(ver -> !ver.isMandatory())
.map(ver -> formatDependencyError(ver, modVersions))
.collect(Collectors.joining("\n"))
);
}
final var missingMandatory = new HashSet<ModVersion>();
final var missingOptional = new HashSet<ModVersion>();
return missingVersions.stream()
.map(mv -> new ExceptionData(mv.isMandatory() ? "fml.modloading.missingdependency" : "fml.modloading.missingdependency.optional",
mv.getOwner(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null"))))
.toList();
for (var dep : modRequirements) {
var modId = dep.getModId();
var existing = modVersions.get(modId);
if (!dep.isMandatory() && existing == null)
continue;
var range = dep.getVersionRange();
if (existing != null && (range.containsVersion(existing) || "0.0NONE".equals(existing.toString())))
continue;
if (!VersionSupportMatrix.testVersionSupportMatrix(range, modId, "mod"))
(dep.isMandatory() ? missingMandatory : missingOptional).add(dep);
}
return Collections.emptyList();
LOGGER.debug(LOADING, "Found {} mod requirements missing ({} mandatory, {} optional)", missingMandatory.size() + missingOptional.size(), missingMandatory.size(), missingOptional.size());
var ret = new ArrayList<ExceptionData>();
if (!missingMandatory.isEmpty()) {
LOGGER.error(LOADING, "Missing or unsupported mandatory dependencies:\n{}", formatDependencyError(missingMandatory, modVersions));
for (var mv : missingMandatory)
ret.add(data(mv, modVersions, "fml.modloading.missingdependency"));
}
if (!missingOptional.isEmpty()) {
LOGGER.error(LOADING, "Unsupported installed optional dependencies:\n{}", formatDependencyError(missingMandatory, modVersions));
for (var mv : missingMandatory)
ret.add(data(mv, modVersions, "fml.modloading.missingdependency.optional"));
}
return ret;
}
private static String formatDependencyError(IModInfo.ModVersion dependency, Map<String, ArtifactVersion> modVersions)
{
ArtifactVersion installed = modVersions.get(dependency.getModId());
return String.format(
private static String formatDependencyError(Collection<ModVersion> missing, Map<String, ArtifactVersion> modVersions) {
var ret = new ArrayList<String>();
for (var dep : missing) {
var installed = modVersions.get(dep.getModId());
ret.add(String.format(
"\tMod ID: '%s', Requested by: '%s', Expected range: '%s', Actual version: '%s'",
dependency.getModId(),
dependency.getOwner().getModId(),
dependency.getVersionRange(),
dep.getModId(),
dep.getOwner().getModId(),
dep.getVersionRange(),
installed != null ? installed.toString() : "[MISSING]"
);
));
}
return String.join("\n", ret);
}
private static boolean modVersionContained(IModInfo.ModVersion mv, Map<String, ArtifactVersion> modVersions) {
var modId = mv.getModId();
var range = mv.getVersionRange();
if (modVersions.containsKey(modId)
&& (range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("0.0NONE")))
return true;
return VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod");
private static final ArtifactVersion NULL_VERSION = new DefaultArtifactVersion("null");
private static ExceptionData data(ModVersion mv, Map<String, ArtifactVersion> modVersions, String key) {
return new ExceptionData(key, mv.getOwner(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(), modVersions.getOrDefault(mv.getModId(), NULL_VERSION));
}
}
@@ -203,14 +203,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService {
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
if (isEmpty)
return NAY;
String internalName = classType.getInternalName();
if (internalName.startsWith("net/minecraftforge/"))
return NAY;
return YAY;
return isEmpty ? NAY : YAY;
}
private static class LambdaGatherer extends MethodVisitor {
@@ -9,6 +9,7 @@ import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.forgespi.language.IModInfo;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import java.util.ArrayList;
@@ -23,16 +24,18 @@ 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
{
@ApiStatus.Internal
@Deprecated(since = "1.21.3", forRemoval = true) // TODO: [FML][Loading] Convert to package private in 1.22
public class UniqueModListBuilder {
private final static Logger LOGGER = LogUtils.getLogger();
private final List<ModFile> modFiles;
public UniqueModListBuilder(final List<ModFile> modFiles) {this.modFiles = modFiles;}
public UniqueModListBuilder(final List<ModFile> modFiles) {
this.modFiles = modFiles;
}
public UniqueModListData buildUniqueList()
{
public UniqueModListData buildUniqueList() {
List<ModFile> uniqueModList;
List<ModFile> uniqueLibListWithVersion;
@@ -139,5 +142,4 @@ public class UniqueModListBuilder
}
public record UniqueModListData(List<ModFile> modFiles, Map<String, List<ModFile>> modFilesByFirstId) {}
}
@@ -68,6 +68,7 @@ public class ModDiscoverer {
}
}
@SuppressWarnings("removal")
public ModValidator discoverMods() {
LOGGER.debug(LogMarkers.SCAN,"Scanning for mods and other resources to load. We know {} ways to find mods", modLocatorList.size());
List<ModFile> loadedFiles = new ArrayList<>();
@@ -46,7 +46,7 @@ record Scanner(ModFile fileToScan, ModFileScanData result) {
try (InputStream in = Files.newInputStream(path)) {
ModClassVisitor mcv = new ModClassVisitor();
ClassReader cr = new ClassReader(in);
cr.accept(mcv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
cr.accept(mcv, 0);
mcv.buildData(result.getClasses(), result.getAnnotations());
} catch (IOException | IllegalArgumentException e) {
// mark path bad
@@ -71,6 +71,7 @@ public abstract class CommonLaunchHandler implements ILaunchHandlerService {
protected record LaunchType(String name, String module, String main, Dist dist, boolean data) {};
protected static final LaunchType CLIENT = new LaunchType("client", "minecraft", "net.minecraft.client.main.Main", Dist.CLIENT, false);
protected static final LaunchType CLIENT_DATA = new LaunchType("client_data", "minecraft", "net.minecraft.client.data.Main", Dist.CLIENT, true);
protected static final LaunchType DATA = new LaunchType("data", "minecraft", "net.minecraft.data.Main", Dist.CLIENT, true);
protected static final LaunchType SERVER = new LaunchType("server", "minecraft", "net.minecraft.server.Main", Dist.DEDICATED_SERVER, false);
protected static final LaunchType SERVER_GAMETEST = new LaunchType("server_gametest", "net.minecraftforge.forge", "net.minecraftforge.gametest.GameTestMain", Dist.DEDICATED_SERVER, false);
@@ -39,6 +39,12 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
}
}
public static final class ClientData extends ForgeDevLaunchHandler {
public ClientData() {
super(CLIENT_DATA);
}
}
public static final class Data extends ForgeDevLaunchHandler {
public Data() {
super(DATA);
+3 -3
View File
@@ -5,11 +5,11 @@ org.gradle.daemon=false
org.gradle.parallel=true
JAVA_VERSION=21
MC_VERSION=1.21.1
MC_VERSION=1.21.4
MC_NEXT_VERSION=1.22
MCP_VERSION=20240808.132146
MCP_VERSION=20241203.143248
MAPPING_CHANNEL=official
MAPPING_VERSION=1.21.1
MAPPING_VERSION=1.21.4
// Set to true before the first build of a new MC version, so we don't do compatibility checks
CHECK_COMPATIBILITY=false
Binary file not shown.
+1 -2
View File
@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+9 -13
View File
@@ -83,8 +83,7 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -131,13 +130,10 @@ location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@@ -145,7 +141,7 @@ 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=SC2039,SC3045
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -153,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -202,11 +198,11 @@ 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, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
# 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
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
Vendored
+10 -10
View File
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
@@ -13,6 +13,7 @@ import net.minecraftforge.eventbus.api.IEventListener;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModLoadingException;
import net.minecraftforge.fml.ModLoadingStage;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.ModFileScanData;
@@ -29,7 +30,6 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Optional;
import java.util.jar.Attributes;
public class FMLModContainer extends ModContainer {
@@ -47,7 +47,6 @@ public class FMLModContainer extends ModContainer {
this.scanResults = modFileScanResults;
activityMap.put(ModLoadingStage.CONSTRUCT, this::constructMod);
this.eventBus = BusBuilder.builder().setExceptionHandler(FMLModContainer::onEventFailed).setTrackPhases(false).markerType(IModBusEvent.class).useModLauncher().build();
this.configHandler = Optional.of(ce->this.eventBus.post(ce.self()));
this.contextExtension = () -> context;
try {
var moduleName = info.getOwningFile().moduleName();
@@ -189,4 +188,14 @@ public class FMLModContainer extends ModContainer {
throw new ModLoadingException(modInfo, modLoadingStage, "fml.modloading.errorduringevent", t);
}
}
@Override
public void dispatchConfigEvent(IConfigEvent event) {
this.eventBus.post(event.self());
}
@Override
public String toString() {
return "FMLModContainer[" + this.getModInfo().getModId() + ", " + this.getClass().getName() + "]";
}
}
+3 -4
View File
@@ -141,6 +141,9 @@ dependencies {
// For more info:
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
// Hack fix for now, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+
implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } }
}
// This block of code expands all declared replace properties in the specified resource targets.
@@ -194,10 +197,6 @@ tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}
// IntelliJ no longer downloads javadocs and sources by default.
// This tells Gradle to force IDEA to do it.
idea.module { downloadJavadoc = downloadSources = true }
eclipse {
// Run everytime eclipse builds the code
//autoBuildTasks genEclipseRuns
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/pipeline/RenderTarget.java
+++ b/com/mojang/blaze3d/pipeline/RenderTarget.java
@@ -104,7 +_,10 @@
@@ -96,7 +_,10 @@
GlStateManager._texParameter(3553, 34892, 0);
GlStateManager._texParameter(3553, 10242, 33071);
GlStateManager._texParameter(3553, 10243, 33071);
@@ -11,22 +11,15 @@
}
this.setFilterMode(9728, true);
@@ -114,8 +_,13 @@
GlStateManager._texImage2D(3553, 0, 32856, this.width, this.height, 0, 6408, 5121, null);
GlStateManager._glBindFramebuffer(36160, this.frameBufferId);
@@ -108,6 +_,7 @@
GlStateManager._glFramebufferTexture2D(36160, 36064, 3553, this.colorTextureId, 0);
- if (this.useDepth) {
+ if (this.useDepth && !stencilEnabled) {
if (this.useDepth) {
GlStateManager._glFramebufferTexture2D(36160, 36096, 3553, this.depthBufferId, 0);
+ } else if(this.useDepth && net.minecraftforge.common.ForgeConfig.CLIENT.useCombinedDepthStencilAttachment.get()) {
+ GlStateManager._glFramebufferTexture2D(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_DEPTH_STENCIL_ATTACHMENT, 3553, this.depthBufferId, 0);
+ } else if (this.useDepth) {
+ GlStateManager._glFramebufferTexture2D(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_DEPTH_ATTACHMENT, 3553, this.depthBufferId, 0);
+ GlStateManager._glFramebufferTexture2D(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_STENCIL_ATTACHMENT, 3553, this.depthBufferId, 0);
+ if (stencilEnabled) GlStateManager._glFramebufferTexture2D(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER, org.lwjgl.opengl.GL30.GL_STENCIL_ATTACHMENT, 3553, this.depthBufferId, 0);
}
this.checkStatus();
@@ -257,5 +_,26 @@
@@ -229,5 +_,26 @@
public int getDepthTextureId() {
return this.depthBufferId;
@@ -42,7 +35,7 @@
+ public void enableStencil() {
+ if (stencilEnabled) return;
+ stencilEnabled = true;
+ this.resize(viewWidth, viewHeight, net.minecraft.client.Minecraft.ON_OSX);
+ this.resize(viewWidth, viewHeight);
+ }
+
+ /**
@@ -1,6 +1,18 @@
--- a/com/mojang/blaze3d/platform/GlStateManager.java
+++ b/com/mojang/blaze3d/platform/GlStateManager.java
@@ -493,9 +_,17 @@
@@ -94,6 +_,11 @@
}
}
+ public static boolean _isBlendEnabled() {
+ RenderSystem.assertOnRenderThread();
+ return BLEND.mode.enabled;
+ }
+
public static void _disableBlend() {
RenderSystem.assertOnRenderThread();
BLEND.mode.disable();
@@ -519,9 +_,17 @@
}
}
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/platform/Window.java
+++ b/com/mojang/blaze3d/platform/Window.java
@@ -84,7 +_,8 @@
@@ -89,7 +_,8 @@
GLFW.glfwWindowHint(139267, 2);
GLFW.glfwWindowHint(139272, 204801);
GLFW.glfwWindowHint(139270, 1);
@@ -10,7 +10,7 @@
if (monitor != null) {
VideoMode videomode = monitor.getPreferredVidMode(this.fullscreen ? this.preferredFullscreenVideoMode : Optional.empty());
this.windowedX = this.x = monitor.getX() + videomode.getWidth() / 2 - this.width / 2;
@@ -96,6 +_,7 @@
@@ -101,6 +_,7 @@
this.windowedX = this.x = aint1[0];
this.windowedY = this.y = aint[0];
}
@@ -18,7 +18,7 @@
GLFW.glfwMakeContextCurrent(this.window);
GL.createCapabilities();
@@ -254,6 +_,9 @@
@@ -271,6 +_,9 @@
GLFW.glfwGetFramebufferSize(this.window, aint, aint1);
this.framebufferWidth = aint[0] > 0 ? aint[0] : 1;
this.framebufferHeight = aint1[0] > 0 ? aint1[0] : 1;
@@ -0,0 +1,14 @@
--- a/com/mojang/blaze3d/systems/RenderSystem.java
+++ b/com/mojang/blaze3d/systems/RenderSystem.java
@@ -196,6 +_,11 @@
GlStateManager._depthMask(p_69459_);
}
+ public static boolean isBlendEnabled() {
+ assertOnRenderThread();
+ return GlStateManager._isBlendEnabled();
+ }
+
public static void enableBlend() {
assertOnRenderThread();
GlStateManager._enableBlend();
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/vertex/PoseStack.java
+++ b/com/mojang/blaze3d/vertex/PoseStack.java
@@ -13,7 +_,7 @@
@@ -14,7 +_,7 @@
import org.joml.Vector3f;
@OnlyIn(Dist.CLIENT)
@@ -1,11 +0,0 @@
--- a/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java
+++ b/com/mojang/blaze3d/vertex/SheetedDecalTextureGenerator.java
@@ -62,7 +_,7 @@
public VertexConsumer setNormal(float p_344306_, float p_342091_, float p_344579_) {
this.delegate.setNormal(p_344306_, p_342091_, p_344579_);
Vector3f vector3f = this.normalInversePose.transform(p_344306_, p_342091_, p_344579_, this.normal);
- Direction direction = Direction.getNearest(vector3f.x(), vector3f.y(), vector3f.z());
+ Direction direction = net.minecraftforge.client.ForgeHooksClient.getNearestStable(vector3f.x(), vector3f.y(), vector3f.z());
Vector3f vector3f1 = this.cameraInversePose.transformPosition(this.x, this.y, this.z, this.worldPos);
vector3f1.rotateY((float) Math.PI);
vector3f1.rotateX((float) (-Math.PI / 2));
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/vertex/VertexConsumer.java
+++ b/com/mojang/blaze3d/vertex/VertexConsumer.java
@@ -12,7 +_,7 @@
@@ -13,7 +_,7 @@
import org.lwjgl.system.MemoryStack;
@OnlyIn(Dist.CLIENT)
@@ -9,16 +9,15 @@
VertexConsumer addVertex(float p_344294_, float p_342213_, float p_344859_);
VertexConsumer setColor(int p_342749_, int p_344324_, int p_343336_, int p_342831_);
@@ -135,10 +_,11 @@
}
@@ -133,9 +_,11 @@
int i1 = FastColor.ARGB32.color(k, (int)f3, (int)f4, (int)f5);
- int j1 = p_331444_[l];
+ int j1 = applyBakedLighting(p_331444_[l], bytebuffer);
int j1 = ARGB.color(k, (int)f3, (int)f4, (int)f5);
int k1 = LightTexture.lightCoordsWithEmission(p_331444_[i1], l);
+ k1 = applyBakedLighting(k1, bytebuffer);
float f10 = bytebuffer.getFloat(16);
float f9 = bytebuffer.getFloat(20);
Vector3f vector3f1 = matrix4f.transformPosition(f, f1, f2, new Vector3f());
+ applyBakedNormals(vector3f, bytebuffer, p_85988_.normal());
this.addVertex(vector3f1.x(), vector3f1.y(), vector3f1.z(), i1, f10, f9, p_85993_, j1, vector3f.x(), vector3f.y(), vector3f.z());
this.addVertex(vector3f1.x(), vector3f1.y(), vector3f1.z(), j1, f10, f9, p_85993_, k1, vector3f.x(), vector3f.y(), vector3f.z());
}
}
@@ -1,6 +1,6 @@
--- a/com/mojang/blaze3d/vertex/VertexFormat.java
+++ b/com/mojang/blaze3d/vertex/VertexFormat.java
@@ -13,7 +_,7 @@
@@ -14,7 +_,7 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@@ -9,7 +9,7 @@
public static final int UNKNOWN_ELEMENT = -1;
private final List<VertexFormatElement> elements;
private final List<String> names;
@@ -22,6 +_,7 @@
@@ -23,6 +_,7 @@
private final int[] offsetsByElement = new int[32];
@Nullable
private VertexBuffer immediateDrawVertexBuffer;
@@ -17,7 +17,7 @@
VertexFormat(List<VertexFormatElement> p_343616_, List<String> p_345241_, IntList p_345522_, int p_344162_) {
this.elements = p_343616_;
@@ -34,6 +_,11 @@
@@ -35,6 +_,11 @@
int j = vertexformatelement != null ? p_343616_.indexOf(vertexformatelement) : -1;
this.offsetsByElement[i] = j != -1 ? p_345522_.getInt(j) : -1;
}
@@ -29,7 +29,7 @@
}
public static VertexFormat.Builder builder() {
@@ -158,6 +_,9 @@
@@ -141,6 +_,9 @@
return vertexbuffer;
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/SharedConstants.java
+++ b/net/minecraft/SharedConstants.java
@@ -171,6 +_,7 @@
@@ -170,6 +_,7 @@
}
static {
@@ -1,6 +1,6 @@
--- a/net/minecraft/Util.java
+++ b/net/minecraft/Util.java
@@ -267,7 +_,7 @@
@@ -268,7 +_,7 @@
.getSchema(DataFixUtils.makeKey(SharedConstants.getCurrentVersion().getDataVersion().getVersion()))
.getChoiceType(p_137552_, p_137553_);
} catch (IllegalArgumentException illegalargumentexception) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/advancements/AdvancementRewards.java
+++ b/net/minecraft/advancements/AdvancementRewards.java
@@ -40,6 +_,7 @@
@@ -41,6 +_,7 @@
LootParams lootparams = new LootParams.Builder(p_9990_.serverLevel())
.withParameter(LootContextParams.THIS_ENTITY, p_9990_)
.withParameter(LootContextParams.ORIGIN, p_9990_.position())
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/Camera.java
+++ b/net/minecraft/client/Camera.java
@@ -105,9 +_,13 @@
@@ -120,9 +_,13 @@
}
protected void setRotation(float p_90573_, float p_90574_) {
@@ -15,7 +15,7 @@
FORWARDS.rotate(this.rotation, this.forwards);
UP.rotate(this.rotation, this.up);
LEFT.rotate(this.rotation, this.left);
@@ -223,6 +_,13 @@
@@ -238,6 +_,13 @@
public float getPartialTickTime() {
return this.partialTickTime;
@@ -1,20 +0,0 @@
--- a/net/minecraft/client/ClientRecipeBook.java
+++ b/net/minecraft/client/ClientRecipeBook.java
@@ -65,7 +_,7 @@
Recipe<?> recipe = recipeholder.value();
if (!recipe.isSpecial() && !recipe.isIncomplete()) {
RecipeBookCategories recipebookcategories = getCategory(recipeholder);
- String s = recipe.getGroup();
+ String s = recipe.getGroup().isEmpty() ? recipeholder.id().toString() : recipe.getGroup(); // 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_ -> Lists.newArrayList()).add(ImmutableList.of(recipeholder));
} else {
@@ -125,6 +_,8 @@
} else if (recipetype == RecipeType.SMITHING) {
return RecipeBookCategories.SMITHING;
} else {
+ var categories = net.minecraftforge.client.RecipeBookManager.findCategories((RecipeType)recipetype, p_299041_);
+ if (categories != null) return categories;
LOGGER.warn(
"Unknown recipe category: {}/{}",
LogUtils.defer(() -> BuiltInRegistries.RECIPE_TYPE.getKey(recipe.getType())),
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/KeyMapping.java
+++ b/net/minecraft/client/KeyMapping.java
@@ -14,9 +_,9 @@
@@ -15,9 +_,9 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
@@ -12,7 +12,7 @@
private static final Set<String> CATEGORIES = Sets.newHashSet();
public static final String CATEGORY_MOVEMENT = "key.categories.movement";
public static final String CATEGORY_MISC = "key.categories.misc";
@@ -42,14 +_,14 @@
@@ -43,14 +_,14 @@
private int clickCount;
public static void click(InputConstants.Key p_90836_) {
@@ -29,7 +29,7 @@
if (keymapping != null) {
keymapping.setDown(p_90839_);
}
@@ -100,7 +_,7 @@
@@ -101,7 +_,7 @@
}
public boolean isDown() {
@@ -38,7 +38,7 @@
}
public String getCategory() {
@@ -136,7 +_,16 @@
@@ -137,7 +_,16 @@
public int compareTo(KeyMapping p_90841_) {
return this.category.equals(p_90841_.category)
? I18n.get(this.name).compareTo(I18n.get(p_90841_.name))
@@ -56,7 +56,7 @@
}
public static Supplier<Component> createNameSupplier(String p_90843_) {
@@ -145,6 +_,20 @@
@@ -146,6 +_,20 @@
}
public boolean same(KeyMapping p_90851_) {
@@ -77,7 +77,7 @@
return this.key.equals(p_90851_.key);
}
@@ -163,11 +_,13 @@
@@ -164,11 +_,13 @@
}
public Component getTranslatedKeyMessage() {
@@ -92,10 +92,10 @@
}
public String saveString() {
@@ -176,5 +_,88 @@
public void setDown(boolean p_90846_) {
this.isDown = p_90846_;
@@ -182,5 +_,88 @@
@Nullable
public static KeyMapping get(String p_378660_) {
return ALL.get(p_378660_);
+ }
+
+ private net.minecraftforge.client.settings.KeyModifier keyModifierDefault = net.minecraftforge.client.settings.KeyModifier.NONE;
@@ -1,18 +1,21 @@
--- a/net/minecraft/client/KeyboardHandler.java
+++ b/net/minecraft/client/KeyboardHandler.java
@@ -405,9 +_,9 @@
Screen.wrapScreenError(() -> {
if (p_90897_ == 1 || p_90897_ == 2) {
@@ -424,12 +_,12 @@
if (screen != null) {
try {
if (p_90897_ != 1 && p_90897_ != 2) {
- if (p_90897_ == 0 && screen.keyReleased(p_90895_, p_90896_, p_90898_)) {
+ if (p_90897_ == 0 && net.minecraftforge.client.ForgeHooksClient.onScreenKeyReleased(screen, p_90895_, p_90896_, p_90898_)) {
return;
}
} else {
screen.afterKeyboardAction();
- aboolean[0] = screen.keyPressed(p_90895_, p_90896_, p_90898_);
+ net.minecraftforge.client.ForgeHooksClient.onScreenKeyPressed(aboolean, screen, p_90895_, p_90896_, p_90898_);
} else if (p_90897_ == 0) {
- aboolean[0] = screen.keyReleased(p_90895_, p_90896_, p_90898_);
+ net.minecraftforge.client.ForgeHooksClient.onScreenKeyReleased(aboolean, screen, p_90895_, p_90896_, p_90898_);
- if (screen.keyPressed(p_90895_, p_90896_, p_90898_)) {
+ if (net.minecraftforge.client.ForgeHooksClient.onScreenKeyPressed(screen, p_90895_, p_90896_, p_90898_)) {
return;
}
}
}, "keyPressed event handler", screen.getClass().getCanonicalName());
if (aboolean[0]) {
@@ -476,20 +_,21 @@
@@ -505,6 +_,7 @@
}
}
}
@@ -20,20 +23,17 @@
}
}
private void charTyped(long p_90890_, int p_90891_, int p_90892_) {
if (p_90890_ == this.minecraft.getWindow().getWindow()) {
- GuiEventListener guieventlistener = this.minecraft.screen;
+ Screen guieventlistener = this.minecraft.screen;
if (guieventlistener != null && this.minecraft.getOverlay() == null) {
if (Character.charCount(p_90891_) == 1) {
Screen.wrapScreenError(
- () -> guieventlistener.charTyped((char)p_90891_, p_90892_), "charTyped event handler", guieventlistener.getClass().getCanonicalName()
+ () -> net.minecraftforge.client.ForgeHooksClient.onScreenCharTyped(guieventlistener, (char)p_90891_, p_90892_), "charTyped event handler", guieventlistener.getClass().getCanonicalName()
);
} else {
for (char c0 : Character.toChars(p_90891_)) {
- Screen.wrapScreenError(() -> guieventlistener.charTyped(c0, p_90892_), "charTyped event handler", guieventlistener.getClass().getCanonicalName());
+ Screen.wrapScreenError(() -> net.minecraftforge.client.ForgeHooksClient.onScreenCharTyped(guieventlistener, c0, p_90892_), "charTyped event handler", guieventlistener.getClass().getCanonicalName());
@@ -514,10 +_,10 @@
if (screen != null && this.minecraft.getOverlay() == null) {
try {
if (Character.isBmpCodePoint(p_90891_)) {
- screen.charTyped((char)p_90891_, p_90892_);
+ net.minecraftforge.client.ForgeHooksClient.onScreenCharTyped(screen, (char)p_90891_, p_90892_);
} else if (Character.isValidCodePoint(p_90891_)) {
- screen.charTyped(Character.highSurrogate(p_90891_), p_90892_);
- screen.charTyped(Character.lowSurrogate(p_90891_), p_90892_);
+ net.minecraftforge.client.ForgeHooksClient.onScreenCharTyped(screen, Character.highSurrogate(p_90891_), p_90892_);
+ net.minecraftforge.client.ForgeHooksClient.onScreenCharTyped(screen, Character.lowSurrogate(p_90891_), p_90892_);
}
}
}
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "charTyped event handler");
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/Minecraft.java
+++ b/net/minecraft/client/Minecraft.java
@@ -254,7 +_,7 @@
@@ -250,7 +_,7 @@
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
@@ -9,7 +9,7 @@
static Minecraft instance;
private static final Logger LOGGER = LogUtils.getLogger();
public static final boolean ON_OSX = Util.getPlatform() == Util.OS.OSX;
@@ -431,7 +_,6 @@
@@ -428,7 +_,6 @@
}
}, Util.nonCriticalIoPool());
LOGGER.info("Setting user: {}", this.user.getName());
@@ -17,10 +17,10 @@
this.demo = p_91084_.game.demo;
this.allowsMultiplayer = !p_91084_.game.disableMultiplayer;
this.allowsChat = !p_91084_.game.disableChat;
@@ -468,15 +_,15 @@
@@ -475,15 +_,15 @@
LOGGER.error("Couldn't set icon", (Throwable)ioexception);
}
this.window.setFramerateLimit(this.options.framerateLimit().get());
+ // FORGE: Move mouse and keyboard handler setup further below
this.mouseHandler = new MouseHandler(this);
- this.mouseHandler.setup(this.window.getWindow());
@@ -29,27 +29,21 @@
RenderSystem.initRenderer(this.options.glDebugVerbosity, false);
this.mainRenderTarget = new MainTarget(this.window.getWidth(), this.window.getHeight());
this.mainRenderTarget.setClearColor(0.0F, 0.0F, 0.0F, 0.0F);
this.mainRenderTarget.clear(ON_OSX);
this.mainRenderTarget.clear();
this.resourceManager = new ReloadableResourceManager(PackType.CLIENT_RESOURCES);
+ net.minecraftforge.client.loading.ClientModLoader.begin(this, this.resourcePackRepository, this.resourceManager);
this.resourcePackRepository.reload();
this.options.loadSelectedResourcePacks(this.resourcePackRepository);
this.languageManager = new LanguageManager(this.options.languageCode, p_340763_ -> {
@@ -540,6 +_,7 @@
this.entityRenderDispatcher = new EntityRenderDispatcher(this, this.textureManager, this.itemRenderer, this.blockRenderer, this.font, this.options, this.entityModels);
this.resourceManager.registerReloadListener(this.entityRenderDispatcher);
@@ -561,6 +_,7 @@
this.blockEntityRenderDispatcher = new BlockEntityRenderDispatcher(this.font, this.modelManager.entityModels(), this.blockRenderer, this.itemModelResolver, this.itemRenderer, this.entityRenderDispatcher);
this.resourceManager.registerReloadListener(this.blockEntityRenderDispatcher);
this.particleEngine = new ParticleEngine(this.level, this.textureManager);
+ net.minecraftforge.client.ForgeHooksClient.onRegisterParticleProviders(this.particleEngine);
this.resourceManager.registerReloadListener(this.particleEngine);
this.paintingTextures = new PaintingTextureManager(this.textureManager);
this.resourceManager.registerReloadListener(this.paintingTextures);
@@ -552,11 +_,15 @@
this.gameRenderer = new GameRenderer(this, this.entityRenderDispatcher.getItemInHandRenderer(), this.resourceManager, this.renderBuffers);
this.resourceManager.registerReloadListener(this.gameRenderer.createReloadListener());
this.levelRenderer = new LevelRenderer(this, this.entityRenderDispatcher, this.blockEntityRenderDispatcher, this.renderBuffers);
+ net.minecraftforge.fml.ModLoader.get().postEvent(new net.minecraftforge.client.event.RenderLevelStageEvent.RegisterStageEvent());
this.resourceManager.registerReloadListener(this.levelRenderer);
this.gpuWarnlistManager = new GpuWarnlistManager();
@@ -576,6 +_,9 @@
this.resourceManager.registerReloadListener(this.gpuWarnlistManager);
this.resourceManager.registerReloadListener(this.regionalCompliancies);
this.gui = new Gui(this);
@@ -59,7 +53,7 @@
this.debugRenderer = new DebugRenderer(this);
RealmsClient realmsclient = RealmsClient.create(this);
this.realmsDataFetcher = new RealmsDataFetcher(realmsclient);
@@ -580,6 +_,7 @@
@@ -599,6 +_,7 @@
this.options.fullscreen().set(this.window.isFullscreen());
}
@@ -67,7 +61,7 @@
this.window.updateVsync(this.options.enableVsync().get());
this.window.updateRawMouseInput(this.options.rawMouseInput().get());
this.window.setDefaultErrorCallback();
@@ -600,16 +_,17 @@
@@ -620,16 +_,17 @@
GameLoadTimesEvent.INSTANCE.beginStep(TelemetryProperty.LOAD_TIME_LOADING_OVERLAY_MS);
Minecraft.GameLoadCookie minecraft$gameloadcookie = new Minecraft.GameLoadCookie(realmsclient, p_91084_.quickPlay);
this.setOverlay(
@@ -87,8 +81,8 @@
+ ).get()
);
this.quickPlayLog = QuickPlayLog.of(p_91084_.quickPlay.path());
}
@@ -698,6 +_,7 @@
this.framerateLimitTracker = new FramerateLimitTracker(this.options, this);
@@ -724,6 +_,7 @@
StringBuilder stringbuilder = new StringBuilder("Minecraft");
if (checkModStatus().shouldReportAsModified()) {
stringbuilder.append("*");
@@ -96,7 +90,7 @@
}
stringbuilder.append(" ");
@@ -721,6 +_,8 @@
@@ -747,6 +_,8 @@
}
private UserApiService createUserApiService(YggdrasilAuthenticationService p_193586_, GameConfig p_193587_) {
@@ -105,7 +99,7 @@
return p_193587_.user.user.getType() != User.Type.MSA
? UserApiService.OFFLINE
: p_193586_.createUserApiService(p_193587_.user.user.getAccessToken());
@@ -731,7 +_,7 @@
@@ -757,7 +_,7 @@
}
private void rollbackResourcePacks(Throwable p_91240_, @Nullable Minecraft.GameLoadCookie p_299515_) {
@@ -114,7 +108,7 @@
this.clearResourcePacksOnError(p_91240_, null, p_299515_);
} else {
Util.throwAsRuntime(p_91240_);
@@ -991,12 +_,6 @@
@@ -1043,12 +_,6 @@
LOGGER.error("setScreen called from non-game thread");
}
@@ -127,7 +121,7 @@
if (p_91153_ == null && this.clientLevelTeardownInProgress) {
throw new IllegalStateException("Trying to return to in-game GUI during disconnection");
} else {
@@ -1010,6 +_,23 @@
@@ -1062,6 +_,23 @@
}
}
@@ -151,27 +145,19 @@
this.screen = p_91153_;
if (this.screen != null) {
this.screen.added();
@@ -1088,6 +_,7 @@
this.resourceManager.close();
FreeTypeUtil.destroy();
Util.shutdownExecutors();
+ net.minecraftforge.fml.config.ConfigTracker.INSTANCE.forceUnload();
} catch (Throwable throwable) {
LOGGER.error("Shutdown failure!", throwable);
throw throwable;
@@ -1155,9 +_,11 @@
@@ -1215,9 +_,11 @@
this.mouseHandler.handleAccumulatedMovement();
this.profiler.pop();
profilerfiller.pop();
if (!this.noRender) {
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTickStart(this.timer);
this.profiler.popPush("gameRenderer");
this.gameRenderer.render(this.timer, p_91384_);
this.profiler.pop();
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTickEnd(this.timer);
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTickStart(this.deltaTracker);
profilerfiller.popPush("gameRenderer");
this.gameRenderer.render(this.deltaTracker, p_91384_);
profilerfiller.pop();
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTickEnd(this.deltaTracker);
}
if (this.fpsPieResults != null) {
@@ -1283,10 +_,12 @@
profilerfiller.push("blit");
@@ -1342,10 +_,12 @@
this.window.setGuiScale((double)i);
if (this.screen != null) {
this.screen.resize(this, this.window.getGuiScaledWidth(), this.window.getGuiScaledHeight());
@@ -179,12 +165,12 @@
}
RenderTarget rendertarget = this.getMainRenderTarget();
rendertarget.resize(this.window.getWidth(), this.window.getHeight(), ON_OSX);
rendertarget.resize(this.window.getWidth(), this.window.getHeight());
+ if (this.gameRenderer != null)
this.gameRenderer.resize(this.window.getWidth(), this.window.getHeight());
this.mouseHandler.setIgnoreFirstMove();
}
@@ -1554,6 +_,7 @@
@@ -1486,6 +_,7 @@
}
public void stop() {
@@ -192,7 +178,7 @@
this.running = false;
}
@@ -1582,10 +_,18 @@
@@ -1514,10 +_,18 @@
if (p_91387_ && this.hitResult != null && this.hitResult.getType() == HitResult.Type.BLOCK) {
BlockHitResult blockhitresult = (BlockHitResult)this.hitResult;
BlockPos blockpos = blockhitresult.getBlockPos();
@@ -214,7 +200,7 @@
this.player.swing(InteractionHand.MAIN_HAND);
}
}
@@ -1613,6 +_,8 @@
@@ -1545,6 +_,8 @@
return false;
} else {
boolean flag = false;
@@ -223,7 +209,7 @@
switch (this.hitResult.getType()) {
case ENTITY:
this.gameMode.attack(this.player, ((EntityHitResult)this.hitResult).getEntity());
@@ -1620,7 +_,7 @@
@@ -1552,7 +_,7 @@
case BLOCK:
BlockHitResult blockhitresult = (BlockHitResult)this.hitResult;
BlockPos blockpos = blockhitresult.getBlockPos();
@@ -232,7 +218,7 @@
this.gameMode.startDestroyBlock(blockpos, blockhitresult.getDirection());
if (this.level.getBlockState(blockpos).isAir()) {
flag = true;
@@ -1633,8 +_,10 @@
@@ -1565,8 +_,10 @@
}
this.player.resetAttackStrengthTicker();
@@ -243,7 +229,7 @@
this.player.swing(InteractionHand.MAIN_HAND);
return flag;
}
@@ -1650,6 +_,12 @@
@@ -1582,6 +_,12 @@
}
for (InteractionHand interactionhand : InteractionHand.values()) {
@@ -256,68 +242,68 @@
ItemStack itemstack = this.player.getItemInHand(interactionhand);
if (!itemstack.isItemEnabled(this.level.enabledFeatures())) {
return;
@@ -1670,7 +_,7 @@
@@ -1602,7 +_,7 @@
}
if (interactionresult.consumesAction()) {
- if (interactionresult.shouldSwing()) {
+ if (interactionresult.shouldSwing() && inputEvent.shouldSwingHand()) {
if (interactionresult instanceof InteractionResult.Success interactionresult$success2) {
- if (interactionresult$success2.swingSource() == InteractionResult.SwingSource.CLIENT) {
+ if (interactionresult$success2.swingSource() == InteractionResult.SwingSource.CLIENT && inputEvent.shouldSwingHand()) {
this.player.swing(interactionhand);
}
@@ -1682,7 +_,7 @@
@@ -1614,7 +_,7 @@
int i = itemstack.getCount();
InteractionResult interactionresult1 = this.gameMode.useItemOn(this.player, interactionhand, blockhitresult);
if (interactionresult1.consumesAction()) {
- if (interactionresult1.shouldSwing()) {
+ if (interactionresult1.shouldSwing() && inputEvent.shouldSwingHand()) {
if (interactionresult1 instanceof InteractionResult.Success interactionresult$success) {
- if (interactionresult$success.swingSource() == InteractionResult.SwingSource.CLIENT) {
+ if (interactionresult$success.swingSource() == InteractionResult.SwingSource.CLIENT && inputEvent.shouldSwingHand()) {
this.player.swing(interactionhand);
if (!itemstack.isEmpty() && (itemstack.getCount() != i || this.gameMode.hasInfiniteItems())) {
this.gameRenderer.itemInHandRenderer.itemUsed(interactionhand);
@@ -1698,6 +_,9 @@
@@ -1630,6 +_,9 @@
}
}
+ if (itemstack.isEmpty() && (this.hitResult == null || this.hitResult.getType() == HitResult.Type.MISS))
+ net.minecraftforge.event.ForgeEventFactory.onRightClickEmpty(this.player, interactionhand);
+
if (!itemstack.isEmpty()) {
InteractionResult interactionresult2 = this.gameMode.useItem(this.player, interactionhand);
if (interactionresult2.consumesAction()) {
@@ -1728,6 +_,8 @@
this.rightClickDelay--;
if (!itemstack.isEmpty()
&& this.gameMode.useItem(this.player, interactionhand) instanceof InteractionResult.Success interactionresult$success1) {
if (interactionresult$success1.swingSource() == InteractionResult.SwingSource.CLIENT) {
@@ -1659,6 +_,8 @@
}
ProfilerFiller profilerfiller = Profiler.get();
+ net.minecraftforge.event.ForgeEventFactory.onPreClientTick();
+
this.profiler.push("gui");
profilerfiller.push("gui");
this.chatListener.tick();
this.gui.tick(this.pause);
@@ -1811,6 +_,7 @@
@@ -1748,6 +_,7 @@
this.tutorial.tick();
+ net.minecraftforge.event.ForgeEventFactory.onPreLevelTick(this.level, () -> true);
try {
this.level.tick(() -> true);
} catch (Throwable throwable) {
@@ -1824,6 +_,7 @@
} catch (Throwable throwable1) {
@@ -1761,6 +_,7 @@
throw new ReportedException(crashreport);
throw new ReportedException(crashreport1);
}
+ net.minecraftforge.event.ForgeEventFactory.onPostLevelTick(this.level, () -> true);
}
this.profiler.popPush("animateTick");
@@ -1843,6 +_,7 @@
this.profiler.popPush("keyboard");
profilerfiller.popPush("animateTick");
@@ -1785,6 +_,7 @@
profilerfiller.popPush("keyboard");
this.keyboardHandler.tick();
this.profiler.pop();
profilerfiller.pop();
+ net.minecraftforge.event.ForgeEventFactory.onPostClientTick();
}
private boolean isLevelRunningNormally() {
@@ -2043,6 +_,7 @@
@@ -1986,6 +_,7 @@
}
public void setLevel(ClientLevel p_91157_, ReceivingLevelScreen.Reason p_335893_) {
@@ -325,7 +311,7 @@
this.updateScreenAndTick(new ReceivingLevelScreen(() -> false, p_335893_));
this.level = p_91157_;
this.updateLevelInEngines(p_91157_);
@@ -2080,6 +_,7 @@
@@ -2023,6 +_,7 @@
IntegratedServer integratedserver = this.singleplayerServer;
this.singleplayerServer = null;
this.gameRenderer.resetData();
@@ -333,15 +319,15 @@
this.gameMode = null;
this.narrator.clear();
this.clientLevelTeardownInProgress = true;
@@ -2087,6 +_,7 @@
@@ -2030,6 +_,7 @@
try {
this.updateScreenAndTick(p_335030_);
if (this.level != null) {
+ net.minecraftforge.event.ForgeEventFactory.onLevelUnload(this.level);
if (integratedserver != null) {
this.profiler.push("waitForServer");
@@ -2099,6 +_,7 @@
ProfilerFiller profilerfiller = Profiler.get();
profilerfiller.push("waitForServer");
@@ -2043,6 +_,7 @@
this.gui.onDisconnected();
this.isLocalServer = false;
@@ -349,40 +335,11 @@
}
this.level = null;
@@ -2245,6 +_,7 @@
@@ -2190,6 +_,7 @@
private void pickBlock() {
if (this.hitResult != null && this.hitResult.getType() != HitResult.Type.MISS) {
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onClickInput(2, this.options.keyPickItem, InteractionHand.MAIN_HAND).isCanceled()) return;
boolean flag = this.player.getAbilities().instabuild;
BlockEntity blockentity = null;
HitResult.Type hitresult$type = this.hitResult.getType();
@@ -2257,7 +_,7 @@
}
Block block = blockstate.getBlock();
- itemstack = block.getCloneItemStack(this.level, blockpos, blockstate);
+ itemstack = blockstate.getCloneItemStack(this.hitResult, this.level, blockpos, this.player);
if (itemstack.isEmpty()) {
return;
}
@@ -2271,7 +_,7 @@
}
Entity entity = ((EntityHitResult)this.hitResult).getEntity();
- itemstack = entity.getPickResult();
+ itemstack = entity.getPickedResult(this.hitResult);
if (itemstack == null) {
return;
}
@@ -2855,6 +_,10 @@
@Nullable
public static String getLauncherBrand() {
return System.getProperty("minecraft.launcher.brand");
+ }
+
+ public ItemColors getItemColors() {
+ return this.itemColors;
}
@OnlyIn(Dist.CLIENT)
boolean flag = Screen.hasControlDown();
HitResult hitresult = this.hitResult;
Objects.requireNonNull(this.hitResult);
@@ -1,34 +1,40 @@
--- a/net/minecraft/client/MouseHandler.java
+++ b/net/minecraft/client/MouseHandler.java
@@ -79,6 +_,7 @@
@@ -85,6 +_,7 @@
this.activeButton = -1;
}
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onMouseButtonPre(p_91532_, p_91533_, p_91534_)) return;
boolean[] aboolean = new boolean[]{false};
if (this.minecraft.getOverlay() == null) {
if (this.minecraft.screen == null) {
@@ -91,9 +_,9 @@
Screen screen = this.minecraft.screen;
if (flag) {
if (!this.mouseGrabbed && flag) {
@@ -98,7 +_,7 @@
screen.afterMouseAction();
- Screen.wrapScreenError(() -> aboolean[0] = screen.mouseClicked(d0, d1, i), "mouseClicked event handler", screen.getClass().getCanonicalName());
+ Screen.wrapScreenError(() -> net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseClicked(aboolean, screen, d0, d1, i), "mouseClicked event handler", screen.getClass().getCanonicalName());
try {
- if (screen.mouseClicked(d0, d1, i)) {
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseClicked(screen, d0, d1, i)) {
return;
}
} catch (Throwable throwable1) {
@@ -112,7 +_,7 @@
}
} else {
- Screen.wrapScreenError(() -> aboolean[0] = screen.mouseReleased(d0, d1, i), "mouseReleased event handler", screen.getClass().getCanonicalName());
+ Screen.wrapScreenError(() -> net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseReleased(aboolean, screen, d0, d1, i), "mouseReleased event handler", screen.getClass().getCanonicalName());
}
try {
- if (screen.mouseReleased(d0, d1, i)) {
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseReleased(screen, d0, d1, i)) {
return;
}
} catch (Throwable throwable) {
@@ -147,6 +_,7 @@
}
}
@@ -116,6 +_,7 @@
}
}
}
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onMouseButtonPost(p_91532_, p_91533_, p_91534_);
}
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onMouseButtonPost(p_91532_, p_91533_, p_91534_);
}
@@ -129,7 +_,9 @@
private void onScroll(long p_91527_, double p_91528_, double p_91529_) {
@@ -160,7 +_,9 @@
if (this.minecraft.screen != null) {
double d3 = this.xpos * (double)this.minecraft.getWindow().getGuiScaledWidth() / (double)this.minecraft.getWindow().getScreenWidth();
double d4 = this.ypos * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
@@ -38,25 +44,25 @@
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenMouseScrollPost(this.minecraft.screen, d3, d4, d1, d2);
this.minecraft.screen.afterMouseAction();
} else if (this.minecraft.player != null) {
if (this.accumulatedScrollX != 0.0 && Math.signum(d1) != Math.signum(this.accumulatedScrollX)) {
@@ -151,6 +_,7 @@
this.accumulatedScrollX -= (double)j;
this.accumulatedScrollY -= (double)i;
int k = i == 0 ? -j : i;
Vector2i vector2i = this.scrollWheelHandler.onMouseScroll(d1, d2);
@@ -169,6 +_,7 @@
}
int i = vector2i.y == 0 ? -vector2i.x : vector2i.y;
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onMouseScroll(this, d1, d2)) return;
if (this.minecraft.player.isSpectator()) {
if (this.minecraft.gui.getSpectatorGui().isMenuActive()) {
this.minecraft.gui.getSpectatorGui().onMouseScrolled(-k);
@@ -236,7 +_,7 @@
if (this.activeButton != -1 && this.mousePressedTime > 0.0) {
double d4 = this.accumulatedDX * (double)this.minecraft.getWindow().getGuiScaledWidth() / (double)this.minecraft.getWindow().getScreenWidth();
this.minecraft.gui.getSpectatorGui().onMouseScrolled(-i);
@@ -274,7 +_,7 @@
double d5 = this.accumulatedDY * (double)this.minecraft.getWindow().getGuiScaledHeight() / (double)this.minecraft.getWindow().getScreenHeight();
- Screen.wrapScreenError(() -> screen.mouseDragged(d2, d3, this.activeButton, d4, d5), "mouseDragged event handler", screen.getClass().getCanonicalName());
+ Screen.wrapScreenError(() -> net.minecraftforge.client.ForgeHooksClient.onScreenMouseDrag(screen, d2, d3, this.activeButton, d4, d5), "mouseDragged event handler", screen.getClass().getCanonicalName());
}
screen.afterMouseMove();
@@ -303,6 +_,14 @@
try {
- screen.mouseDragged(d2, d3, this.activeButton, d4, d5);
+ net.minecraftforge.client.ForgeHooksClient.onScreenMouseDrag(screen, d2, d3, this.activeButton, d4, d5);
} catch (Throwable throwable) {
CrashReport crashreport1 = CrashReport.forThrowable(throwable, "mouseDragged event handler");
screen.fillCrashDetails(crashreport1);
@@ -349,6 +_,14 @@
public double ypos() {
return this.ypos;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/Options.java
+++ b/net/minecraft/client/Options.java
@@ -681,7 +_,8 @@
@@ -698,7 +_,8 @@
},
new OptionInstance.LazyEnum<>(
() -> Stream.concat(Stream.of(""), Minecraft.getInstance().getSoundManager().getAvailableSoundDevices().stream()).toList(),
@@ -10,7 +10,7 @@
? Optional.empty()
: Optional.of(p_232011_),
Codec.STRING
@@ -1050,6 +_,7 @@
@@ -1079,6 +_,7 @@
}
public Options(Minecraft p_92138_, File p_92139_) {
@@ -18,7 +18,7 @@
this.minecraft = p_92138_;
this.optionsFile = new File(p_92139_, "options.txt");
boolean flag = Runtime.getRuntime().maxMemory() >= 1000000000L;
@@ -1184,12 +_,22 @@
@@ -1210,12 +_,22 @@
p_168428_.process("telemetryOptInExtra", this.telemetryOptInExtra);
this.onboardAccessibility = p_168428_.process("onboardAccessibility", this.onboardAccessibility);
p_168428_.process("menuBackgroundBlurriness", this.menuBackgroundBlurriness);
@@ -42,7 +42,7 @@
}
}
@@ -1207,6 +_,10 @@
@@ -1233,6 +_,10 @@
}
public void load() {
@@ -53,7 +53,7 @@
try {
if (!this.optionsFile.exists()) {
return;
@@ -1234,7 +_,8 @@
@@ -1260,7 +_,8 @@
}
}
@@ -63,15 +63,15 @@
new Options.FieldAccess() {
@Nullable
private String getValueOrNull(String p_168459_) {
@@ -1428,6 +_,7 @@
@@ -1451,6 +_,7 @@
}
public void broadcastOptions() {
+ if (net.minecraftforge.client.loading.ClientModLoader.isLoading()) return; //Don't save settings before mods add keybindigns and the like to prevent them from being deleted.
if (this.minecraft.player != null) {
this.minecraft.player.connection.send(new ServerboundClientInformationPacket(this.buildPlayerInformation()));
this.minecraft.player.connection.broadcastClientInformation(this.buildPlayerInformation());
}
@@ -1546,6 +_,23 @@
@@ -1564,6 +_,23 @@
public static Component genericValueLabel(Component p_231901_, int p_231902_) {
return genericValueLabel(p_231901_, Component.literal(Integer.toString(p_231902_)));
@@ -1,45 +0,0 @@
--- a/net/minecraft/client/RecipeBookCategories.java
+++ b/net/minecraft/client/RecipeBookCategories.java
@@ -12,7 +_,7 @@
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
-public enum RecipeBookCategories {
+public enum RecipeBookCategories implements net.minecraftforge.common.IExtensibleEnum {
CRAFTING_SEARCH(new ItemStack(Items.COMPASS)),
CRAFTING_BUILDING_BLOCKS(new ItemStack(Blocks.BRICKS)),
CRAFTING_REDSTONE(new ItemStack(Items.REDSTONE)),
@@ -38,7 +_,7 @@
public static final List<RecipeBookCategories> CRAFTING_CATEGORIES = ImmutableList.of(
CRAFTING_SEARCH, CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE
);
- public static final Map<RecipeBookCategories, List<RecipeBookCategories>> AGGREGATE_CATEGORIES = ImmutableMap.of(
+ public static final Map<RecipeBookCategories, List<RecipeBookCategories>> AGGREGATE_CATEGORIES = net.minecraftforge.client.RecipeBookManager.getAggregateCategories(ImmutableMap.of(
CRAFTING_SEARCH,
ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE),
FURNACE_SEARCH,
@@ -47,7 +_,7 @@
ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC),
SMOKER_SEARCH,
ImmutableList.of(SMOKER_FOOD)
- );
+ ));
private final List<ItemStack> itemIcons;
private RecipeBookCategories(final ItemStack... p_92267_) {
@@ -60,10 +_,15 @@
case FURNACE -> FURNACE_CATEGORIES;
case BLAST_FURNACE -> BLAST_FURNACE_CATEGORIES;
case SMOKER -> SMOKER_CATEGORIES;
+ default -> net.minecraftforge.client.RecipeBookManager.getCustomCategoriesOrEmpty(p_92270_);
};
}
public List<ItemStack> getIconItems() {
return this.itemIcons;
+ }
+
+ public static RecipeBookCategories create(String name, ItemStack... icons) {
+ throw new IllegalStateException("Enum not extended");
}
}
@@ -1,16 +1,16 @@
--- a/net/minecraft/client/color/block/BlockColors.java
+++ b/net/minecraft/client/color/block/BlockColors.java
@@ -29,7 +_,8 @@
@OnlyIn(Dist.CLIENT)
public class BlockColors {
@@ -30,7 +_,8 @@
private static final int DEFAULT = -1;
public static final int LILY_PAD_IN_WORLD = -14647248;
public static final int LILY_PAD_DEFAULT = -9321636;
- private final IdMapper<BlockColor> blockColors = new IdMapper<>(32);
+ // Forge: Use registry delegate as non-Vanilla block ids are not constant
+ private final java.util.Map<net.minecraft.core.Holder.Reference<Block>, BlockColor> blockColors = new java.util.HashMap<>(32);
private final Map<Block, Set<Property<?>>> coloringStates = Maps.newHashMap();
public static BlockColors createDefault() {
@@ -91,11 +_,12 @@
@@ -90,11 +_,12 @@
}, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM);
blockcolors.addColoringState(StemBlock.AGE, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM);
blockcolors.register((p_92596_, p_92597_, p_92598_, p_92599_) -> p_92597_ != null && p_92598_ != null ? -14647248 : -9321636, Blocks.LILY_PAD);
@@ -24,7 +24,7 @@
if (blockcolor != null) {
return blockcolor.getColor(p_92583_, null, null, 0);
} else {
@@ -105,13 +_,15 @@
@@ -104,13 +_,15 @@
}
public int getColor(BlockState p_92578_, @Nullable BlockAndTintGetter p_92579_, @Nullable BlockPos p_92580_, int p_92581_) {
@@ -1,35 +0,0 @@
--- a/net/minecraft/client/color/item/ItemColors.java
+++ b/net/minecraft/client/color/item/ItemColors.java
@@ -26,7 +_,8 @@
@OnlyIn(Dist.CLIENT)
public class ItemColors {
private static final int DEFAULT = -1;
- private final IdMapper<ItemColor> itemColors = new IdMapper<>(32);
+ // Forge: Use registry delegate as non-Vanilla item ids are not constant
+ private final java.util.Map<net.minecraft.core.Holder.Reference<Item>, ItemColor> itemColors = new java.util.HashMap<>(32);
public static ItemColors createDefault(BlockColors p_92684_) {
ItemColors itemcolors = new ItemColors();
@@ -105,17 +_,20 @@
: FastColor.ARGB32.opaque(p_325310_.getOrDefault(DataComponents.MAP_COLOR, MapItemColor.DEFAULT).rgb()),
Items.FILLED_MAP
);
+ net.minecraftforge.client.ForgeHooksClient.onItemColorsInit(itemcolors, p_92684_);
return itemcolors;
}
public int getColor(ItemStack p_92677_, int p_92678_) {
- ItemColor itemcolor = this.itemColors.byId(BuiltInRegistries.ITEM.getId(p_92677_.getItem()));
+ ItemColor itemcolor = this.itemColors.get(net.minecraftforge.registries.ForgeRegistries.ITEMS.getDelegateOrThrow(p_92677_.getItem()));
return itemcolor == null ? -1 : itemcolor.getColor(p_92677_, p_92678_);
}
+ /** @deprecated Register via {@link net.minecraftforge.client.event.RegisterColorHandlersEvent.Item} */
+ @Deprecated
public void register(ItemColor p_92690_, ItemLike... p_92691_) {
for (ItemLike itemlike : p_92691_) {
- this.itemColors.addMapping(p_92690_, Item.getId(itemlike.asItem()));
+ this.itemColors.put(net.minecraftforge.registries.ForgeRegistries.ITEMS.getDelegateOrThrow(itemlike.asItem()), p_92690_);
}
}
}
@@ -0,0 +1,22 @@
--- a/net/minecraft/client/data/Main.java
+++ b/net/minecraft/client/data/Main.java
@@ -30,13 +_,18 @@
OptionSpec<Void> optionspec1 = optionparser.accepts("client", "Include client generators");
OptionSpec<Void> optionspec2 = optionparser.accepts("all", "Include all generators");
OptionSpec<String> optionspec3 = optionparser.accepts("output", "Output folder").withRequiredArg().defaultsTo("generated");
+ OptionSpec<String> inputSpec = optionparser.accepts("input", "Input folder").withRequiredArg();
+ var loader = net.minecraftforge.data.loading.DatagenModLoader.setup(optionparser, true);
OptionSet optionset = optionparser.parse(p_375526_);
- if (!optionset.has(optionspec) && optionset.hasOptions()) {
+ if (!optionset.has(optionspec) && optionset.hasOptions() && loader.hasArgs(optionset)) {
+ var input = optionset.valuesOf(inputSpec).stream().map(Paths::get).toList();
Path path = Paths.get(optionspec3.value(optionset));
boolean flag = optionset.has(optionspec2);
boolean flag1 = flag || optionset.has(optionspec1);
Bootstrap.bootStrap();
ClientBootstrap.bootstrap();
+ if (!loader.run(optionset, path, input, flag, flag1, flag, flag, false))
+ return;
DataGenerator datagenerator = new DataGenerator(path, SharedConstants.getCurrentVersion(), true);
addClientProviders(datagenerator, flag1);
datagenerator.run();
@@ -1,20 +1,11 @@
--- a/net/minecraft/client/gui/Font.java
+++ b/net/minecraft/client/gui/Font.java
@@ -31,7 +_,7 @@
import org.joml.Vector3f;
@@ -32,7 +_,7 @@
import org.joml.Matrix4f;
@OnlyIn(Dist.CLIENT)
-public class Font {
+public class Font implements net.minecraftforge.client.extensions.IForgeFont {
private static final float EFFECT_DEPTH = 0.01F;
private static final Vector3f SHADOW_OFFSET = new Vector3f(0.0F, 0.0F, 0.03F);
public static final int ALPHA_CUTOFF = 8;
@@ -322,6 +_,8 @@
public StringSplitter getSplitter() {
return this.splitter;
}
+
+ @Override public Font self() { return this; }
@OnlyIn(Dist.CLIENT)
public static enum DisplayMode {
public static final float SHADOW_DEPTH = 0.03F;
public static final int NO_SHADOW = 0;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/Gui.java
+++ b/net/minecraft/client/gui/Gui.java
@@ -131,7 +_,7 @@
@@ -147,7 +_,7 @@
public float vignetteBrightness = 1.0F;
private int toolHighlightTimer;
private ItemStack lastToolHighlight = ItemStack.EMPTY;
@@ -9,7 +9,7 @@
private final SubtitleOverlay subtitleOverlay;
private final SpectatorGui spectatorGui;
private final PlayerTabOverlay tabList;
@@ -318,7 +_,7 @@
@@ -345,7 +_,7 @@
Window window = this.minecraft.getWindow();
int i = Mth.floor(this.minecraft.mouseHandler.xpos() * (double)window.getGuiScaledWidth() / (double)window.getScreenWidth());
int j = Mth.floor(this.minecraft.mouseHandler.ypos() * (double)window.getGuiScaledHeight() / (double)window.getScreenHeight());
@@ -18,24 +18,24 @@
}
}
@@ -434,6 +_,8 @@
@@ -443,6 +_,8 @@
for (MobEffectInstance mobeffectinstance : Ordering.natural().reverse().sortedCopy(collection)) {
Holder<MobEffect> holder = mobeffectinstance.getEffect();
+ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance);
+ if (!renderer.isVisibleInGui(mobeffectinstance)) continue;
if (mobeffectinstance.showIcon()) {
int i = p_282812_.guiWidth();
int j = 1;
@@ -463,6 +_,7 @@
int k = p_282812_.guiWidth();
int l = 1;
@@ -473,6 +_,7 @@
}
}
+ if (renderer.renderGuiIcon(mobeffectinstance, this, p_282812_, i, j, 0, f)) continue;
+ if (renderer.renderGuiIcon(mobeffectinstance, this, p_282812_, k, l, 0, f)) continue;
TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.get(holder);
int l1 = i;
int i1 = j;
@@ -625,6 +_,10 @@
int l1 = k;
int k1 = l;
@@ -623,6 +_,10 @@
}
private void renderSelectedItemName(GuiGraphics p_283501_) {
@@ -43,10 +43,10 @@
+ }
+
+ public void renderSelectedItemName(GuiGraphics p_283501_, int yShift) {
this.minecraft.getProfiler().push("selectedItemName");
Profiler.get().push("selectedItemName");
if (this.toolHighlightTimer > 0 && !this.lastToolHighlight.isEmpty()) {
MutableComponent mutablecomponent = Component.empty().append(this.lastToolHighlight.getHoverName()).withStyle(this.lastToolHighlight.getRarity().color());
@@ -632,9 +_,13 @@
@@ -630,9 +_,13 @@
mutablecomponent.withStyle(ChatFormatting.ITALIC);
}
@@ -62,16 +62,16 @@
if (!this.minecraft.gameMode.canHurtPlayer()) {
k += 14;
}
@@ -645,7 +_,7 @@
@@ -643,7 +_,7 @@
}
if (l > 0) {
- p_283501_.drawStringWithBackdrop(this.getFont(), mutablecomponent, j, k, i, FastColor.ARGB32.color(l, -1));
+ p_283501_.drawStringWithBackdrop(font, highlightTip, j, k, i, FastColor.ARGB32.color(l, -1));
- p_283501_.drawStringWithBackdrop(this.getFont(), mutablecomponent, j, k, i, ARGB.color(l, -1));
+ p_283501_.drawStringWithBackdrop(font, highlightTip, j, k, i, ARGB.color(l, -1));
}
}
@@ -1146,7 +_,7 @@
@@ -1152,7 +_,7 @@
ItemStack itemstack = this.minecraft.player.getInventory().getSelected();
if (itemstack.isEmpty()) {
this.toolHighlightTimer = 0;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/GuiGraphics.java
+++ b/net/minecraft/client/gui/GuiGraphics.java
@@ -56,7 +_,7 @@
@@ -52,7 +_,7 @@
import org.joml.Vector2ic;
@OnlyIn(Dist.CLIENT)
@@ -9,7 +9,7 @@
public static final float MAX_GUI_Z = 10000.0F;
public static final float MIN_GUI_Z = -10000.0F;
private static final int EXTRA_SPACE_AFTER_FIRST_TOOLTIP_LINE = 2;
@@ -268,6 +_,11 @@
@@ -229,6 +_,11 @@
}
public int drawString(Font p_283343_, @Nullable String p_281896_, int p_283569_, int p_283418_, int p_281560_, boolean p_282130_) {
@@ -18,10 +18,10 @@
+
+ // Forge: Add float variant for x,y coordinates
+ public int drawString(Font p_283343_, @Nullable String p_281896_, float p_283569_, float p_283418_, int p_281560_, boolean p_282130_) {
if (p_281896_ == null) {
return 0;
} else {
@@ -294,6 +_,11 @@
return p_281896_ == null
? 0
: p_283343_.drawInBatch(
@@ -250,6 +_,11 @@
}
public int drawString(Font p_282636_, FormattedCharSequence p_281596_, int p_281586_, int p_282816_, int p_281743_, boolean p_282394_) {
@@ -30,10 +30,10 @@
+
+ // Forge: Add float variant for x,y coordinates
+ public int drawString(Font p_282636_, FormattedCharSequence p_281596_, float p_281586_, float p_282816_, int p_281743_, boolean p_282394_) {
int i = p_282636_.drawInBatch(
return p_282636_.drawInBatch(
p_281596_,
(float)p_281586_,
@@ -864,6 +_,7 @@
@@ -859,6 +_,7 @@
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering item");
CrashReportCategory crashreportcategory = crashreport.addCategory("Item being rendered");
crashreportcategory.setDetail("Item Type", () -> String.valueOf(p_281675_.getItem()));
@@ -41,9 +41,9 @@
crashreportcategory.setDetail("Item Components", () -> String.valueOf(p_281675_.getComponents()));
crashreportcategory.setDetail("Item Foil", () -> String.valueOf(p_281675_.hasFoil()));
throw new ReportedException(crashreport);
@@ -904,16 +_,26 @@
}
@@ -879,13 +_,24 @@
this.renderItemCount(p_282005_, p_283349_, p_282641_, p_282146_, p_282803_);
this.renderItemCooldown(p_283349_, p_282641_, p_282146_);
this.pose.popPose();
+ net.minecraftforge.client.ItemDecoratorHandler.of(p_283349_).render(this, p_282005_, p_283349_, p_282641_, p_282146_);
}
@@ -53,50 +53,56 @@
public void renderTooltip(Font p_282308_, ItemStack p_282781_, int p_282687_, int p_282292_) {
+ this.tooltipStack = p_282781_;
this.renderTooltip(p_282308_, Screen.getTooltipFromItem(this.minecraft, p_282781_), p_282781_.getTooltipImage(), p_282687_, p_282292_);
this.renderTooltip(
p_282308_, Screen.getTooltipFromItem(this.minecraft, p_282781_), p_282781_.getTooltipImage(), p_282687_, p_282292_, p_282781_.get(DataComponents.TOOLTIP_STYLE)
);
+ this.tooltipStack = ItemStack.EMPTY;
+ }
+
+ public void renderTooltip(Font font, List<Component> textComponents, Optional<TooltipComponent> tooltipComponent, ItemStack stack, int mouseX, int mouseY) {
+ this.tooltipStack = stack;
+ this.renderTooltip(font, textComponents, tooltipComponent, mouseX, mouseY);
+ this.renderTooltip(font, textComponents, tooltipComponent, mouseX, mouseY, stack.get(DataComponents.TOOLTIP_STYLE));
+ this.tooltipStack = ItemStack.EMPTY;
}
public void renderTooltip(Font p_283128_, List<Component> p_282716_, Optional<TooltipComponent> p_281682_, int p_283678_, int p_281696_) {
- List<ClientTooltipComponent> list = p_282716_.stream().map(Component::getVisualOrderText).map(ClientTooltipComponent::create).collect(Util.toMutableList());
- p_281682_.ifPresent(p_325321_ -> list.add(list.isEmpty() ? 0 : 1, ClientTooltipComponent.create(p_325321_)));
+ List<ClientTooltipComponent> list = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_282716_, p_281682_, p_283678_, guiWidth(), guiHeight(), p_283128_);
this.renderTooltipInternal(p_283128_, list, p_283678_, p_281696_, DefaultTooltipPositioner.INSTANCE);
@@ -895,8 +_,7 @@
public void renderTooltip(
Font p_362491_, List<Component> p_368544_, Optional<TooltipComponent> p_362815_, int p_366300_, int p_368952_, @Nullable ResourceLocation p_368469_
) {
- List<ClientTooltipComponent> list = p_368544_.stream().map(Component::getVisualOrderText).map(ClientTooltipComponent::create).collect(Util.toMutableList());
- p_362815_.ifPresent(p_325321_ -> list.add(list.isEmpty() ? 0 : 1, ClientTooltipComponent.create(p_325321_)));
+ List<ClientTooltipComponent> list = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_368544_, p_362815_, p_366300_, guiWidth(), guiHeight(), p_362491_);
this.renderTooltipInternal(p_362491_, list, p_366300_, p_368952_, DefaultTooltipPositioner.INSTANCE, p_368469_);
}
@@ -922,7 +_,22 @@
@@ -909,7 +_,22 @@
}
public void renderComponentTooltip(Font p_282739_, List<Component> p_281832_, int p_282191_, int p_282446_) {
- this.renderTooltip(p_282739_, Lists.transform(p_281832_, Component::getVisualOrderText), p_282191_, p_282446_);
- this.renderComponentTooltip(p_282739_, p_281832_, p_282191_, p_282446_, null);
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(this.tooltipStack, p_281832_, p_282191_, guiWidth(), guiHeight(), p_282739_);
+ this.renderTooltipInternal(p_282739_, components, p_282191_, p_282446_, DefaultTooltipPositioner.INSTANCE);
+ this.renderTooltipInternal(p_282739_, components, p_282191_, p_282446_, DefaultTooltipPositioner.INSTANCE, null);
+ }
+
+ public void renderComponentTooltip(Font font, List<? extends net.minecraft.network.chat.FormattedText> tooltips, int mouseX, int mouseY, ItemStack stack) {
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponents(stack, tooltips, mouseX, guiWidth(), guiHeight(), font);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null);
+ this.tooltipStack = ItemStack.EMPTY;
+ }
+
+ public void renderComponentTooltipFromElements(Font font, List<com.mojang.datafixers.util.Either<FormattedText, TooltipComponent>> elements, int mouseX, int mouseY, ItemStack stack) {
+ this.tooltipStack = stack;
+ List<ClientTooltipComponent> components = net.minecraftforge.client.ForgeHooksClient.gatherTooltipComponentsFromElements(stack, elements, mouseX, guiWidth(), guiHeight(), font);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE);
+ this.renderTooltipInternal(font, components, mouseX, mouseY, DefaultTooltipPositioner.INSTANCE, null);
+ this.tooltipStack = ItemStack.EMPTY;
}
public void renderTooltip(Font p_282192_, List<? extends FormattedCharSequence> p_282297_, int p_281680_, int p_283325_) {
@@ -941,11 +_,13 @@
private void renderTooltipInternal(Font p_282675_, List<ClientTooltipComponent> p_282615_, int p_283230_, int p_283417_, ClientTooltipPositioner p_282442_) {
public void renderComponentTooltip(Font p_369090_, List<Component> p_365405_, int p_368143_, int p_366244_, @Nullable ResourceLocation p_364763_) {
@@ -951,11 +_,13 @@
@Nullable ResourceLocation p_368234_
) {
if (!p_282615_.isEmpty()) {
+ var preEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipPre(this.tooltipStack, this, p_283230_, p_283417_, guiWidth(), guiHeight(), p_282615_, p_282675_, p_282442_);
+ if (preEvent.isCanceled()) return;
@@ -109,21 +115,19 @@
if (k > i) {
i = k;
}
@@ -955,18 +_,21 @@
@@ -965,18 +_,19 @@
int i2 = i;
int j2 = j;
- Vector2ic vector2ic = p_282442_.positionTooltip(this.guiWidth(), this.guiHeight(), p_283230_, p_283417_, i2, j2);
- Vector2ic vector2ic = p_282442_.positionTooltip(this.guiWidth(), this.guiHeight(), p_283230_, p_283417_, i, j);
+ Vector2ic vector2ic = p_282442_.positionTooltip(this.guiWidth(), this.guiHeight(), preEvent.getX(), preEvent.getY(), i2, j2);
int l = vector2ic.x();
int i1 = vector2ic.y();
this.pose.pushPose();
int j1 = 400;
- this.drawManaged(() -> TooltipRenderUtil.renderTooltipBackground(this, l, i1, i2, j2, 400));
+ this.drawManaged(() -> {
+ var colorEvent = net.minecraftforge.client.ForgeHooksClient.onRenderTooltipColor(this.tooltipStack, this, l, i1, preEvent.getFont(), p_282615_);
+ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i2, j2, 400, colorEvent.getBackgroundStart(), colorEvent.getBackgroundEnd(), colorEvent.getBorderStart(), colorEvent.getBorderEnd());
+ });
- TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, 400, p_368234_);
+ var background_event = net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderTooltipBackground(this.tooltipStack, this, l, i1, preEvent.getFont(), p_282615_, p_368234_);
+ TooltipRenderUtil.renderTooltipBackground(this, l, i1, i, j, 400, background_event.getBackground());
this.pose.translate(0.0F, 0.0F, 400.0F);
int k1 = i1;
@@ -131,15 +135,26 @@
ClientTooltipComponent clienttooltipcomponent1 = p_282615_.get(l1);
- clienttooltipcomponent1.renderText(p_282675_, l, k1, this.pose.last().pose(), this.bufferSource);
+ clienttooltipcomponent1.renderText(preEvent.getFont(), l, k1, this.pose.last().pose(), this.bufferSource);
k1 += clienttooltipcomponent1.getHeight() + (l1 == 0 ? 2 : 0);
k1 += clienttooltipcomponent1.getHeight(p_282675_) + (l1 == 0 ? 2 : 0);
}
@@ -974,7 +_,7 @@
@@ -984,7 +_,7 @@
for (int k2 = 0; k2 < p_282615_.size(); k2++) {
ClientTooltipComponent clienttooltipcomponent2 = p_282615_.get(k2);
- clienttooltipcomponent2.renderImage(p_282675_, l, k1, this);
+ clienttooltipcomponent2.renderImage(preEvent.getFont(), l, k1, this);
k1 += clienttooltipcomponent2.getHeight() + (k2 == 0 ? 2 : 0);
- clienttooltipcomponent2.renderImage(p_282675_, l, k1, i2, j2, this);
+ clienttooltipcomponent2.renderImage(preEvent.getFont(), l, k1, i2, j2, this);
k1 += clienttooltipcomponent2.getHeight(p_282675_) + (k2 == 0 ? 2 : 0);
}
@@ -1041,6 +_,10 @@
}
}
}
+ }
+
+ public MultiBufferSource.BufferSource getBufferSource() {
+ return this.bufferSource;
}
public void drawSpecial(Consumer<MultiBufferSource> p_367429_) {
@@ -1,9 +1,9 @@
--- a/net/minecraft/client/gui/components/AbstractButton.java
+++ b/net/minecraft/client/gui/components/AbstractButton.java
@@ -34,7 +_,7 @@
RenderSystem.enableDepthTest();
p_281670_.blitSprite(SPRITES.get(this.active, this.isHoveredOrFocused()), this.getX(), this.getY(), this.getWidth(), this.getHeight());
p_281670_.setColor(1.0F, 1.0F, 1.0F, 1.0F);
@@ -39,7 +_,7 @@
this.getHeight(),
ARGB.white(this.alpha)
);
- int i = this.active ? 16777215 : 10526880;
+ int i = getFGColor();
this.renderString(p_281670_, minecraft.font, i | Mth.ceil(this.alpha * 255.0F) << 24);
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/components/AbstractWidget.java
+++ b/net/minecraft/client/gui/components/AbstractWidget.java
@@ -255,6 +_,25 @@
@@ -250,6 +_,25 @@
this.focused = p_93693_;
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/components/BossHealthOverlay.java
+++ b/net/minecraft/client/gui/components/BossHealthOverlay.java
@@ -63,13 +_,16 @@
@@ -66,13 +_,16 @@
for (LerpingBossEvent lerpingbossevent : this.events.values()) {
int k = i / 2 - 91;
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/components/DebugScreenOverlay.java
+++ b/net/minecraft/client/gui/components/DebugScreenOverlay.java
@@ -101,9 +_,9 @@
@@ -105,9 +_,9 @@
@Nullable
private CompletableFuture<LevelChunk> serverChunk;
private boolean renderDebug;
@@ -13,53 +13,54 @@
private final LocalSampleLogger frameTimeLogger = new LocalSampleLogger(1);
private final LocalSampleLogger tickTimeLogger = new LocalSampleLogger(TpsDebugDimensions.values().length);
private final LocalSampleLogger pingLogger = new LocalSampleLogger(1);
@@ -129,14 +_,18 @@
@@ -135,14 +_,18 @@
this.clientChunk = null;
}
- public void render(GuiGraphics p_281427_) {
- this.minecraft.getProfiler().push("debug");
- ProfilerFiller profilerfiller = Profiler.get();
- profilerfiller.push("debug");
+ protected void update() {
Entity entity = this.minecraft.getCameraEntity();
this.block = entity.pick(20.0, 0.0F, false);
this.liquid = entity.pick(20.0, 0.0F, true);
- p_281427_.drawManaged(() -> {
+ }
+
+ protected void drawText(GuiGraphics p_281427_) {
this.drawGameInformation(p_281427_);
this.drawSystemInformation(p_281427_);
+ protected void drawText(ProfilerFiller profilerfiller, GuiGraphics p_281427_) {
this.drawGameInformation(p_281427_);
this.drawSystemInformation(p_281427_);
+ }
+
+ protected void drawFPSCharts(GuiGraphics p_281427_) {
if (this.renderFpsCharts) {
int i = p_281427_.guiWidth();
int j = i / 2;
@@ -146,7 +_,9 @@
this.tpsChart.drawChart(p_281427_, i - k, k);
}
}
+ protected void drawFPSCharts(ProfilerFiller profilerfiller, GuiGraphics p_281427_) {
this.profilerPieChart.setBottomOffset(10);
if (this.renderFpsCharts) {
int i = p_281427_.guiWidth();
@@ -155,7 +_,9 @@
this.profilerPieChart.setBottomOffset(this.tpsChart.getFullHeight());
}
+ }
+ protected void drawNetworkCharts(GuiGraphics p_281427_) {
if (this.renderNetworkCharts) {
int l = p_281427_.guiWidth();
int i1 = l / 2;
@@ -157,12 +_,21 @@
int j1 = this.pingChart.getWidth(i1);
this.pingChart.drawChart(p_281427_, l - j1, j1);
}
+ protected void drawNetworkCharts(ProfilerFiller profilerfiller, GuiGraphics p_281427_) {
if (this.renderNetworkCharts) {
int l = p_281427_.guiWidth();
int i1 = l / 2;
@@ -171,12 +_,22 @@
try (Zone zone = profilerfiller.zone("profilerPie")) {
this.profilerPieChart.render(p_281427_);
}
+ }
+
+ public void render(GuiGraphics p_281427_) {
+ this.minecraft.getProfiler().push("debug");
+ ProfilerFiller profilerfiller = Profiler.get();
+ profilerfiller.push("debug");
+ this.update();
+ p_281427_.drawManaged(() -> {
+ this.drawText(p_281427_);
+ this.drawFPSCharts(p_281427_);
+ this.drawNetworkCharts(p_281427_);
});
this.minecraft.getProfiler().pop();
+
+ this.drawText(profilerfiller, p_281427_);
+ this.drawFPSCharts(profilerfiller, p_281427_);
+ this.drawNetworkCharts(profilerfiller, p_281427_);
profilerfiller.pop();
}
- protected void drawGameInformation(GuiGraphics p_281525_) {
@@ -69,7 +70,7 @@
list.add("");
boolean flag = this.minecraft.getSingleplayerServer() != null;
list.add(
@@ -176,11 +_,18 @@
@@ -190,11 +_,18 @@
+ (this.renderNetworkCharts ? " visible" : " hidden")
);
list.add("For help: press F3 + Q");
@@ -79,17 +80,17 @@
+ protected void drawGameInformation(GuiGraphics p_281525_) {
+ List<String> list = this.getGameInformation();
+ list.addAll(this.getOverlayHelp());
+ net.minecraftforge.client.ForgeHooksClient.onCustomizeDebugEvent(p_281525_, minecraft.getWindow(), minecraft.getTimer().getRealtimeDeltaTicks(), list, true);
+ net.minecraftforge.client.ForgeHooksClient.onCustomizeDebugEvent(p_281525_, minecraft.getWindow(), minecraft.getDeltaTracker().getRealtimeDeltaTicks(), list, true);
+ this.renderLines(p_281525_, list, true);
}
protected void drawSystemInformation(GuiGraphics p_281261_) {
List<String> list = this.getSystemInformation();
+ net.minecraftforge.client.ForgeHooksClient.onCustomizeDebugEvent(p_281261_, minecraft.getWindow(), minecraft.getTimer().getRealtimeDeltaTicks(), list, false);
+ net.minecraftforge.client.ForgeHooksClient.onCustomizeDebugEvent(p_281261_, minecraft.getWindow(), minecraft.getDeltaTracker().getRealtimeDeltaTicks(), list, false);
this.renderLines(p_281261_, list, false);
}
@@ -529,6 +_,7 @@
@@ -543,6 +_,7 @@
list.add("");
list.add(ChatFormatting.UNDERLINE + "Targeted Entity");
list.add(String.valueOf(BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType())));
@@ -1,10 +0,0 @@
--- a/net/minecraft/client/gui/components/toasts/ToastComponent.java
+++ b/net/minecraft/client/gui/components/toasts/ToastComponent.java
@@ -97,6 +_,7 @@
}
public void addToast(Toast p_94923_) {
+ if (net.minecraftforge.client.ForgeHooksClient.onToastAdd(p_94923_)) return;
this.queued.add(p_94923_);
}
@@ -0,0 +1,10 @@
--- a/net/minecraft/client/gui/components/toasts/ToastManager.java
+++ b/net/minecraft/client/gui/components/toasts/ToastManager.java
@@ -107,6 +_,7 @@
}
public void addToast(Toast p_360768_) {
+ if (net.minecraftforge.client.event.ForgeEventFactoryClient.onToastAdd(p_360768_)) return;
this.queued.add(p_360768_);
}
@@ -1,6 +1,30 @@
--- a/net/minecraft/client/gui/screens/LoadingOverlay.java
+++ b/net/minecraft/client/gui/screens/LoadingOverlay.java
@@ -131,6 +_,7 @@
@@ -61,6 +_,8 @@
return p_169325_ & 16777215 | p_169326_ << 24;
}
+ protected boolean renderContents(GuiGraphics gui, float alpha) { return true; }
+
@Override
public void render(GuiGraphics p_281839_, int p_282704_, int p_283650_, float p_283394_) {
int i = p_281839_.guiWidth();
@@ -99,6 +_,7 @@
f2 = 1.0F;
}
+ if (renderContents(p_281839_, f2)) {
int k2 = (int)((double)p_281839_.guiWidth() * 0.5);
int l2 = (int)((double)p_281839_.guiHeight() * 0.5);
double d1 = Math.min((double)p_281839_.guiWidth() * 0.75, (double)p_281839_.guiHeight()) * 0.25;
@@ -114,12 +_,14 @@
if (f < 1.0F) {
this.drawProgressBar(p_281839_, i / 2 - j1, l1 - 5, i / 2 + j1, l1 + 5, 1.0F - Mth.clamp(f, 0.0F, 1.0F));
}
+ }
if (f >= 2.0F) {
this.minecraft.setOverlay(null);
}
if (this.fadeOutStart == -1L && this.reload.isDone() && (!this.fadeIn || f1 >= 2.0F)) {
@@ -8,7 +32,7 @@
try {
this.reload.checkExceptions();
this.onFinish.accept(Optional.empty());
@@ -138,7 +_,6 @@
@@ -127,7 +_,6 @@
this.onFinish.accept(Optional.of(throwable));
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/PauseScreen.java
+++ b/net/minecraft/client/gui/screens/PauseScreen.java
@@ -94,6 +_,7 @@
@@ -95,6 +_,7 @@
} else {
gridlayout$rowhelper.addChild(this.openScreenButton(PLAYER_REPORTING, () -> new SocialInteractionsScreen(this)));
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/Screen.java
+++ b/net/minecraft/client/gui/screens/Screen.java
@@ -201,7 +_,7 @@
@@ -200,7 +_,7 @@
}
public void onClose() {
@@ -9,7 +9,7 @@
}
protected <T extends GuiEventListener & Renderable & NarratableEntry> T addRenderableWidget(T p_169406_) {
@@ -312,8 +_,10 @@
@@ -311,8 +_,10 @@
this.width = p_96608_;
this.height = p_96609_;
if (!this.initialized) {
@@ -20,7 +20,7 @@
} else {
this.repositionElements();
}
@@ -326,8 +_,10 @@
@@ -325,8 +_,10 @@
protected void rebuildWidgets() {
this.clearWidgets();
this.clearFocus();
@@ -31,15 +31,15 @@
}
@Override
@@ -354,6 +_,7 @@
@@ -353,6 +_,7 @@
this.renderBlurredBackground(p_297268_);
this.renderBlurredBackground();
this.renderMenuBackground(p_283688_);
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onRenderScreenBackground(this, p_283688_);
}
protected void renderBlurredBackground(float p_336041_) {
@@ -463,6 +_,19 @@
protected void renderBlurredBackground() {
@@ -454,6 +_,19 @@
}
public void onFilesDrop(List<Path> p_96591_) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/TitleScreen.java
+++ b/net/minecraft/client/gui/screens/TitleScreen.java
@@ -60,6 +_,7 @@
@@ -58,6 +_,7 @@
private boolean fading;
private long fadeInStart;
private final LogoRenderer logoRenderer;
@@ -8,32 +8,32 @@
public TitleScreen() {
this(false);
@@ -115,11 +_,15 @@
@@ -111,11 +_,15 @@
int j = this.width - i - 2;
int k = 24;
int l = this.height / 4 + 48;
+ Button modButton = null;
if (this.minecraft.isDemo()) {
this.createDemoMenuOptions(l, 24);
l = this.createDemoMenuOptions(l, 24);
} else {
this.createNormalMenuOptions(l, 24);
l = this.createNormalMenuOptions(l, 24);
+ modButton = this.addRenderableWidget(Button.builder(Component.translatable("fml.menu.mods"), button -> this.minecraft.setScreen(new net.minecraftforge.client.gui.ModListScreen(this)))
+ .pos(this.width / 2 - 100, l + 24 * 2).size(98, 20).build());
+ .pos(this.width / 2 - 100, l).size(98, 20).build());
}
+ modUpdateNotification = net.minecraftforge.client.gui.TitleScreenModUpdateIndicator.init(this, modButton);
l = this.createTestWorldButton(l, 24);
SpriteIconButton spriteiconbutton = this.addRenderableWidget(
CommonButtons.language(
@@ -170,7 +_,7 @@
}).bounds(this.width / 2 - 100, p_96764_ + p_96765_ * 1, 200, 20).tooltip(tooltip).build()).active = flag;
@@ -180,7 +_,7 @@
}).bounds(this.width / 2 - 100, i = p_96764_ + p_96765_, 200, 20).tooltip(tooltip).build()).active = flag;
this.addRenderableWidget(
Button.builder(Component.translatable("menu.online"), p_325369_ -> this.minecraft.setScreen(new RealmsMainScreen(this)))
- .bounds(this.width / 2 - 100, p_96764_ + p_96765_ * 2, 200, 20)
+ .bounds(this.width / 2 + 2, p_96764_ + p_96765_ * 2, 98, 20)
- .bounds(this.width / 2 - 100, p_96764_ = i + p_96765_, 200, 20)
+ .bounds(this.width / 2 + 2, p_96764_ = i + p_96765_, 98, 20)
.tooltip(tooltip)
.build()
)
@@ -276,6 +_,7 @@
@@ -289,6 +_,7 @@
if ((i & -67108864) != 0) {
super.render(p_282860_, p_281753_, p_283539_, p_282628_);
this.logoRenderer.renderLogo(p_282860_, this.width, f);
@@ -41,7 +41,7 @@
if (this.splash != null && !this.minecraft.options.hideSplashTexts().get()) {
this.splash.render(p_282860_, this.width, this.font, i);
}
@@ -291,11 +_,19 @@
@@ -304,10 +_,18 @@
s = s + I18n.get("menu.modded");
}
@@ -55,7 +55,6 @@
+ );
+
if (this.realmsNotificationsEnabled() && f >= 1.0F) {
RenderSystem.enableDepthTest();
this.realmsNotificationsScreen.render(p_282860_, p_281753_, p_283539_, p_282628_);
}
+ if (f >= 1.0f) this.modUpdateNotification.render(p_282860_, p_281753_, p_283539_, p_282628_);
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/advancements/AdvancementTab.java
+++ b/net/minecraft/client/gui/screens/advancements/AdvancementTab.java
@@ -37,6 +_,7 @@
@@ -38,6 +_,7 @@
private int maxY = Integer.MIN_VALUE;
private float fade;
private boolean centered;
@@ -8,7 +8,7 @@
public AdvancementTab(
Minecraft p_97145_, AdvancementsScreen p_97146_, AdvancementTabType p_97147_, int p_97148_, AdvancementNode p_297568_, DisplayInfo p_97150_
@@ -53,6 +_,15 @@
@@ -54,6 +_,15 @@
this.addWidget(this.root, p_297568_.holder());
}
@@ -24,7 +24,7 @@
public AdvancementTabType getType() {
return this.type;
}
@@ -146,8 +_,8 @@
@@ -147,8 +_,8 @@
return null;
} else {
for (AdvancementTabType advancementtabtype : AdvancementTabType.values()) {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/advancements/AdvancementTabType.java
+++ b/net/minecraft/client/gui/screens/advancements/AdvancementTabType.java
@@ -69,6 +_,7 @@
@@ -70,6 +_,7 @@
5
);
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/advancements/AdvancementsScreen.java
+++ b/net/minecraft/client/gui/screens/advancements/AdvancementsScreen.java
@@ -49,6 +_,7 @@
@@ -51,6 +_,7 @@
@Nullable
private AdvancementTab selectedTab;
private boolean isScrolling;
@@ -8,7 +8,7 @@
public AdvancementsScreen(ClientAdvancements p_97340_) {
this(p_97340_, null);
@@ -62,6 +_,19 @@
@@ -64,6 +_,19 @@
@Override
protected void init() {
@@ -28,7 +28,7 @@
this.layout.addTitleHeader(TITLE, this.font);
this.tabs.clear();
this.selectedTab = null;
@@ -106,7 +_,7 @@
@@ -108,7 +_,7 @@
int j = (this.height - 140) / 2;
for (AdvancementTab advancementtab : this.tabs.values()) {
@@ -37,8 +37,8 @@
this.advancements.setSelectedTab(advancementtab.getRootNode().holder(), true);
break;
}
@@ -180,10 +_,12 @@
p_283395_.blit(WINDOW_LOCATION, p_281890_, p_282532_, 0, 0, 252, 140);
@@ -181,10 +_,12 @@
p_283395_.blit(RenderType::guiTextured, WINDOW_LOCATION, p_281890_, p_282532_, 0.0F, 0.0F, 252, 140, 256, 256);
if (this.tabs.size() > 1) {
for (AdvancementTab advancementtab : this.tabs.values()) {
+ if (advancementtab.getPage() == tabPage)
@@ -50,7 +50,7 @@
advancementtab1.drawIcon(p_283395_, p_281890_, p_282532_);
}
}
@@ -203,6 +_,7 @@
@@ -202,6 +_,7 @@
if (this.tabs.size() > 1) {
for (AdvancementTab advancementtab : this.tabs.values()) {
@@ -1,49 +1,32 @@
--- a/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java
@@ -92,6 +_,7 @@
@@ -106,6 +_,7 @@
int i = this.leftPos;
int j = this.topPos;
super.render(p_283479_, p_283661_, p_281248_, p_281886_);
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onContainerRenderBackground(this, p_283479_, p_283661_, p_281248_);
RenderSystem.disableDepthTest();
p_283479_.pose().pushPose();
p_283479_.pose().translate((float)i, (float)j, 0.0F);
@@ -108,12 +_,13 @@
int l = slot.x;
int i1 = slot.y;
if (this.hoveredSlot.isHighlightable()) {
- renderSlotHighlight(p_283479_, l, i1, 0);
+ renderSlotHighlight(p_283479_, l, i1, 0, getSlotColor(k));
}
}
Slot slot = this.hoveredSlot;
@@ -117,6 +_,8 @@
this.onStopHovering(slot);
}
this.renderLabels(p_283479_, p_283661_, p_281248_);
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onContainerRenderForeground(this, p_283479_, p_283661_, p_281248_);
+
this.renderLabels(p_283479_, p_283661_, p_281248_);
ItemStack itemstack = this.draggingItem.isEmpty() ? this.menu.getCarried() : this.draggingItem;
if (!itemstack.isEmpty()) {
int l1 = 8;
@@ -156,13 +_,17 @@
}
public static void renderSlotHighlight(GuiGraphics p_283692_, int p_281453_, int p_281915_, int p_283504_) {
- p_283692_.fillGradient(RenderType.guiOverlay(), p_281453_, p_281915_, p_281453_ + 16, p_281915_ + 16, -2130706433, -2130706433, p_283504_);
+ renderSlotHighlight(p_283692_, p_281453_, p_281915_, p_283504_, -2130706433);
+ }
+
+ public static void renderSlotHighlight(GuiGraphics p_283692_, int p_281453_, int p_281915_, int p_283504_, int color) {
+ p_283692_.fillGradient(RenderType.guiOverlay(), p_281453_, p_281915_, p_281453_ + 16, p_281915_ + 16, color, color, p_283504_);
}
protected void renderTooltip(GuiGraphics p_283594_, int p_282171_, int p_281909_) {
if (this.menu.getCarried().isEmpty() && this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
@@ -197,7 +_,7 @@
ItemStack itemstack = this.hoveredSlot.getItem();
- p_283594_.renderTooltip(this.font, this.getTooltipFromContainerItem(itemstack), itemstack.getTooltipImage(), p_282171_, p_281909_);
+ p_283594_.renderTooltip(this.font, this.getTooltipFromContainerItem(itemstack), itemstack.getTooltipImage(), itemstack, p_282171_, p_281909_);
if (this.menu.getCarried().isEmpty() || this.showTooltipWithItemInHand(itemstack)) {
p_283594_.renderTooltip(
- this.font, this.getTooltipFromContainerItem(itemstack), itemstack.getTooltipImage(), p_282171_, p_281909_, itemstack.get(DataComponents.TOOLTIP_STYLE)
+ this.font, this.getTooltipFromContainerItem(itemstack), itemstack.getTooltipImage(), itemstack, p_282171_, p_281909_
);
}
}
}
@@ -174,7 +_,8 @@
@@ -215,7 +_,8 @@
p_282567_.pose().pushPose();
p_282567_.pose().translate(0.0F, 0.0F, 232.0F);
p_282567_.renderItem(p_281330_, p_281772_, p_281689_);
@@ -53,17 +36,17 @@
p_282567_.pose().popPose();
}
@@ -282,7 +_,8 @@
@@ -321,7 +_,8 @@
if (super.mouseClicked(p_97748_, p_97749_, p_97750_)) {
return true;
} else {
- boolean flag = this.minecraft.options.keyPickItem.matchesMouse(p_97750_) && this.minecraft.gameMode.hasInfiniteItems();
+ InputConstants.Key mouseKey = InputConstants.Type.MOUSE.getOrCreate(p_97750_);
+ boolean flag = this.minecraft.options.keyPickItem.isActiveAndMatches(mouseKey);
Slot slot = this.findSlot(p_97748_, p_97749_);
Slot slot = this.getHoveredSlot(p_97748_, p_97749_);
long i = Util.getMillis();
this.doubleclick = this.lastClickSlot == slot && i - this.lastClickTime < 250L && this.lastClickButton == p_97750_;
@@ -293,6 +_,7 @@
@@ -332,6 +_,7 @@
int j = this.leftPos;
int k = this.topPos;
boolean flag1 = this.hasClickedOutside(p_97748_, p_97749_, j, k, p_97750_);
@@ -71,7 +54,7 @@
int l = -1;
if (slot != null) {
l = slot.index;
@@ -318,7 +_,7 @@
@@ -357,7 +_,7 @@
}
} else if (!this.isQuickCrafting) {
if (this.menu.getCarried().isEmpty()) {
@@ -80,7 +63,7 @@
this.slotClicked(slot, l, p_97750_, ClickType.CLONE);
} else {
boolean flag2 = l != -999
@@ -346,7 +_,7 @@
@@ -385,7 +_,7 @@
this.quickCraftingType = 0;
} else if (p_97750_ == 1) {
this.quickCraftingType = 1;
@@ -89,12 +72,12 @@
this.quickCraftingType = 2;
}
}
@@ -425,10 +_,13 @@
@@ -464,10 +_,13 @@
@Override
public boolean mouseReleased(double p_97812_, double p_97813_, int p_97814_) {
+ super.mouseReleased(p_97812_, p_97813_, p_97814_); //Forge, Call parent to release buttons
Slot slot = this.findSlot(p_97812_, p_97813_);
Slot slot = this.getHoveredSlot(p_97812_, p_97813_);
int i = this.leftPos;
int j = this.topPos;
boolean flag = this.hasClickedOutside(p_97812_, p_97813_, i, j, p_97814_);
@@ -103,7 +86,7 @@
int k = -1;
if (slot != null) {
k = slot.index;
@@ -445,7 +_,7 @@
@@ -484,7 +_,7 @@
if (slot2 != null
&& slot2.mayPickup(this.minecraft.player)
&& slot2.hasItem()
@@ -112,7 +95,7 @@
&& AbstractContainerMenu.canItemQuickReplace(slot2, this.lastQuickMoved, true)) {
this.slotClicked(slot2, slot2.index, p_97814_, ClickType.QUICK_MOVE);
}
@@ -509,7 +_,7 @@
@@ -548,7 +_,7 @@
this.slotClicked(null, -999, AbstractContainerMenu.getQuickcraftMask(2, this.quickCraftingType), ClickType.QUICK_CRAFT);
} else if (!this.menu.getCarried().isEmpty()) {
@@ -121,7 +104,7 @@
this.slotClicked(slot, k, p_97814_, ClickType.CLONE);
} else {
boolean flag1 = k != -999
@@ -568,9 +_,10 @@
@@ -628,9 +_,10 @@
@Override
public boolean keyPressed(int p_97765_, int p_97766_, int p_97767_) {
@@ -133,11 +116,10 @@
this.onClose();
return true;
} else {
@@ -639,5 +_,17 @@
public void onClose() {
this.minecraft.player.closeContainer();
@@ -704,4 +_,11 @@
super.onClose();
+ }
}
+
+ @org.jetbrains.annotations.Nullable
+ public Slot getSlotUnderMouse() { return this.hoveredSlot; }
@@ -145,9 +127,4 @@
+ public int getGuiTop() { return topPos; }
+ public int getXSize() { return imageWidth; }
+ public int getYSize() { return imageHeight; }
+
+ protected int slotColor = -2130706433;
+ public int getSlotColor(int index) {
+ return slotColor;
}
}
@@ -1,15 +1,15 @@
--- a/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java
@@ -112,6 +_,8 @@
private boolean hasClickedOutside;
@@ -114,6 +_,8 @@
private final Set<TagKey<Item>> visibleTags = new HashSet<>();
private final boolean displayOperatorCreativeTab;
private final EffectsInInventory effects;
+ private final List<net.minecraftforge.client.gui.CreativeTabsScreenPage> pages = new java.util.ArrayList<>();
+ private net.minecraftforge.client.gui.CreativeTabsScreenPage currentPage = new net.minecraftforge.client.gui.CreativeTabsScreenPage(new java.util.ArrayList<>());
public CreativeModeInventoryScreen(LocalPlayer p_344408_, FeatureFlagSet p_260074_, boolean p_259569_) {
super(new CreativeModeInventoryScreen.ItemPickerMenu(p_344408_), p_344408_.getInventory(), CommonComponents.EMPTY);
@@ -159,7 +_,7 @@
@@ -162,7 +_,7 @@
private void refreshCurrentTabContents(Collection<ItemStack> p_261591_) {
int i = this.menu.getRowIndexForScroll(this.scrollOffs);
this.menu.items.clear();
@@ -18,7 +18,7 @@
this.refreshSearchResults();
} else {
this.menu.items.addAll(p_261591_);
@@ -322,6 +_,35 @@
@@ -330,6 +_,35 @@
protected void init() {
if (this.minecraft.gameMode.hasInfiniteItems()) {
super.init();
@@ -54,7 +54,7 @@
this.searchBox = new EditBox(this.font, this.leftPos + 82, this.topPos + 6, 80, 9, Component.translatable("itemGroup.search"));
this.searchBox.setMaxLength(50);
this.searchBox.setBordered(false);
@@ -368,7 +_,7 @@
@@ -376,7 +_,7 @@
public boolean charTyped(char p_98521_, int p_98522_) {
if (this.ignoreTextInput) {
return false;
@@ -63,7 +63,7 @@
return false;
} else {
String s = this.searchBox.getValue();
@@ -387,7 +_,7 @@
@@ -395,7 +_,7 @@
@Override
public boolean keyPressed(int p_98547_, int p_98548_, int p_98549_) {
this.ignoreTextInput = false;
@@ -72,7 +72,7 @@
if (this.minecraft.options.keyChat.matches(p_98547_, p_98548_)) {
this.ignoreTextInput = true;
this.selectTab(CreativeModeTabs.searchTab());
@@ -423,6 +_,7 @@
@@ -431,6 +_,7 @@
}
private void refreshSearchResults() {
@@ -80,7 +80,7 @@
this.menu.items.clear();
this.visibleTags.clear();
String s = this.searchBox.getValue();
@@ -435,10 +_,10 @@
@@ -443,10 +_,10 @@
SearchTree<ItemStack> searchtree;
if (s.startsWith("#")) {
s = s.substring(1);
@@ -93,7 +93,7 @@
}
this.menu.items.addAll(searchtree.search(s.toLowerCase(Locale.ROOT)));
@@ -466,7 +_,8 @@
@@ -478,7 +_,8 @@
@Override
protected void renderLabels(GuiGraphics p_283168_, int p_281774_, int p_281466_) {
if (selectedTab.showTitle()) {
@@ -103,7 +103,7 @@
}
}
@@ -476,7 +_,7 @@
@@ -488,7 +_,7 @@
double d0 = p_98531_ - (double)this.leftPos;
double d1 = p_98532_ - (double)this.topPos;
@@ -112,7 +112,7 @@
if (this.checkTabClicked(creativemodetab, d0, d1)) {
return true;
}
@@ -498,7 +_,7 @@
@@ -510,7 +_,7 @@
double d1 = p_98623_ - (double)this.topPos;
this.scrolling = false;
@@ -121,15 +121,7 @@
if (this.checkTabClicked(creativemodetab, d0, d1)) {
this.selectTab(creativemodetab);
return true;
@@ -516,6 +_,7 @@
private void selectTab(CreativeModeTab p_98561_) {
CreativeModeTab creativemodetab = selectedTab;
selectedTab = p_98561_;
+ slotColor = p_98561_.getSlotColor();
this.quickCraftSlots.clear();
this.menu.items.clear();
this.clearDraggingState();
@@ -592,13 +_,15 @@
@@ -604,13 +_,15 @@
this.originalSlots = null;
}
@@ -146,9 +138,9 @@
this.refreshSearchResults();
} else {
@@ -661,7 +_,15 @@
public void render(GuiGraphics p_283000_, int p_281317_, int p_282770_, float p_281295_) {
@@ -676,7 +_,15 @@
super.render(p_283000_, p_281317_, p_282770_, p_281295_);
this.effects.render(p_283000_, p_281317_, p_282770_, p_281295_);
- for (CreativeModeTab creativemodetab : CreativeModeTabs.tabs()) {
+ if (this.pages.size() != 1) {
@@ -163,7 +155,7 @@
if (this.checkTabHovering(p_283000_, creativemodetab, p_281317_, p_282770_)) {
break;
}
@@ -673,6 +_,7 @@
@@ -688,6 +_,7 @@
p_283000_.renderTooltip(this.font, TRASH_SLOT_TOOLTIP, p_281317_, p_282770_);
}
@@ -171,7 +163,7 @@
this.renderTooltip(p_283000_, p_281317_, p_282770_);
}
@@ -680,7 +_,7 @@
@@ -700,7 +_,7 @@
public List<Component> getTooltipFromContainerItem(ItemStack p_281769_) {
boolean flag = this.hoveredSlot != null && this.hoveredSlot instanceof CreativeModeInventoryScreen.CustomCreativeSlot;
boolean flag1 = selectedTab.getType() == CreativeModeTab.Type.CATEGORY;
@@ -180,7 +172,7 @@
TooltipFlag.Default tooltipflag$default = this.minecraft.options.advancedItemTooltips ? TooltipFlag.Default.ADVANCED : TooltipFlag.Default.NORMAL;
TooltipFlag tooltipflag = flag ? tooltipflag$default.asCreative() : tooltipflag$default;
List<Component> list = p_281769_.getTooltipLines(Item.TooltipContext.of(this.minecraft.level), this.minecraft.player, tooltipflag);
@@ -699,7 +_,7 @@
@@ -719,7 +_,7 @@
int i = 1;
for (CreativeModeTab creativemodetab : CreativeModeTabs.tabs()) {
@@ -189,7 +181,7 @@
list1.add(i++, creativemodetab.getDisplayName().copy().withStyle(ChatFormatting.BLUE));
}
}
@@ -710,7 +_,7 @@
@@ -730,7 +_,7 @@
@Override
protected void renderBg(GuiGraphics p_282663_, float p_282504_, int p_282089_, int p_282249_) {
@@ -198,15 +190,15 @@
if (creativemodetab != selectedTab) {
this.renderTabButton(p_282663_, creativemodetab);
}
@@ -726,6 +_,7 @@
p_282663_.blitSprite(resourcelocation, j, k + (int)((float)(i - k - 17) * this.scrollOffs), 12, 15);
@@ -746,6 +_,7 @@
p_282663_.blitSprite(RenderType::guiTextured, resourcelocation, j, k + (int)((float)(i - k - 17) * this.scrollOffs), 12, 15);
}
+ if (currentPage.getVisibleTabs().contains(selectedTab)) //Forge: only display tab selection when the selected tab is on the current page
this.renderTabButton(p_282663_, selectedTab);
if (selectedTab.getType() == CreativeModeTab.Type.INVENTORY) {
InventoryScreen.renderEntityInInventoryFollowsMouse(
@@ -744,7 +_,7 @@
@@ -764,7 +_,7 @@
}
private int getTabX(CreativeModeTab p_260136_) {
@@ -215,7 +207,7 @@
int j = 27;
int k = 27 * i;
if (p_260136_.isAlignedRight()) {
@@ -756,7 +_,7 @@
@@ -776,7 +_,7 @@
private int getTabY(CreativeModeTab p_260181_) {
int i = 0;
@@ -224,7 +216,7 @@
i -= 32;
} else {
i += this.imageHeight;
@@ -784,8 +_,8 @@
@@ -804,8 +_,8 @@
protected void renderTabButton(GuiGraphics p_283590_, CreativeModeTab p_283489_) {
boolean flag = p_283489_ == selectedTab;
@@ -235,15 +227,15 @@
int j = this.leftPos + this.getTabX(p_283489_);
int k = this.topPos - (flag1 ? 28 : -(this.imageHeight - 4));
ResourceLocation[] aresourcelocation;
@@ -795,6 +_,7 @@
@@ -815,6 +_,7 @@
aresourcelocation = flag ? SELECTED_BOTTOM_TABS : UNSELECTED_BOTTOM_TABS;
}
+ com.mojang.blaze3d.systems.RenderSystem.enableBlend(); //Forge: Make sure blend is enabled else tabs show a white border.
p_283590_.blitSprite(aresourcelocation[Mth.clamp(i, 0, aresourcelocation.length)], j, k, 26, 32);
p_283590_.blitSprite(RenderType::guiTextured, aresourcelocation[Mth.clamp(i, 0, aresourcelocation.length)], j, k, 26, 32);
p_283590_.pose().pushPose();
p_283590_.pose().translate(0.0F, 0.0F, 100.0F);
@@ -836,6 +_,14 @@
@@ -856,6 +_,14 @@
}
}
@@ -258,7 +250,7 @@
@OnlyIn(Dist.CLIENT)
static class CustomCreativeSlot extends Slot {
public CustomCreativeSlot(Container p_98633_, int p_98634_, int p_98635_, int p_98636_) {
@@ -1020,6 +_,22 @@
@@ -1037,6 +_,22 @@
@Override
public boolean mayPickup(Player p_98665_) {
return this.target.mayPickup(p_98665_);
@@ -275,8 +267,8 @@
+ }
+
+ @Override
+ public Slot setBackground(ResourceLocation atlas, ResourceLocation sprite) {
+ this.target.setBackground(atlas, sprite);
+ public Slot setBackground(ResourceLocation sprite) {
+ this.target.setBackground(sprite);
+ return this;
}
}
@@ -1,10 +1,10 @@
--- a/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/EffectRenderingInventoryScreen.java
@@ -47,12 +_,16 @@
--- a/net/minecraft/client/gui/screens/inventory/EffectsInInventory.java
+++ b/net/minecraft/client/gui/screens/inventory/EffectsInInventory.java
@@ -48,12 +_,16 @@
Collection<MobEffectInstance> collection = this.minecraft.player.getActiveEffects();
if (!collection.isEmpty() && j >= 32) {
boolean flag = j >= 120;
+ var event = net.minecraftforge.client.ForgeHooksClient.onScreenPotionSize(this, j, !flag, i);
+ var event = net.minecraftforge.client.event.ForgeEventFactoryClient.onScreenEffectSize(this.screen, j, !flag, i);
+ if (event.isCanceled()) return;
+ flag = !event.isCompact();
+ i = event.getHorizontalOffset();
@@ -15,30 +15,40 @@
- Iterable<MobEffectInstance> iterable = Ordering.natural().sortedCopy(collection);
+ Iterable<MobEffectInstance> iterable = collection.stream().filter(net.minecraftforge.client.ForgeHooksClient::shouldRenderEffect).sorted().toList();
this.renderBackgrounds(p_281945_, i, k, iterable, flag);
this.renderIcons(p_281945_, i, k, iterable, flag);
this.renderBackgrounds(p_362146_, i, k, iterable, flag);
this.renderIcons(p_362146_, i, k, iterable, flag);
if (flag) {
@@ -98,6 +_,11 @@
int i = this.topPos;
@@ -99,6 +_,11 @@
int i = this.screen.topPos;
for (MobEffectInstance mobeffectinstance : p_282642_) {
for (MobEffectInstance mobeffectinstance : p_361981_) {
+ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance);
+ if (renderer.renderInventoryIcon(mobeffectinstance, this, p_282745_, p_282521_ + (p_281536_ ? 6 : 7), i, 0)) {
+ i += p_282291_;
+ if (renderer.renderInventoryIcon(mobeffectinstance, this, p_367085_, p_367644_ + (p_368681_ ? 6 : 7), i, 0)) {
+ i += p_367522_;
+ continue;
+ }
Holder<MobEffect> holder = mobeffectinstance.getEffect();
TextureAtlasSprite textureatlassprite = mobeffecttexturemanager.get(holder);
p_282745_.blit(p_282521_ + (p_281536_ ? 6 : 7), i + 7, 0, 18, 18, textureatlassprite);
@@ -109,6 +_,11 @@
int i = this.topPos;
p_367085_.blitSprite(RenderType::guiTextured, textureatlassprite, p_367644_ + (p_368681_ ? 6 : 7), i + 7, 18, 18);
@@ -110,6 +_,11 @@
int i = this.screen.topPos;
for (MobEffectInstance mobeffectinstance : p_281986_) {
for (MobEffectInstance mobeffectinstance : p_365480_) {
+ var renderer = net.minecraftforge.client.extensions.common.IClientMobEffectExtensions.of(mobeffectinstance);
+ if (renderer.renderInventoryText(mobeffectinstance, this, p_281462_, p_283484_, i, 0)) {
+ i += p_282057_;
+ if (renderer.renderInventoryText(mobeffectinstance, this, p_361851_, p_367468_, i, 0)) {
+ i += p_365556_;
+ continue;
+ }
Component component = this.getEffectName(mobeffectinstance);
p_281462_.drawString(this.font, component, p_283484_ + 10 + 18, i + 6, 16777215);
p_361851_.drawString(this.screen.getFont(), component, p_367468_ + 10 + 18, i + 6, 16777215);
Component component1 = MobEffectUtil.formatDuration(mobeffectinstance, 1.0F, this.minecraft.level.tickRateManager().tickrate());
@@ -125,5 +_,9 @@
}
return mutablecomponent;
+ }
+
+ public AbstractContainerScreen<?> getScreen() {
+ return this.screen;
}
}
@@ -1,18 +1,18 @@
--- a/net/minecraft/client/gui/screens/inventory/EnchantmentScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/EnchantmentScreen.java
@@ -111,7 +_,7 @@
@@ -109,7 +_,7 @@
int l1 = 86 - this.font.width(s);
FormattedText formattedtext = EnchantmentNames.getInstance().getRandomName(this.font, l1);
int i2 = 6839882;
- if ((k < l + 1 || this.minecraft.player.experienceLevel < k1) && !this.minecraft.player.getAbilities().instabuild) {
+ if (((k < l + 1 || this.minecraft.player.experienceLevel < k1) && !this.minecraft.player.getAbilities().instabuild) || this.menu.enchantClue[l] == -1) { // Forge: render buttons as disabled when enchantable but enchantability not met on lower levels{
RenderSystem.enableBlend();
p_282430_.blitSprite(ENCHANTMENT_SLOT_DISABLED_SPRITE, i1, j + 14 + 19 * l, 108, 19);
p_282430_.blitSprite(DISABLED_LEVEL_SPRITES[l], i1 + 1, j + 15 + 19 * l, 16, 16);
@@ -177,13 +_,16 @@
p_282430_.blitSprite(RenderType::guiTextured, ENCHANTMENT_SLOT_DISABLED_SPRITE, i1, j + 14 + 19 * l, 108, 19);
p_282430_.blitSprite(RenderType::guiTextured, DISABLED_LEVEL_SPRITES[l], i1 + 1, j + 15 + 19 * l, 16, 16);
p_282430_.drawWordWrap(this.font, formattedtext, j1, j + 16 + 19 * l, l1, (i2 & 16711422) >> 1, false);
@@ -175,13 +_,16 @@
.registryAccess()
.registryOrThrow(Registries.ENCHANTMENT)
.getHolder(this.menu.enchantClue[j]);
.lookupOrThrow(Registries.ENCHANTMENT)
.get(this.menu.enchantClue[j]);
- if (!optional.isEmpty()) {
+ {
int l = this.menu.levelClue[j];
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/inventory/HangingSignEditScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/HangingSignEditScreen.java
@@ -15,7 +_,7 @@
@@ -16,7 +_,7 @@
private static final Vector3f TEXT_SCALE = new Vector3f(1.0F, 1.0F, 1.0F);
private static final int TEXTURE_WIDTH = 16;
private static final int TEXTURE_HEIGHT = 16;
@@ -1,16 +1,17 @@
--- a/net/minecraft/client/gui/screens/inventory/MerchantScreen.java
+++ b/net/minecraft/client/gui/screens/inventory/MerchantScreen.java
@@ -234,7 +_,12 @@
p_281357_.renderItemDecorations(this.font, p_283466_, p_282403_, p_283601_);
@@ -232,6 +_,14 @@
} else {
p_281357_.renderItemDecorations(this.font, p_282046_, p_282403_, p_283601_, p_282046_.getCount() == 1 ? "1" : null);
- p_281357_.renderItemDecorations(this.font, p_283466_, p_282403_ + 14, p_283601_, p_283466_.getCount() == 1 ? "1" : null);
p_281357_.renderItemDecorations(this.font, p_283466_, p_282403_ + 14, p_283601_, p_283466_.getCount() == 1 ? "1" : null);
+ /*
+ // Forge: fixes Forge-8806, code for count rendering taken from GuiGraphics#renderGuiItemDecorations
+ p_281357_.pose().pushPose();
+ p_281357_.pose().translate(0.0F, 0.0F, 200.0F);
+ String count = p_283466_.getCount() == 1 ? "1" : String.valueOf(p_283466_.getCount());
+ font.drawInBatch(count, (float) (p_282403_ + 14) + 19 - 2 - font.width(count), (float)p_283601_ + 6 + 3, 0xFFFFFF, true, p_281357_.pose().last().pose(), p_281357_.bufferSource(), net.minecraft.client.gui.Font.DisplayMode.NORMAL, 0, 15728880, false);
+ p_281357_.pose().popPose();
+ */
p_281357_.pose().pushPose();
p_281357_.pose().translate(0.0F, 0.0F, 300.0F);
p_281357_.blitSprite(DISCOUNT_STRIKETHRUOGH_SPRITE, p_282403_ + 7, p_283601_ + 12, 0, 9, 2);
p_281357_.blitSprite(RenderType::guiTextured, DISCOUNT_STRIKETHRUOGH_SPRITE, p_282403_ + 7, p_283601_ + 12, 9, 2);
@@ -1,11 +1,11 @@
--- a/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java
+++ b/net/minecraft/client/gui/screens/inventory/tooltip/ClientTooltipComponent.java
@@ -22,6 +_,8 @@
} else if (p_169951_ instanceof ClientActivePlayersTooltip.ActivePlayersTooltip clientactiveplayerstooltip$activeplayerstooltip) {
return new ClientActivePlayersTooltip(clientactiveplayerstooltip$activeplayerstooltip);
} else {
+ ClientTooltipComponent result = net.minecraftforge.client.gui.ClientTooltipComponentManager.createClientTooltipComponent(p_169951_);
+ if (result != null) return result;
throw new IllegalArgumentException("Unknown TooltipComponent");
}
@@ -25,7 +_,7 @@
case ClientActivePlayersTooltip.ActivePlayersTooltip clientactiveplayerstooltip$activeplayerstooltip -> new ClientActivePlayersTooltip(
clientactiveplayerstooltip$activeplayerstooltip
);
- default -> throw new IllegalArgumentException("Unknown TooltipComponent");
+ default -> net.minecraftforge.client.gui.ClientTooltipComponentManager.createClientTooltipComponent(p_169951_);
});
}
@@ -1,40 +0,0 @@
--- a/net/minecraft/client/gui/screens/inventory/tooltip/TooltipRenderUtil.java
+++ b/net/minecraft/client/gui/screens/inventory/tooltip/TooltipRenderUtil.java
@@ -17,16 +_,21 @@
private static final int BORDER_COLOR_BOTTOM = 1344798847;
public static void renderTooltipBackground(GuiGraphics p_282666_, int p_281901_, int p_281846_, int p_281559_, int p_283336_, int p_283422_) {
+ renderTooltipBackground(p_282666_, p_281901_, p_281846_, p_281559_, p_283336_, p_283422_, BACKGROUND_COLOR, BACKGROUND_COLOR, BORDER_COLOR_TOP, BORDER_COLOR_BOTTOM);
+ }
+
+ // Forge: Allow specifying colors for the inner border gradient and a gradient instead of a single color for the background and outer border
+ public static void renderTooltipBackground(GuiGraphics p_282666_, int p_281901_, int p_281846_, int p_281559_, int p_283336_, int p_283422_, int backgroundTop, int backgroundBottom, int borderTop, int borderBottom) {
int i = p_281901_ - 3;
int j = p_281846_ - 3;
int k = p_281559_ + 3 + 3;
int l = p_283336_ + 3 + 3;
- renderHorizontalLine(p_282666_, i, j - 1, k, p_283422_, -267386864);
- renderHorizontalLine(p_282666_, i, j + l, k, p_283422_, -267386864);
- renderRectangle(p_282666_, i, j, k, l, p_283422_, -267386864);
- renderVerticalLine(p_282666_, i - 1, j, l, p_283422_, -267386864);
- renderVerticalLine(p_282666_, i + k, j, l, p_283422_, -267386864);
- renderFrameGradient(p_282666_, i, j + 1, k, l, p_283422_, 1347420415, 1344798847);
+ renderHorizontalLine(p_282666_, i, j - 1, k, p_283422_, backgroundTop);
+ renderHorizontalLine(p_282666_, i, j + l, k, p_283422_, backgroundBottom);
+ renderRectangleGradient(p_282666_, i, j, k, l, p_283422_, backgroundTop, backgroundBottom);
+ renderVerticalLineGradient(p_282666_, i - 1, j, l, p_283422_, backgroundTop, backgroundBottom);
+ renderVerticalLineGradient(p_282666_, i + k, j, l, p_283422_, backgroundTop, backgroundBottom);
+ renderFrameGradient(p_282666_, i, j + 1, k, l, p_283422_, borderTop, borderBottom);
}
private static void renderFrameGradient(
@@ -52,5 +_,9 @@
private static void renderRectangle(GuiGraphics p_281392_, int p_282294_, int p_283353_, int p_282640_, int p_281964_, int p_283211_, int p_282349_) {
p_281392_.fill(p_282294_, p_283353_, p_282294_ + p_282640_, p_283353_ + p_281964_, p_283211_, p_282349_);
+ }
+
+ private static void renderRectangleGradient(GuiGraphics p_281392_, int p_282294_, int p_283353_, int p_282640_, int p_281964_, int p_283211_, int p_282349_, int colorTo) {
+ p_281392_.fillGradient(p_282294_, p_283353_, p_282294_ + p_282640_, p_283353_ + p_281964_, p_283211_, p_282349_, colorTo);
}
}
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/multiplayer/ServerSelectionList.java
+++ b/net/minecraft/client/gui/screens/multiplayer/ServerSelectionList.java
@@ -372,6 +_,8 @@
@@ -371,6 +_,8 @@
this.screen.setTooltipForNextRenderPass(Lists.transform(this.onlinePlayersTooltip, Component::getVisualOrderText));
}
@@ -1,18 +1,6 @@
--- a/net/minecraft/client/gui/screens/options/controls/KeyBindsList.java
+++ b/net/minecraft/client/gui/screens/options/controls/KeyBindsList.java
@@ -69,6 +_,11 @@
return 340;
}
+ @Override
+ protected int getScrollbarPosition() {
+ return super.getScrollbarPosition() + 20;
+ }
+
@OnlyIn(Dist.CLIENT)
public class CategoryEntry extends KeyBindsList.Entry {
final Component name;
@@ -153,9 +_,10 @@
@@ -148,9 +_,10 @@
this.name = p_343976_;
this.changeButton = Button.builder(p_343976_, p_342196_ -> {
KeyBindsList.this.keyBindsScreen.selectedKey = p_343088_;
@@ -24,15 +12,16 @@
.createNarration(
p_342179_ -> p_343088_.isUnbound()
? Component.translatable("narrator.controls.unbound", p_343976_)
@@ -163,6 +_,7 @@
@@ -158,7 +_,7 @@
)
.build();
this.resetButton = Button.builder(RESET_BUTTON_TITLE, p_343650_ -> {
this.resetButton = Button.builder(RESET_BUTTON_TITLE, p_357685_ -> {
- p_343088_.setKey(p_343088_.getDefaultKey());
+ this.key.setToDefault();
KeyBindsList.this.minecraft.options.setKey(p_343088_, p_343088_.getDefaultKey());
KeyBindsList.this.resetMappingAndUpdateButtons();
}).bounds(0, 0, 50, 20).createNarration(p_344192_ -> Component.translatable("narrator.controls.reset", p_343976_)).build();
@@ -215,7 +_,7 @@
this.refreshEntry();
@@ -210,7 +_,7 @@
MutableComponent mutablecomponent = Component.empty();
if (!this.key.isUnbound()) {
for (KeyMapping keymapping : KeyBindsList.this.minecraft.options.keyMappings) {
@@ -9,15 +9,15 @@
}
this.keyBindsList.resetMappingAndUpdateButtons();
@@ -73,11 +_,14 @@
@@ -73,11 +_,12 @@
public boolean keyPressed(int p_342715_, int p_342862_, int p_345515_) {
if (this.selectedKey != null) {
if (p_342715_ == 256) {
- this.selectedKey.setKey(InputConstants.UNKNOWN);
+ this.selectedKey.setKeyModifierAndCode(null, InputConstants.UNKNOWN);
this.options.setKey(this.selectedKey, InputConstants.UNKNOWN);
} else {
- this.selectedKey.setKey(InputConstants.getKey(p_342715_, p_342862_));
+ this.selectedKey.setKeyModifierAndCode(null, InputConstants.getKey(p_342715_, p_342862_));
this.options.setKey(this.selectedKey, InputConstants.getKey(p_342715_, p_342862_));
}
+ if (p_342715_ == 256 || !net.minecraftforge.client.settings.KeyModifier.isKeyCodeModifier(this.selectedKey.getKey()))
@@ -6,6 +6,6 @@
p_100014_.setSelected(null);
- p_100015_.forEach(
+ p_100015_.filter(PackSelectionModel.Entry::notHidden).forEach(
p_340813_ -> {
p_374582_ -> {
TransferableSelectionList.PackEntry transferableselectionlist$packentry1 = new TransferableSelectionList.PackEntry(
this.minecraft, p_100014_, p_340813_
this.minecraft, p_100014_, p_374582_
@@ -1,20 +0,0 @@
--- a/net/minecraft/client/gui/screens/recipebook/RecipeBookComponent.java
+++ b/net/minecraft/client/gui/screens/recipebook/RecipeBookComponent.java
@@ -115,7 +_,7 @@
this.initFilterButtonTextures();
this.tabButtons.clear();
- for (RecipeBookCategories recipebookcategories : RecipeBookCategories.getCategories(this.menu.getRecipeBookType())) {
+ for (RecipeBookCategories recipebookcategories : this.menu.getRecipeBookCategories()) {
this.tabButtons.add(new RecipeBookTabButton(recipebookcategories));
}
@@ -293,7 +_,7 @@
}
if (itemstack != null && this.minecraft.screen != null) {
- p_282776_.renderComponentTooltip(this.minecraft.font, Screen.getTooltipFromItem(this.minecraft, itemstack), p_282948_, p_283050_);
+ p_282776_.renderComponentTooltip(this.minecraft.font, Screen.getTooltipFromItem(this.minecraft, itemstack), p_282948_, p_283050_, itemstack);
}
}
@@ -1,14 +1,14 @@
--- a/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java
+++ b/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java
@@ -118,6 +_,7 @@
public static void openFresh(Minecraft p_232897_, @Nullable Screen p_232898_) {
queueLoadScreen(p_232897_, PREPARING_WORLD_DATA);
PackRepository packrepository = new PackRepository(new ServerPacksSource(p_232897_.directoryValidator()));
@@ -168,6 +_,7 @@
) {
queueLoadScreen(p_369292_, PREPARING_WORLD_DATA);
PackRepository packrepository = new PackRepository(new ServerPacksSource(p_369292_.directoryValidator()));
+ net.minecraftforge.event.ForgeEventFactory.addPackFindersServer(packrepository::addPackFinder);
WorldLoader.InitConfig worldloader$initconfig = createDefaultLoadConfig(packrepository, WorldDataConfiguration.DEFAULT);
CompletableFuture<WorldCreationContext> completablefuture = WorldLoader.load(
worldloader$initconfig,
@@ -415,7 +_,7 @@
@@ -468,7 +_,7 @@
if (p_269627_) {
p_270552_.accept(this.uiState.getSettings().dataConfiguration());
} else {
@@ -17,7 +17,7 @@
}
},
Component.translatable("dataPack.validation.failed"),
@@ -533,6 +_,7 @@
@@ -582,6 +_,7 @@
if (path != null) {
if (this.tempDataPackRepository == null) {
this.tempDataPackRepository = ServerPacksSource.createPackRepository(path, this.packValidator);
@@ -1,11 +1,15 @@
--- a/net/minecraft/client/gui/screens/worldselection/WorldCreationContext.java
+++ b/net/minecraft/client/gui/screens/worldselection/WorldCreationContext.java
@@ -62,6 +_,10 @@
@@ -75,6 +_,14 @@
);
}
+ public WorldCreationContext withDataConfiguration(WorldDataConfiguration dataConfiguration) {
+ return new WorldCreationContext(this.options, this.datapackDimensions, this.selectedDimensions, this.worldgenRegistries, this.dataPackResources, dataConfiguration);
+ return new WorldCreationContext(this.options, this.datapackDimensions, this.selectedDimensions, this.worldgenRegistries, this.dataPackResources, dataConfiguration, this.initialWorldCreationOptions);
+ }
+
+ public WorldCreationContext withInitalOptions(InitialWorldCreationOptions initialWorldCreationOptions) {
+ return new WorldCreationContext(this.options, this.datapackDimensions, this.selectedDimensions, this.worldgenRegistries, this.dataPackResources, this.dataConfiguration, initialWorldCreationOptions);
+ }
+
public RegistryAccess.Frozen worldgenLoadContext() {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/worldselection/WorldCreationUiState.java
+++ b/net/minecraft/client/gui/screens/worldselection/WorldCreationUiState.java
@@ -225,7 +_,7 @@
@@ -234,7 +_,7 @@
@Nullable
public PresetEditor getPresetEditor() {
Holder<WorldPreset> holder = this.getWorldType().preset();
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/gui/screens/worldselection/WorldOpenFlows.java
+++ b/net/minecraft/client/gui/screens/worldselection/WorldOpenFlows.java
@@ -321,6 +_,8 @@
@@ -329,6 +_,8 @@
this.minecraft.forceSetScreen(new GenericMessageScreen(Component.translatable("selectWorld.resource_load")));
PackRepository packrepository = ServerPacksSource.createPackRepository(p_333651_);
@@ -8,16 +8,16 @@
static final Component FROM_NEWER_TOOLTIP_1 = Component.translatable("selectWorld.tooltip.fromNewerVersion1").withStyle(ChatFormatting.RED);
static final Component FROM_NEWER_TOOLTIP_2 = Component.translatable("selectWorld.tooltip.fromNewerVersion2").withStyle(ChatFormatting.RED);
static final Component SNAPSHOT_TOOLTIP_1 = Component.translatable("selectWorld.tooltip.snapshot1").withStyle(ChatFormatting.GOLD);
@@ -402,6 +_,7 @@
RenderSystem.enableBlend();
p_281612_.blit(this.icon.textureLocation(), p_282820_, p_283181_, 0.0F, 0.0F, 32, 32, 32, 32);
RenderSystem.disableBlend();
@@ -400,6 +_,7 @@
p_281612_.drawString(this.minecraft.font, s1, p_282820_ + 32 + 3, p_283181_ + 9 + 3, -8355712);
p_281612_.drawString(this.minecraft.font, component, p_282820_ + 32 + 3, p_283181_ + 9 + 9 + 3, -8355712);
p_281612_.blit(RenderType::guiTextured, this.icon.textureLocation(), p_282820_, p_283181_, 0.0F, 0.0F, 32, 32, 32, 32);
+ renderExperimentalWarning(p_281612_, p_283204_, p_283025_, p_283181_, p_282820_);
if (this.minecraft.options.touchscreen().get() || p_283396_) {
p_281612_.fill(p_282820_, p_283181_, p_282820_ + 32, p_283181_ + 32, -1601138544);
int j = p_283204_ - p_282820_;
@@ -448,6 +_,19 @@
p_281612_.blitSprite(resourcelocation, p_282820_, p_283181_, 32, 32);
@@ -446,6 +_,19 @@
p_281612_.blitSprite(RenderType::guiTextured, resourcelocation, p_282820_, p_283181_, 32, 32);
}
}
+ }
@@ -26,7 +26,7 @@
+ private void renderExperimentalWarning(GuiGraphics guiGraphics, int mouseX, int mouseY, int top, int left) {
+ if (this.summary.isLifecycleExperimental()) {
+ int leftStart = left + WorldSelectionList.this.getRowWidth();
+ guiGraphics.blit(WorldSelectionList.FORGE_EXPERIMENTAL_WARNING_ICON, leftStart - 36, top, 0.0F, 0.0F, 32, 32, 32, 32);
+ guiGraphics.blit(RenderType::guiTextured, WorldSelectionList.FORGE_EXPERIMENTAL_WARNING_ICON, leftStart - 36, top, 0.0F, 0.0F, 32, 32, 32, 32);
+ if (WorldSelectionList.this.getEntryAtPosition(mouseX, mouseY) == this && mouseX > leftStart - 36 && mouseX < leftStart) {
+ var font = Minecraft.getInstance().font;
+ List<net.minecraft.util.FormattedCharSequence> tooltip = font.split(Component.translatable("forge.experimentalsettings.tooltip"), 200);
@@ -1,12 +1,13 @@
--- a/net/minecraft/client/main/Main.java
+++ b/net/minecraft/client/main/Main.java
@@ -111,8 +_,8 @@
@@ -121,8 +_,8 @@
CrashReport.preload();
logger = LogUtils.getLogger();
s1 = "Bootstrap";
- Bootstrap.bootStrap();
GameLoadTimesEvent.INSTANCE.setBootstrapTime(Bootstrap.bootstrapDuration.get());
- ClientBootstrap.bootstrap();
+ net.minecraftforge.fml.loading.BackgroundWaiter.runAndTick(Bootstrap::bootStrap, net.minecraftforge.fml.loading.FMLLoader.progressWindowTick);
+ net.minecraftforge.fml.loading.BackgroundWaiter.runAndTick(ClientBootstrap::bootstrap, net.minecraftforge.fml.loading.FMLLoader.progressWindowTick);
GameLoadTimesEvent.INSTANCE.setBootstrapTime(Bootstrap.bootstrapDuration.get());
Bootstrap.validate();
s1 = "Argument parsing";
List<String> list = optionset.valuesOf(optionspec27);
@@ -1,24 +1,24 @@
--- a/net/minecraft/client/model/HumanoidModel.java
+++ b/net/minecraft/client/model/HumanoidModel.java
@@ -308,6 +_,8 @@
@@ -255,6 +_,8 @@
case BRUSH:
this.rightArm.xRot = this.rightArm.xRot * 0.5F - (float) (Math.PI / 5);
this.rightArm.yRot = 0.0F;
+ default:
+ this.rightArmPose.applyTransform(this, p_102876_, net.minecraft.world.entity.HumanoidArm.RIGHT);
+ p_366231_.applyTransform(this, p_362371_, net.minecraft.world.entity.HumanoidArm.RIGHT);
}
}
@@ -352,6 +_,8 @@
@@ -299,6 +_,8 @@
case BRUSH:
this.leftArm.xRot = this.leftArm.xRot * 0.5F - (float) (Math.PI / 5);
this.leftArm.yRot = 0.0F;
+ default:
+ this.leftArmPose.applyTransform(this, p_102879_, net.minecraft.world.entity.HumanoidArm.LEFT);
+ p_370002_.applyTransform(this, p_363560_, net.minecraft.world.entity.HumanoidArm.LEFT);
}
}
@@ -451,7 +_,7 @@
@@ -377,7 +_,7 @@
}
@OnlyIn(Dist.CLIENT)
@@ -27,7 +27,7 @@
EMPTY(false),
ITEM(false),
BLOCK(false),
@@ -467,10 +_,28 @@
@@ -393,10 +_,28 @@
private ArmPose(final boolean p_102896_) {
this.twoHanded = p_102896_;
@@ -51,8 +51,8 @@
+ throw new IllegalStateException("Enum not extended");
+ }
+
+ public <T extends LivingEntity> void applyTransform(HumanoidModel<T> model, T entity, net.minecraft.world.entity.HumanoidArm arm) {
+ if (this.forgeArmPose != null) this.forgeArmPose.applyTransform(model, entity, arm);
+ public <T extends HumanoidRenderState> void applyTransform(HumanoidModel<T> model, T state, net.minecraft.world.entity.HumanoidArm arm) {
+ if (this.forgeArmPose != null) this.forgeArmPose.applyTransform(model, state, arm);
}
}
}
@@ -1,9 +1,9 @@
--- a/net/minecraft/client/model/geom/LayerDefinitions.java
+++ b/net/minecraft/client/model/geom/LayerDefinitions.java
@@ -329,6 +_,7 @@
WoodType.values().forEach(p_171114_ -> builder.put(ModelLayers.createSignModelName(p_171114_), layerdefinition23));
LayerDefinition layerdefinition24 = HangingSignRenderer.createHangingSignLayer();
WoodType.values().forEach(p_247864_ -> builder.put(ModelLayers.createHangingSignModelName(p_247864_), layerdefinition24));
@@ -464,6 +_,7 @@
builder.put(ModelLayers.createHangingSignModelName(p_374591_, hangingsignrenderer$attachmenttype), layerdefinition55);
}
});
+ net.minecraftforge.client.ForgeHooksClient.loadLayerDefinitions(builder);
ImmutableMap<ModelLayerLocation, LayerDefinition> immutablemap = builder.build();
List<ModelLayerLocation> list = ModelLayers.getKnownLocations().filter(p_171117_ -> !immutablemap.containsKey(p_171117_)).collect(Collectors.toList());
@@ -1,18 +1,24 @@
--- a/net/minecraft/client/model/geom/ModelLayers.java
+++ b/net/minecraft/client/model/geom/ModelLayers.java
@@ -229,11 +_,13 @@
@@ -308,15 +_,18 @@
}
public static ModelLayerLocation createSignModelName(WoodType p_171292_) {
- return createLocation("sign/" + p_171292_.name(), "main");
public static ModelLayerLocation createStandingSignModelName(WoodType p_171292_) {
- return createLocation("sign/standing/" + p_171292_.name(), "main");
+ ResourceLocation location = ResourceLocation.parse(p_171292_.name());
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "sign/" + location.getPath()), "main");
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "sign/standing/" + location.getPath()), "main");
}
public static ModelLayerLocation createHangingSignModelName(WoodType p_252225_) {
- return createLocation("hanging_sign/" + p_252225_.name(), "main");
public static ModelLayerLocation createWallSignModelName(WoodType p_363532_) {
- return createLocation("sign/wall/" + p_363532_.name(), "main");
+ ResourceLocation location = ResourceLocation.parse(p_363532_.name());
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "sign/wall/" + location.getPath()), "main");
}
public static ModelLayerLocation createHangingSignModelName(WoodType p_252225_, HangingSignRenderer.AttachmentType p_378070_) {
- return createLocation("hanging_sign/" + p_252225_.name() + "/" + p_378070_.getSerializedName(), "main");
+ ResourceLocation location = ResourceLocation.parse(p_252225_.name());
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "hanging_sign/" + location.getPath()), "main");
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "hanging_sign/" + location.getPath() + "/" + p_378070_.getSerializedName()), "main");
}
public static Stream<ModelLayerLocation> getKnownLocations() {
@@ -1,14 +1,14 @@
--- a/net/minecraft/client/multiplayer/ClientChunkCache.java
+++ b/net/minecraft/client/multiplayer/ClientChunkCache.java
@@ -61,6 +_,7 @@
@@ -63,6 +_,7 @@
int i = this.storage.getIndex(p_298665_.x, p_298665_.z);
LevelChunk levelchunk = this.storage.getChunk(i);
if (isValidChunk(levelchunk, p_298665_.x, p_298665_.z)) {
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.level.ChunkEvent.Unload(levelchunk));
this.storage.replace(i, levelchunk, null);
this.storage.drop(i, levelchunk);
}
}
@@ -121,6 +_,7 @@
@@ -124,6 +_,7 @@
}
this.level.onChunkLoaded(chunkpos);
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java
+++ b/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java
@@ -149,6 +_,7 @@
@@ -142,6 +_,7 @@
@Override
public void handleCustomPayload(ClientboundCustomPayloadPacket p_298103_) {
Loaded 100 of 944 files, more files were not shown because too many files have changed in this diff. Show more