mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 01:04:24 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ae39c8597 | ||
|
|
dcafb4f633 | ||
|
|
1ea7ce9831 | ||
|
|
674f2efd54 | ||
|
|
02e82c672d | ||
|
|
b25f6e3a7c | ||
|
|
e69b07a54a | ||
|
|
79efe2ac36 | ||
|
|
464483db5b | ||
|
|
f49adb285f | ||
|
|
55862dfd1d | ||
|
|
124b9bd8d3 | ||
|
|
bae3915728 | ||
|
|
b3c2c62c7e | ||
|
|
68698d70c1 | ||
|
|
d55dee9394 | ||
|
|
2d114f2719 | ||
|
|
3e6583af01 | ||
|
|
762f6a7d78 | ||
|
|
3c5a534b7a | ||
|
|
bc62d1693a | ||
|
|
554ead8d4a | ||
|
|
ec5ac91389 | ||
|
|
f63813d929 | ||
|
|
5d4825ac4b | ||
|
|
3024ef7707 | ||
|
|
0d3b488728 | ||
|
|
a01012f20c | ||
|
|
d4e3ef4a22 | ||
|
|
d7293a78dc | ||
|
|
8e4e02e258 | ||
|
|
2f5a6fee48 | ||
|
|
0e74886f8d | ||
|
|
07977ba242 | ||
|
|
a894c244fe | ||
|
|
cf32a799a4 | ||
|
|
0fda1d9393 | ||
|
|
c7f0acbe38 | ||
|
|
9c06c20023 | ||
|
|
041084d1da | ||
|
|
e643d0a11f | ||
|
|
5efb8d3f12 | ||
|
|
70537542d1 | ||
|
|
bd4b059c2b | ||
|
|
e0d2c68c5b | ||
|
|
86d4bda32e | ||
|
|
98b90f26bc | ||
|
|
4e7c471fa3 | ||
|
|
ec6f9fc6e7 | ||
|
|
427fef1d4b | ||
|
|
83594b0b0a | ||
|
|
b76064e57a | ||
|
|
b2bf70c7f1 | ||
|
|
384286a453 | ||
|
|
d93b7db69a | ||
|
|
bdbde4bb0f | ||
|
|
e2a68ad903 | ||
|
|
46cfe50108 | ||
|
|
4b423a3087 | ||
|
|
7d0b07e858 | ||
|
|
40220600b0 | ||
|
|
0c7a0e927c | ||
|
|
60e8157b9a | ||
|
|
b8f5e4553b | ||
|
|
de587eb50a |
No files matched your search
@@ -3,6 +3,7 @@
|
||||
*.patch text eol=lf
|
||||
*.java text eol=lf
|
||||
*.gradle text eol=crlf
|
||||
**/MANIFEST.MF text eol=crlf
|
||||
*.png binary
|
||||
*.gif binary
|
||||
*.exe binary
|
||||
|
||||
@@ -41,3 +41,8 @@ src/*/generated/**/.cache/
|
||||
|
||||
/ForgeRoot.ipr
|
||||
/ForgeRoot.iws
|
||||
|
||||
# APT stuff
|
||||
/*/.gitignore
|
||||
/*/.factorypath
|
||||
/*/.apt_generated/
|
||||
+19
-3
@@ -3,6 +3,7 @@ package net.minecraftforge.forge.tasks
|
||||
import groovy.transform.CompileStatic
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
@@ -12,13 +13,19 @@ abstract class BytecodePredicateFinder extends BytecodeFinder {
|
||||
@Internal
|
||||
abstract Property<Closure<Boolean>> getPredicate()
|
||||
|
||||
private final Set<String> matches = new HashSet<>()
|
||||
private final Map<String, List<String>> matches = new TreeMap<>(Comparator.naturalOrder())
|
||||
|
||||
@Override
|
||||
protected process(ClassNode parent, MethodNode node) {
|
||||
for (final current : node.instructions) {
|
||||
if (predicate.get().call(parent, node, current)) {
|
||||
matches.add(parent.name)
|
||||
var methods = matches.compute(parent.name, { k, v -> v ?: new ArrayList<>() })
|
||||
|
||||
// only add non-synthetic methods
|
||||
if ((node.access & Opcodes.ACC_SYNTHETIC) == 0) {
|
||||
methods.add(node.name + node.desc)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -27,6 +34,15 @@ abstract class BytecodePredicateFinder extends BytecodeFinder {
|
||||
@Internal
|
||||
@Override
|
||||
protected Object getData() {
|
||||
return matches.toSorted(Comparator.naturalOrder()) ?: {throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.')}()
|
||||
var array = new ArrayList<Object>()
|
||||
matches.forEach { c, m ->
|
||||
{
|
||||
array.add(
|
||||
'class': c,
|
||||
'methods': m
|
||||
)
|
||||
}
|
||||
}
|
||||
return array ?: { throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.') }()
|
||||
}
|
||||
}
|
||||
+51
-16
@@ -97,13 +97,13 @@ final String S2S_TOOL = 'net.minecraftforge:Srg2Source:8.1.0:fatjar'
|
||||
configurations {
|
||||
// Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it.
|
||||
bootstrap { transitive = false }
|
||||
installer {
|
||||
installer {
|
||||
extendsFrom(bootstrap)
|
||||
transitive = false
|
||||
transitive = false
|
||||
}
|
||||
installerextra {
|
||||
installerextra {
|
||||
extendsFrom(bootstrap)
|
||||
transitive = false
|
||||
transitive = false
|
||||
}
|
||||
api.extendsFrom(installer)
|
||||
}
|
||||
@@ -117,9 +117,9 @@ dependencies {
|
||||
bootstrap(libs.securemodules) // Has Union file system in it
|
||||
bootstrap(libs.unsafe) // Needed by securemodules
|
||||
bootstrap(libs.bundles.asm) // Needed by securemodules
|
||||
|
||||
implementation(libs.jopt.simple) { version { strictly '5.0.4' } }
|
||||
|
||||
|
||||
implementation(libs.jopt.simple)
|
||||
|
||||
installer(libs.bootstrap)
|
||||
installer(libs.bootstrap.api) // Needed by securemodules
|
||||
installer(libs.accesstransformers)
|
||||
@@ -227,6 +227,31 @@ patcher {
|
||||
'--assetsDir', downloadAssets.output,
|
||||
'--assetIndex', "{asset_index}"
|
||||
}
|
||||
|
||||
forge_client_data {
|
||||
args '--launchTarget', 'forge_dev_client_data',
|
||||
'--mod', 'forge',
|
||||
'--all',
|
||||
'--validate',
|
||||
'--output', rootProject.file('src/main/generated/'),
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--assetsDir', downloadAssets.output,
|
||||
'--assetIndex', "{asset_index}"
|
||||
}
|
||||
|
||||
forge_client_data_test {
|
||||
source sourceSets.test
|
||||
args '--launchTarget', 'forge_dev',
|
||||
'--launchEntry', 'minecraft/net.minecraft.client.data.Main',
|
||||
'--launchData',
|
||||
'--mod', '.+',
|
||||
'--all',
|
||||
'--output', rootProject.file('src/test/generated/'),
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--existing', sourceSets.test.resources.srcDirs[0],
|
||||
'--assetsDir', downloadAssets.output,
|
||||
'--assetIndex', "{asset_index}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +293,11 @@ tasks.register('downloadCrowdin', Download) {
|
||||
tasks.userdevConfig.configure {
|
||||
configurations.installer.allDependencies.forEach {
|
||||
def dep = it.toString()
|
||||
if (it instanceof ProjectDependency)
|
||||
if (it instanceof ProjectDependency)
|
||||
dep = "net.minecraftforge:$it.dependencyProject.name:$it.dependencyProject.version"
|
||||
libraries.add(dep)
|
||||
}
|
||||
|
||||
|
||||
inject = '' // We don't have a userdev sourceset anymore. Empty as a gradle workaround...
|
||||
runs {
|
||||
client {
|
||||
@@ -284,6 +309,13 @@ tasks.userdevConfig.configure {
|
||||
args '--assetsDir', '{assets_root}'
|
||||
}
|
||||
|
||||
clientData {
|
||||
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
||||
args '--launchTarget', "forge_userdev_client_data"
|
||||
args '--assetIndex', '{asset_index}'
|
||||
args '--assetsDir', '{assets_root}'
|
||||
}
|
||||
|
||||
server {
|
||||
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
||||
property 'forge.enableGameTest', 'true'
|
||||
@@ -381,13 +413,13 @@ tasks.register('extractInheritance', ExtractInheritance) {
|
||||
}
|
||||
}
|
||||
tasks.register("findFinalizeSpawnTargets", BytecodePredicateFinder) {
|
||||
jar = createJoinedSRG.output
|
||||
jar = createClientOfficial.output
|
||||
output = rootProject.file('src/main/resources/coremods/finalize_spawn_targets.json')
|
||||
predicate = {
|
||||
parent, node, insn ->
|
||||
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.name == 'finalizeSpawn'
|
||||
&& 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;';
|
||||
}
|
||||
}
|
||||
@@ -493,7 +525,7 @@ tasks.register('serverShimJar', Jar) {
|
||||
from {
|
||||
zipTree(downloadServerShim.output).find { it.name == 'MANIFEST.MF' }
|
||||
}
|
||||
|
||||
|
||||
attributes('Class-Path': configurations.bootstrap.resolvedConfiguration.resolvedArtifacts.collect { "libraries/${Util.getMavenInfoFromDep(it).path}" }.join(' '))
|
||||
}
|
||||
archiveClassifier = 'shim'
|
||||
@@ -586,7 +618,7 @@ tasks.register('checkJarCompatibility', CheckJarCompatibility) {
|
||||
baseLibraries.from(project.tasks.named('createJoinedSRG').flatMap { it.output })
|
||||
|
||||
inputJar = project.tasks.named('reobfJar').flatMap { it.output }
|
||||
|
||||
|
||||
commonLibraries.from(project.configurations.minecraftImplementation)
|
||||
commonLibraries.from(project.configurations.installer)
|
||||
}
|
||||
@@ -607,11 +639,11 @@ tasks.register('launcherJson', LauncherJson).configure {
|
||||
|
||||
tasks.register('installerJson', InstallerJson) {
|
||||
icon = rootProject.file('icon.ico')
|
||||
|
||||
|
||||
// Json to install into the client's launcher
|
||||
dependsOn(launcherJson)
|
||||
input.from(launcherJson.output)
|
||||
|
||||
|
||||
// Download Official Mappings
|
||||
dependsOn(downloadClientMappings, downloadServerMappings)
|
||||
input.from(downloadClientMappings.output, downloadServerMappings.output)
|
||||
@@ -923,6 +955,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/'
|
||||
@@ -1056,7 +1091,7 @@ publishing {
|
||||
license gradleutils.pom.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
@@ -75,3 +75,11 @@ eclipse {
|
||||
// Run when importing the project
|
||||
synchronizationTasks generateResources, copyEclipseSettings, eclipseClasspath, eclipseProject
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
// IntelliJ IDEA does not do this by itself anymore...
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
||||
+25
-6
@@ -2,16 +2,15 @@
|
||||
|
||||
MinecraftForge
|
||||
=============
|
||||
[][Download]
|
||||
[][Download]
|
||||
[][Download] [][Discord] [][Patreon]
|
||||
|
||||
Forge is a free, open-source modding API all of your favourite mods use!
|
||||
|
||||
| Version | Support |
|
||||
|---------| ------------- |
|
||||
| 1.20.x | Active |
|
||||
| 1.19.x | Legacy |
|
||||
| Version | Support |
|
||||
|--------------|-----------------------------|
|
||||
| All versions | [Supported][Support-Policy] |
|
||||
|
||||
* [Download]
|
||||
* [Forum]
|
||||
@@ -31,6 +30,19 @@ 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].
|
||||
@@ -63,8 +75,15 @@ 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,21 +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 java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
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.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -43,20 +34,21 @@ 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));
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -95,54 +87,9 @@ public class ModList {
|
||||
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) {
|
||||
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()));
|
||||
}
|
||||
|
||||
@@ -201,6 +148,10 @@ 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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,6 +14,7 @@ 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;
|
||||
@@ -25,9 +26,66 @@ 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());
|
||||
@@ -37,7 +95,7 @@ public class ConfigFileTypeHandler {
|
||||
onFileNotFound((newfile, configFormat)-> setupConfigFile(c, newfile, configFormat)).
|
||||
writingMode(WritingMode.REPLACE).
|
||||
build();
|
||||
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath.toString());
|
||||
LOGGER.debug(CONFIG, "Built TOML config for {}", configPath);
|
||||
try
|
||||
{
|
||||
configData.load();
|
||||
@@ -46,9 +104,9 @@ public class ConfigFileTypeHandler {
|
||||
{
|
||||
throw new ConfigLoadingException(c, ex);
|
||||
}
|
||||
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());
|
||||
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);
|
||||
return configData;
|
||||
};
|
||||
}
|
||||
@@ -56,9 +114,9 @@ public class ConfigFileTypeHandler {
|
||||
public void unload(Path configBasePath, ModConfig config) {
|
||||
Path configPath = configBasePath.resolve(config.getFileName());
|
||||
try {
|
||||
FileWatcher.defaultInstance().removeWatch(configBasePath.resolve(config.getFileName()));
|
||||
this.getWatcher().removeWatch(configPath);
|
||||
} catch (RuntimeException e) {
|
||||
LOGGER.error("Failed to remove config {} from tracker!", configPath.toString(), e);
|
||||
LOGGER.error("Failed to remove config {} from tracker!", configPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +167,11 @@ public class ConfigFileTypeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConfigFileTypeHandler[" + (type != null ? type : "UNKNOWN") + "]";
|
||||
}
|
||||
|
||||
private record ConfigWatcher(
|
||||
ModConfig modConfig,
|
||||
CommentedFileConfig commentedFileConfig,
|
||||
|
||||
@@ -8,6 +8,9 @@ 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;
|
||||
@@ -52,11 +55,24 @@ 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.TOML;
|
||||
this.configHandler = ConfigFileTypeHandler.get(type);
|
||||
ConfigTracker.INSTANCE.trackConfig(this);
|
||||
}
|
||||
|
||||
|
||||
+19
-4
@@ -604,10 +604,25 @@ public class DisplayWindow implements ImmediateWindowProvider {
|
||||
|
||||
@Override
|
||||
public void updateModuleReads(final ModuleLayer layer) {
|
||||
var fm = layer.findModule("forge").orElseThrow();
|
||||
getClass().getModule().addReads(fm);
|
||||
var clz = FMLLoader.getGameLayer().findModule("forge").map(l->Class.forName(l, "net.minecraftforge.client.loading.ForgeLoadingOverlay")).orElseThrow();
|
||||
loadingOverlay = Arrays.stream(clz.getDeclaredMethods()).filter(m-> Modifier.isStatic(m.getModifiers()) && m.getName().equals("newInstance")).findFirst().orElseThrow();
|
||||
final var FORGE_MODULE = "net.minecraftforge.forge";
|
||||
var forge_module = layer.findModule(FORGE_MODULE).orElse(null);
|
||||
if (forge_module == null)
|
||||
throw new IllegalStateException("Could not find " + FORGE_MODULE + " in " + layer);
|
||||
|
||||
getClass().getModule().addReads(forge_module);
|
||||
|
||||
|
||||
var clz = Class.forName(forge_module, "net.minecraftforge.client.loading.ForgeLoadingOverlay");
|
||||
|
||||
for (var mtd : clz.getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(mtd.getModifiers()) && "newInstance".equals(mtd.getName())) {
|
||||
this.loadingOverlay = mtd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (loadingOverlay == null)
|
||||
throw new IllegalStateException("Could not find static newInstace method in " + clz.getName());
|
||||
}
|
||||
|
||||
public int getFramebufferTextureId() {
|
||||
|
||||
+4
-5
@@ -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,15 +24,14 @@ 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 = memoryBean.getHeapMemoryUsage();
|
||||
final MemoryUsage heapusage = MEMORY_BEAN.getHeapMemoryUsage();
|
||||
memory = (float) heapusage.getUsed() / heapusage.getMax();
|
||||
|
||||
if (!showCPUUsage) {
|
||||
text = "Heap: %d/%d MB (%.1f%%) OffHeap: %d MB".formatted(heapusage.getUsed() >> 20, heapusage.getMax() >> 20, memory * 100.0, memoryBean.getNonHeapMemoryUsage().getUsed() >> 20);
|
||||
text = "Memory: %d/%dMB (%.1f%%)".formatted(heapusage.getUsed() >>> 20, heapusage.getMax() >>> 20, memory * 100f);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +43,7 @@ public class PerformanceInfo {
|
||||
cpuText = "CPU: %.1f%%".formatted(cpuLoad * 100f);
|
||||
}
|
||||
|
||||
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);
|
||||
text = "Memory: %d/%dMB (%.1f%%) %s".formatted(heapusage.getUsed() >>> 20, heapusage.getMax() >>> 20, memory * 100f, cpuText);
|
||||
}
|
||||
|
||||
String text() {
|
||||
|
||||
@@ -84,16 +84,6 @@ public class RenderElement {
|
||||
|
||||
font.generateVerticesForTexts(10, context.scaledHeight() - texts.size() * font.lineSpacing() + font.descent() - 10, bb, texts.toArray(SimpleFont.DisplayText[]::new));
|
||||
}
|
||||
public static RenderElement monag() {
|
||||
return new RenderElement(RenderElement.initializeTexture("monagstudios.png", 45000, 4, (bb, ctx, sz, frame) -> {
|
||||
var size = 256;
|
||||
var x0 = (ctx.width() - 2 * size) / 2;
|
||||
var y0 = 64;
|
||||
QuadHelper.loadQuad(bb, x0, x0+size, y0, y0+size/2f, 0f, 1f, 0f, 0.5f, 0xFFFFFFFF);
|
||||
QuadHelper.loadQuad(bb, x0+size, x0+2*size, y0, y0+size/2f, 0f, 1f, 0.5f, 1f, 0xFFFFFFFF);
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
public static RenderElement mojang(final int textureId, final int frameStart) {
|
||||
return new RenderElement(()->(bb, ctx, frame) -> {
|
||||
|
||||
+21
-1
@@ -5,6 +5,7 @@ plugins {
|
||||
id 'maven-publish'
|
||||
id 'net.minecraftforge.licenser'
|
||||
id 'net.minecraftforge.gradleutils'
|
||||
alias(libs.plugins.apt)
|
||||
}
|
||||
|
||||
apply from: rootProject.file('build_shared.gradle')
|
||||
@@ -36,6 +37,7 @@ dependencies {
|
||||
implementation(libs.terminalconsoleappender)
|
||||
implementation(libs.jimfs)
|
||||
|
||||
// Needed because we have a custom log4j plugin, and they removed package scanning and require a data file to be generated
|
||||
implementation(libs.log4j.core)
|
||||
annotationProcessor(libs.bundles.log4j)
|
||||
|
||||
@@ -85,7 +87,7 @@ publishing {
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
@@ -102,5 +104,23 @@ tasks.register('writeForgeVersionJson') {
|
||||
}
|
||||
|
||||
tasks.named('generateResources').configure {
|
||||
dependsOn('eclipseJdt')
|
||||
dependsOn('eclipseJdtApt')
|
||||
dependsOn('eclipseFactorypath')
|
||||
dependsOn('writeForgeVersionJson')
|
||||
}
|
||||
|
||||
eclipse {
|
||||
classpath {
|
||||
// We need to set the default output directory for the log4j annotation processor
|
||||
// Ideally we'd just set the value, but the eclipse plugin deduplicates the output directories
|
||||
// So we have to do a hacky whenMerged
|
||||
//defaultOutputDir = file('bin/main')
|
||||
file.whenMerged {
|
||||
entries.each { entry ->
|
||||
if (entry.kind == 'output' && entry.hasProperty('path'))
|
||||
entry.path = 'bin/main'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-1
@@ -50,7 +50,14 @@ public class CapabilityTokenSubclass implements ILaunchPluginService {
|
||||
|
||||
@Override
|
||||
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
|
||||
return isEmpty ? NAY : YAY;
|
||||
if (isEmpty)
|
||||
return NAY;
|
||||
|
||||
String internalName = classType.getInternalName();
|
||||
if (internalName.startsWith("net/minecraft/") || internalName.startsWith("com/mojang/"))
|
||||
return NAY;
|
||||
|
||||
return YAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+24
-3
@@ -8,6 +8,7 @@ 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;
|
||||
@@ -35,6 +36,9 @@ 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;
|
||||
|
||||
@@ -47,9 +51,26 @@ public class ObjectHolderDefinalize implements ILaunchPluginService {
|
||||
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
|
||||
|
||||
@Override
|
||||
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
|
||||
{
|
||||
return isEmpty ? NAY : YAY;
|
||||
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;
|
||||
}
|
||||
|
||||
private static boolean hasHolder(List<AnnotationNode> lst) {
|
||||
|
||||
@@ -48,9 +48,15 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
||||
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
|
||||
|
||||
@Override
|
||||
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
|
||||
{
|
||||
return isEmpty ? NAY : YAY;
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,15 +65,14 @@ 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 {
|
||||
|
||||
@@ -140,7 +140,7 @@ public class ImmediateWindowHandler {
|
||||
|
||||
@Override
|
||||
public void updateModuleReads(final ModuleLayer layer) {
|
||||
var fm = layer.findModule("forge");
|
||||
var fm = layer.findModule("net.minecraftforge.forge");
|
||||
if (fm.isPresent()) {
|
||||
getClass().getModule().addReads(fm.get());
|
||||
var clz = fm.map(l -> Class.forName(l, "net.minecraftforge.client.loading.NoVizFallback")).orElseThrow();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,21 @@ public class RuntimeDistCleaner implements ILaunchPluginService {
|
||||
return "runtimedistcleaner";
|
||||
}
|
||||
|
||||
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
|
||||
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/"))
|
||||
return NAY;
|
||||
|
||||
return YAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason) {
|
||||
var changed = false;
|
||||
@@ -198,14 +213,6 @@ public class RuntimeDistCleaner implements ILaunchPluginService {
|
||||
};
|
||||
}
|
||||
|
||||
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
|
||||
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
|
||||
|
||||
@Override
|
||||
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty) {
|
||||
return isEmpty ? NAY : YAY;
|
||||
}
|
||||
|
||||
private static class LambdaGatherer extends MethodVisitor {
|
||||
private static final Handle META_FACTORY = new Handle(Opcodes.H_INVOKESTATIC,
|
||||
"java/lang/invoke/LambdaMetafactory", "metafactory",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -135,9 +138,8 @@ public class UniqueModListBuilder
|
||||
return modFile.getSecureJar().name();
|
||||
}
|
||||
|
||||
return modFile.getModFileInfo().moduleName();
|
||||
return modFile.getModFileInfo().getMods().get(0).getModId();
|
||||
}
|
||||
|
||||
public record UniqueModListData(List<ModFile> modFiles, Map<String, List<ModFile>> modFilesByFirstId) {}
|
||||
|
||||
}
|
||||
@@ -18,9 +18,7 @@ import org.apache.logging.log4j.util.PerformanceSensitive;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper for {@link HighlightConverter} that auto-disables ANSI when the terminal doesn't support it.
|
||||
|
||||
+62
-7
@@ -6,6 +6,7 @@
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
|
||||
import cpw.mods.jarhandling.JarMetadata;
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
import net.minecraftforge.fml.loading.LogMarkers;
|
||||
@@ -22,19 +23,25 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.module.InvalidModuleDescriptorException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract class AbstractModProvider implements IModProvider {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
protected static final String MODS_TOML = "META-INF/mods.toml";
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
protected static final String MODS_TOML = "META-INF/mods.toml";
|
||||
protected static final String MODULE_INFO = "module-info.class";
|
||||
|
||||
protected IModLocator.ModFileOrException createMod(Path path) {
|
||||
return createMod(path, false);
|
||||
@@ -48,10 +55,12 @@ public abstract class AbstractModProvider implements IModProvider {
|
||||
@Nullable
|
||||
protected IModLocator.ModFileOrException createMod(Path path, boolean ignoreUnknown, String defaultType) {
|
||||
var mjm = new ModJarMetadata();
|
||||
var sj = SecureJar.from(
|
||||
jar -> jar.moduleDataProvider().findFile(MODS_TOML).isPresent() ? mjm : JarMetadata.from(jar, path),
|
||||
path
|
||||
);
|
||||
SecureJar sj = null;
|
||||
try {
|
||||
sj = SecureJar.from(jar -> loadMetaFromJar(jar, mjm), path);
|
||||
} catch (Throwable t) {
|
||||
return new IModLocator.ModFileOrException(null, new ModFileLoadingException("Failed to create secure jar for \"" + path + "\" - " + t.getMessage()));
|
||||
}
|
||||
|
||||
IModFile mod;
|
||||
var type = sj.moduleDataProvider().getManifest().getMainAttributes().getValue(ModFile.TYPE);
|
||||
@@ -61,6 +70,8 @@ public abstract class AbstractModProvider implements IModProvider {
|
||||
if (sj.moduleDataProvider().findFile(MODS_TOML).isPresent()) {
|
||||
LOGGER.debug(LogMarkers.SCAN, "Found {} mod of type {}: {}", MODS_TOML, type, path);
|
||||
mod = new ModFile(sj, this, ModFileParser::modsTomlParser);
|
||||
// ModJarMetadata is only used when loading mods.toml mods as ModJarMetadata
|
||||
mjm.setModFile(mod);
|
||||
if (mod.getModFileInfo().getFileProperties().containsKey(ModFileInfo.NOT_A_FORGE_MOD_PROP)) {
|
||||
LOGGER.error(LogMarkers.SCAN, "Unable to load file \"{}\" because its mods.toml is requesting an invalid javafml loaderVersion (use \"*\" if you want to allow all versions) and is missing a forge modId dependency declaration (see the sample mods.toml in the MDK).", path);
|
||||
return new IModLocator.ModFileOrException(null, new ModFileLoadingException("File \"%s\" is not a Forge mod and cannot be loaded. Look for a Forge version of this mod or consider alternative mods.".formatted(mod.getFileName())));
|
||||
@@ -73,10 +84,54 @@ public abstract class AbstractModProvider implements IModProvider {
|
||||
} else
|
||||
return new IModLocator.ModFileOrException(null, new ModFileLoadingException("Invalid mod file found " + path));
|
||||
|
||||
mjm.setModFile(mod);
|
||||
return new IModLocator.ModFileOrException(mod, null);
|
||||
}
|
||||
|
||||
private static JarMetadata loadMetaFromJar(SecureJar jar, ModJarMetadata mjm) {
|
||||
var info = jar.moduleDataProvider().open(MODULE_INFO).orElse(null);
|
||||
if (info != null) {
|
||||
try {
|
||||
var desc = ModuleDescriptor.read(info, jar::getPackages);
|
||||
var all = new HashSet<>(jar.getPackages());
|
||||
all.removeAll(desc.packages());
|
||||
if (!all.isEmpty()) {
|
||||
var missing = all.stream().sorted().collect(Collectors.joining(", "));
|
||||
LOGGER.error("Invalid module-info, missing packages " + missing);
|
||||
throw new ModFileLoadingException("Invalid module-info, missing packages " + missing);
|
||||
} else {
|
||||
return new JarMetadata() {
|
||||
@Override
|
||||
public String name() {
|
||||
return desc.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String version() {
|
||||
return desc.version().map(Version::toString).or(desc::rawVersion).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleDescriptor descriptor() {
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (InvalidModuleDescriptorException | IOException e) {
|
||||
LOGGER.error("Failed to parse " + jar.getPrimaryPath() + " module-info", e);
|
||||
throw new ModFileLoadingException("Invalid module-info: " + e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
info.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (jar.moduleDataProvider().findFile(MODS_TOML).isEmpty())
|
||||
return JarMetadata.from(jar, jar.getPrimaryPath());
|
||||
|
||||
return mjm;
|
||||
}
|
||||
|
||||
protected IModFileInfo manifestParser(final IModFile mod) {
|
||||
var mf = mod.getSecureJar().moduleDataProvider().getManifest().getMainAttributes();
|
||||
var license = mf.getValue("LICENSE");
|
||||
|
||||
+2
-4
@@ -22,13 +22,11 @@ public final class MinecraftLocator extends AbstractModProvider implements IModL
|
||||
@Override
|
||||
public List<IModLocator.ModFileOrException> scanMods() {
|
||||
var minecraft = FMLLoader.getLaunchHandler().getMinecraftPaths();
|
||||
var paths = minecraft.toArray(Path[]::new);
|
||||
|
||||
// Minecraft itself.
|
||||
var meta = new ModJarMetadata();
|
||||
var mcjar = SecureJar.from(
|
||||
jar -> meta,
|
||||
minecraft.toArray(Path[]::new)
|
||||
);
|
||||
var mcjar = SecureJar.from(jar -> meta, paths);
|
||||
var mc = ModFileFactory.FACTORY.build(mcjar, this, MinecraftLocator::buildMinecraftTOML);
|
||||
meta.setModFile(mc);
|
||||
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
+1
-1
@@ -259,7 +259,7 @@ public class ModFileInfo implements IModFileInfo, IConfigurable {
|
||||
|
||||
@Override
|
||||
public String moduleName() {
|
||||
return getMods().get(0).getModId();
|
||||
return this.modFile.getSecureJar().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+31
-16
@@ -9,49 +9,64 @@ import cpw.mods.jarhandling.JarMetadata;
|
||||
import net.minecraftforge.forgespi.locating.IModFile;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class ModJarMetadata implements JarMetadata {
|
||||
private static final String AUTOMATIC_MODULE_NAME = "Automatic-Module-Name";
|
||||
private IModFile modFile;
|
||||
private String name;
|
||||
private String version;
|
||||
private ModuleDescriptor descriptor;
|
||||
|
||||
ModJarMetadata() {
|
||||
}
|
||||
ModJarMetadata() { }
|
||||
|
||||
public void setModFile(IModFile file) {
|
||||
this.modFile = file;
|
||||
var mods = this.modFile.getModFileInfo().getMods();
|
||||
|
||||
if (!mods.isEmpty()) {
|
||||
var main = mods.get(0);
|
||||
this.name = main.getModId();
|
||||
this.version = main.getVersion().toString();
|
||||
}
|
||||
|
||||
var jar = file.getSecureJar();
|
||||
var aname = jar.moduleDataProvider().getManifest().getMainAttributes().getValue(AUTOMATIC_MODULE_NAME);
|
||||
if (aname != null)
|
||||
this.name = aname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return modFile.getModFileInfo().moduleName();
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String version() {
|
||||
return modFile.getModFileInfo().versionString();
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleDescriptor descriptor() {
|
||||
if (descriptor != null) return descriptor;
|
||||
if (descriptor != null)
|
||||
return descriptor;
|
||||
|
||||
var bld = ModuleDescriptor.newAutomaticModule(name())
|
||||
.version(version())
|
||||
.packages(modFile.getSecureJar().getPackages());
|
||||
modFile.getSecureJar().getProviders().stream()
|
||||
.filter(p -> !p.providers().isEmpty())
|
||||
.forEach(p -> bld.provides(p.serviceName(), p.providers()));
|
||||
modFile.getModFileInfo().usesServices().forEach(bld::uses);
|
||||
.version(version())
|
||||
.packages(modFile.getSecureJar().getPackages());
|
||||
|
||||
for (var provider : modFile.getSecureJar().getProviders()) {
|
||||
if (provider.providers().isEmpty())
|
||||
continue;
|
||||
|
||||
bld.provides(provider.serviceName(), provider.providers());
|
||||
}
|
||||
|
||||
descriptor = bld.build();
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public IModFile modFile() {
|
||||
return modFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
|
||||
@@ -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, 0);
|
||||
cr.accept(mcv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
mcv.buildData(result.getClasses(), result.getAnnotations());
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
// mark path bad
|
||||
|
||||
@@ -81,6 +81,10 @@ class ArgumentList {
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public boolean has(String key) {
|
||||
return this.values.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean hasValue(String key) {
|
||||
return getOrDefault(key, null) != null;
|
||||
}
|
||||
|
||||
+30
-4
@@ -22,6 +22,10 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
super(type, prefix);
|
||||
}
|
||||
|
||||
protected CommonDevLaunchHandler(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override public String getNaming() { return "mcp"; }
|
||||
@Override public boolean isProduction() { return false; }
|
||||
|
||||
@@ -29,13 +33,35 @@ abstract class CommonDevLaunchHandler extends CommonLaunchHandler {
|
||||
protected String[] preLaunch(String[] arguments, ModuleLayer layer) {
|
||||
super.preLaunch(arguments, layer);
|
||||
|
||||
var args = ArgumentList.from(arguments);
|
||||
|
||||
if (this.module == null) {
|
||||
var entry = args.get("launchEntry");
|
||||
if (entry == null)
|
||||
throw new IllegalArgumentException("When using " + this.name() + " launch target you must specify a --launchEntry argument");
|
||||
|
||||
args.remove("launchEntry");
|
||||
|
||||
int idx = entry.indexOf('/');
|
||||
if (idx == -1) {
|
||||
this.module = "minecraft";
|
||||
this.main = entry;
|
||||
} else {
|
||||
this.module = entry.substring(0, idx);
|
||||
this.main = entry.substring(idx + 1);
|
||||
}
|
||||
|
||||
if (args.has("launchData")) {
|
||||
args.remove("launchData");
|
||||
this.isData = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (getDist().isDedicatedServer())
|
||||
return arguments;
|
||||
return args.getArguments();
|
||||
|
||||
if (isData())
|
||||
return arguments;
|
||||
|
||||
var args = ArgumentList.from(arguments);
|
||||
return args.getArguments();
|
||||
|
||||
String username = args.get("username");
|
||||
if (username != null) { // Replace '#' placeholders with random numbers
|
||||
|
||||
+20
-9
@@ -29,17 +29,27 @@ import java.util.List;
|
||||
public abstract class CommonLaunchHandler implements ILaunchHandlerService {
|
||||
protected static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
protected final LaunchType type;
|
||||
private final String prefix;
|
||||
private final String name;
|
||||
protected Dist dist = Dist.CLIENT;
|
||||
protected boolean isData = false;
|
||||
protected String module;
|
||||
protected String main;
|
||||
|
||||
protected CommonLaunchHandler(LaunchType type, String prefix) {
|
||||
this.type = type;
|
||||
this.prefix = prefix;
|
||||
this(prefix + type.name());
|
||||
this.dist = type.dist();
|
||||
this.isData = type.data();
|
||||
this.module = type.module();
|
||||
this.main = type.main();
|
||||
}
|
||||
|
||||
@Override public String name() { return this.prefix + this.type.name(); }
|
||||
public Dist getDist() { return this.type.dist(); }
|
||||
public boolean isData() { return this.type.data(); }
|
||||
protected CommonLaunchHandler(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override public String name() { return this.name; }
|
||||
public Dist getDist() { return this.dist; }
|
||||
public boolean isData() { return this.isData; }
|
||||
public boolean isProduction() { return false; }
|
||||
public abstract String getNaming();
|
||||
|
||||
@@ -66,14 +76,15 @@ public abstract class CommonLaunchHandler implements ILaunchHandlerService {
|
||||
}
|
||||
|
||||
protected ServiceRunner makeService(final String[] arguments, final ModuleLayer gameLayer) {
|
||||
return () -> runTarget(this.type.module(), this.type.main(), arguments, gameLayer);
|
||||
return () -> runTarget(this.module, this.main, arguments, gameLayer);
|
||||
}
|
||||
|
||||
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", "forge", "net.minecraftforge.gametest.GameTestMain", 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);
|
||||
|
||||
protected void runTarget(String module, String target, final String[] arguments, final ModuleLayer layer) throws Throwable {
|
||||
var mod = layer.findModule(module).orElse(null);
|
||||
|
||||
+18
-4
@@ -14,12 +14,14 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
super(type, "forge_dev_");
|
||||
}
|
||||
|
||||
private ForgeDevLaunchHandler(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftPaths() {
|
||||
|
||||
// The extra jar is on the classpath, so try and pull it out of the legacy classpath
|
||||
var legacyCP = findClassPath();
|
||||
var extra = findJarOnClasspath(legacyCP, "client-extra");
|
||||
// The client extra jar is on the classpath we can try locating it using the .mcassetsroot which vanilla uses for loading data
|
||||
var extra = getPathFromResource("assets/.mcassetsroot");
|
||||
// Minecraft is an exploded directory, so find it.
|
||||
var minecraft = getPathFromResource("net/minecraft/client/Minecraft.class");
|
||||
var forge = getPathFromResource("net/minecraftforge/common/MinecraftForge.class");
|
||||
@@ -39,6 +41,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);
|
||||
@@ -56,4 +64,10 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
|
||||
super(SERVER_GAMETEST);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Custom extends ForgeDevLaunchHandler {
|
||||
public Custom() {
|
||||
super("forge_dev");
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-12
@@ -91,23 +91,24 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
|
||||
// First lets find all class files, that have the @Mod annotation and map packages to modids.
|
||||
var packages = findTestModPackages(path);
|
||||
for (var entry : packages.entrySet()) {
|
||||
var pkg = entry.getKey();
|
||||
var pkg = entry.getKey() + '/';
|
||||
var modids = entry.getValue();
|
||||
|
||||
// Find resource directories for every mod in this group
|
||||
var resourcePaths = new LinkedHashSet<Path>();
|
||||
var paths = new LinkedHashSet<Path>();
|
||||
for (var modid : modids) {
|
||||
var rsc = path.resolve(modid);
|
||||
if (Files.exists(rsc))
|
||||
resourcePaths.add(rsc);
|
||||
paths.add(rsc);
|
||||
}
|
||||
|
||||
var root = memory.getPath(modids.iterator().next()); // use the first modid as our root
|
||||
buildModsToml(resourcePaths, modids, root);
|
||||
buildPackMeta(resourcePaths, root);
|
||||
buildModsToml(paths, modids, root);
|
||||
buildPackMeta(paths, root);
|
||||
moveModuleInfo(paths, root);
|
||||
|
||||
if (Files.exists(root))
|
||||
resourcePaths.add(root);
|
||||
paths.add(root);
|
||||
|
||||
// We want just the class files from the root of the input paths. So make a new union with a filter.
|
||||
var classes = UnionHelper.newFileSystem(
|
||||
@@ -121,14 +122,10 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
|
||||
}, new Path[] { path }
|
||||
);
|
||||
|
||||
// And we want the resources, and none of the classes, just in case things get kinda fucky and somehow a package overlaps a sub package {shading?}
|
||||
var resources = UnionHelper.newFileSystem((name, base) -> !name.endsWith(".class"), resourcePaths.toArray(Path[]::new));
|
||||
paths.addFirst(classes.getRootDirectories().iterator().next());
|
||||
|
||||
// Union of unions, Yay!
|
||||
var union = UnionHelper.newFileSystem(null, new Path[] {
|
||||
classes.getRootDirectories().iterator().next(),
|
||||
resources.getRootDirectories().iterator().next()
|
||||
});
|
||||
var union = UnionHelper.newFileSystem(null, paths.stream().toArray(Path[]::new));
|
||||
mod.add(union.getRootDirectories().iterator().next());
|
||||
}
|
||||
|
||||
@@ -274,6 +271,25 @@ public final class ForgeDevLocator extends AbstractModProvider implements IModLo
|
||||
}
|
||||
}
|
||||
|
||||
private static void moveModuleInfo(Set<Path> paths, Path root) {
|
||||
var existing = paths.stream()
|
||||
.map(p -> p.resolve("module-info.dat"))
|
||||
.filter(Files::exists)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (existing == null)
|
||||
return;
|
||||
|
||||
var target = root.resolve("module-info.class");
|
||||
try {
|
||||
Files.createDirectories(target.getParent());
|
||||
Files.copy(existing, target);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to copy module-info.dat to memory: " + target, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends Throwable, R> R sneak(Throwable e) throws E {
|
||||
throw (E)e;
|
||||
|
||||
+17
-4
@@ -8,17 +8,18 @@ package net.minecraftforge.fml.loading.targets;
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.BiPredicate;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
|
||||
@ApiStatus.Internal
|
||||
sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
private ForgeUserdevLaunchHandler(LaunchType type) {
|
||||
super(type, "forge_userdev_");
|
||||
}
|
||||
|
||||
private ForgeUserdevLaunchHandler(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftPaths() {
|
||||
var legacyCP = findClassPath();
|
||||
@@ -26,7 +27,7 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
|
||||
// Minecraft is extra jar {resources} + forge jar {patches}
|
||||
// The MC extra and forge jars are on the classpath, so try and pull them out
|
||||
var extra = findJarOnClasspath(legacyCP, "client-extra");
|
||||
var extra = findJarOnClasspath(legacyCP, "client-extra"); // This should be "client-" + vers.mcAndMCPVersion() + "-extra" but FG6 qwerks
|
||||
var forge = findJarOnClasspath(legacyCP, "forge-" + vers.mcAndForgeVersion());
|
||||
// We need to filter the forge jar to just MC code
|
||||
var minecraft = CommonDevLaunchHandler.getMinecraftOnly(extra, forge);
|
||||
@@ -39,6 +40,12 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ClientData extends ForgeUserdevLaunchHandler {
|
||||
public ClientData() {
|
||||
super(CLIENT_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Data extends ForgeUserdevLaunchHandler {
|
||||
public Data() {
|
||||
super(DATA);
|
||||
@@ -56,4 +63,10 @@ sealed abstract class ForgeUserdevLaunchHandler extends CommonDevLaunchHandler {
|
||||
super(SERVER_GAMETEST);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Custom extends ForgeUserdevLaunchHandler {
|
||||
public Custom() {
|
||||
super("forge_userdev");
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -4,12 +4,16 @@ net.minecraftforge.fml.loading.targets.ForgeProdLaunchHandler$Server
|
||||
|
||||
# Mod Developers
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Client
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$ClientData
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Custom
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Data
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$Server
|
||||
net.minecraftforge.fml.loading.targets.ForgeUserdevLaunchHandler$ServerGameTest
|
||||
|
||||
#Working on Forge itself
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Client
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$ClientData
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Custom
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Data
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$Server
|
||||
net.minecraftforge.fml.loading.targets.ForgeDevLaunchHandler$ServerGameTest
|
||||
@@ -4,7 +4,7 @@
|
||||
SPDX-License-Identifier: LGPL-2.1-only
|
||||
-->
|
||||
|
||||
<Configuration status="warn" packages="net.minecrell.terminalconsole,net.minecrell.terminalconsole.util,com.mojang.util,cpw.mods.modlauncher.log,net.minecraftforge.fml.loading.log4j" shutdownHook="disable">
|
||||
<Configuration status="warn" shutdownHook="disable">
|
||||
<filters>
|
||||
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="${sys:forge.logging.marker.networking:-DENY}" onMismatch="NEUTRAL"/>
|
||||
|
||||
+3
-3
@@ -5,11 +5,11 @@ org.gradle.daemon=false
|
||||
org.gradle.parallel=true
|
||||
|
||||
JAVA_VERSION=21
|
||||
MC_VERSION=1.21.3
|
||||
MC_VERSION=1.21.4
|
||||
MC_NEXT_VERSION=1.22
|
||||
MCP_VERSION=20241025.112443
|
||||
MCP_VERSION=20241203.143248
|
||||
MAPPING_CHANNEL=official
|
||||
MAPPING_VERSION=1.21.3
|
||||
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
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+2
-1
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -83,7 +83,8 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# 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
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -130,10 +131,13 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
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.
|
||||
|
||||
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.
|
||||
@@ -141,7 +145,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=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -149,7 +153,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=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -198,11 +202,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, 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.
|
||||
# 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.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
||||
Vendored
+10
-10
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
goto fail
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ dependencies {
|
||||
compileOnly(libs.nulls)
|
||||
implementation(project(':fmlloader'))
|
||||
implementation(project(':fmlcore'))
|
||||
implementation(libs.unsafe)
|
||||
implementation(libs.securemodules)
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -57,7 +59,7 @@ publishing {
|
||||
license PomUtils.Licenses.LGPLv2_1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
maven gradleutils.publishingForgeMaven
|
||||
}
|
||||
|
||||
+86
-3
@@ -13,18 +13,24 @@ 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;
|
||||
import net.minecraftforge.unsafe.UnsafeHacks;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
|
||||
import cpw.mods.jarhandling.SecureJar;
|
||||
|
||||
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 {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
@@ -41,20 +47,87 @@ 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();
|
||||
var module = gameLayer.findModule(moduleName)
|
||||
.orElseThrow(() -> new IllegalStateException("Failed to find " + moduleName + " in " + gameLayer));
|
||||
|
||||
openModules(gameLayer, module, info.getOwningFile().getFile().getSecureJar());
|
||||
|
||||
modClass = Class.forName(module, className);
|
||||
LOGGER.trace(LOADING,"Loaded modclass {} with {}", modClass.getName(), modClass.getClassLoader());
|
||||
LOGGER.debug(LOADING,"Loaded modclass {}/{} with {}", modClass.getModule().getName(), modClass.getName(), modClass.getClassLoader());
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error(LOADING, "Failed to load class {}", className, e);
|
||||
throw new ModLoadingException(info, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadmodclass", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Reads the Add-Exports and Add-Opens attributes (see note) from a mod file and
|
||||
* attempts to apply them. This differers from the JEP in two significant ways:
|
||||
* 1) Instead of opening things to ALL-UNNAMED it instead only opens to the
|
||||
* mod's module itself. Because I don't want other mods accidently relying
|
||||
* on transitive behavior
|
||||
* 2) It is read from all mods not just the executable jars.
|
||||
*
|
||||
* From <a href = "https://openjdk.org/jeps/261">JEP 261: Module System</a>
|
||||
*
|
||||
* Two new JDK-specific JAR-file manifest attributes are defined to correspond
|
||||
* to the --add-exports and --add-opens command-line options:
|
||||
* Add-Exports: <module>/<package>( <module>/<package>)*
|
||||
* Add-Opens: <module>/<package>( <module>/<package>)*
|
||||
*
|
||||
* The value of each attribute is a space-separated list of slash-separated
|
||||
* module-name/package-name pairs. A >module</>package< pair in
|
||||
* the value of an Add-Exports attribute has the same meaning as the
|
||||
* command-line option --add-exports >module</>package<=ALL-UNNAMED.
|
||||
*
|
||||
* A >module</>package< pair in the value of an Add-Opens attribute has the
|
||||
* same meaning as the command-line option --add-opens >module</>package<=ALL-UNNAMED.
|
||||
*
|
||||
* Each attribute can occur at most once, in the main section of a MANIFEST.MF file.
|
||||
* A particular pair can be listed more than once. If a specified module was not
|
||||
* resolved, or if a specified package does not exist, then the corresponding pair
|
||||
* is ignored.
|
||||
*/
|
||||
private static void openModules(ModuleLayer layer, Module self, SecureJar jar) throws NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
|
||||
var manifest = jar.moduleDataProvider().getManifest().getMainAttributes();
|
||||
addOpenOrExports(layer, self, true, manifest);
|
||||
addOpenOrExports(layer, self, false, manifest);
|
||||
}
|
||||
|
||||
private static void addOpenOrExports(ModuleLayer layer, Module self, boolean open, Attributes attrs) throws NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
|
||||
var key = open ? "Add-Opens" : "Add-Exports";
|
||||
var entry = attrs.getValue(key);
|
||||
if (entry == null)
|
||||
return;
|
||||
|
||||
for (var pair : entry.split(" ")) {
|
||||
var pts = pair.trim().split("/");
|
||||
if (pts.length == 2) {
|
||||
var target = layer.findModule(pts[0]).orElse(null);
|
||||
if (target == null || !target.getDescriptor().packages().contains(pts[1]))
|
||||
continue;
|
||||
addOpenOrExport(target, pts[1], self, open);
|
||||
} else {
|
||||
LOGGER.warn(LOADING, "Invalid {} entry in {}: {}", key, self.getName(), pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Method implAddExportsOrOpens;
|
||||
private static void addOpenOrExport(Module target, String pkg, Module reader, boolean open) throws NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
|
||||
if (implAddExportsOrOpens == null) {
|
||||
implAddExportsOrOpens = Module.class.getDeclaredMethod("implAddExportsOrOpens", String.class, Module.class, boolean.class, boolean.class);
|
||||
UnsafeHacks.setAccessible(implAddExportsOrOpens);
|
||||
}
|
||||
|
||||
LOGGER.info(LOADING, "{} {}/{} to {}", open ? "Opening" : "Exporting", target.getName(), pkg, reader.getName());
|
||||
implAddExportsOrOpens.invoke(target, pkg, reader, open, /*syncVM*/true);
|
||||
}
|
||||
|
||||
private static void onEventFailed(IEventBus iEventBus, Event event, IEventListener[] iEventListeners, int i, Throwable throwable) {
|
||||
LOGGER.error(new EventBusErrorMessage(event, i, iEventListeners, throwable));
|
||||
}
|
||||
@@ -115,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() + "]";
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -141,9 +141,6 @@ 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.
|
||||
@@ -197,6 +194,10 @@ 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
|
||||
|
||||
@@ -11,18 +11,11 @@
|
||||
}
|
||||
|
||||
this.setFilterMode(9728, true);
|
||||
@@ -106,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();
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
--- a/com/mojang/blaze3d/platform/GlStateManager.java
|
||||
+++ b/com/mojang/blaze3d/platform/GlStateManager.java
|
||||
@@ -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
|
||||
@@ -88,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;
|
||||
@@ -100,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();
|
||||
@@ -267,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/net/minecraft/Util.java
|
||||
+++ b/net/minecraft/Util.java
|
||||
@@ -264,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/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,6 +1,6 @@
|
||||
--- a/net/minecraft/client/Minecraft.java
|
||||
+++ b/net/minecraft/client/Minecraft.java
|
||||
@@ -253,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;
|
||||
@@ -433,7 +_,6 @@
|
||||
@@ -428,7 +_,6 @@
|
||||
}
|
||||
}, Util.nonCriticalIoPool());
|
||||
LOGGER.info("Setting user: {}", this.user.getName());
|
||||
@@ -17,7 +17,7 @@
|
||||
this.demo = p_91084_.game.demo;
|
||||
this.allowsMultiplayer = !p_91084_.game.disableMultiplayer;
|
||||
this.allowsChat = !p_91084_.game.disableChat;
|
||||
@@ -480,15 +_,15 @@
|
||||
@@ -475,15 +_,15 @@
|
||||
LOGGER.error("Couldn't set icon", (Throwable)ioexception);
|
||||
}
|
||||
|
||||
@@ -35,15 +35,15 @@
|
||||
this.resourcePackRepository.reload();
|
||||
this.options.loadSelectedResourcePacks(this.resourcePackRepository);
|
||||
this.languageManager = new LanguageManager(this.options.languageCode, p_340763_ -> {
|
||||
@@ -562,6 +_,7 @@
|
||||
);
|
||||
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);
|
||||
@@ -577,6 +_,9 @@
|
||||
@@ -576,6 +_,9 @@
|
||||
this.resourceManager.registerReloadListener(this.gpuWarnlistManager);
|
||||
this.resourceManager.registerReloadListener(this.regionalCompliancies);
|
||||
this.gui = new Gui(this);
|
||||
@@ -53,7 +53,7 @@
|
||||
this.debugRenderer = new DebugRenderer(this);
|
||||
RealmsClient realmsclient = RealmsClient.create(this);
|
||||
this.realmsDataFetcher = new RealmsDataFetcher(realmsclient);
|
||||
@@ -600,6 +_,7 @@
|
||||
@@ -599,6 +_,7 @@
|
||||
this.options.fullscreen().set(this.window.isFullscreen());
|
||||
}
|
||||
|
||||
@@ -145,6 +145,14 @@
|
||||
this.screen = p_91153_;
|
||||
if (this.screen != null) {
|
||||
this.screen.added();
|
||||
@@ -1146,6 +_,7 @@
|
||||
|
||||
FreeTypeUtil.destroy();
|
||||
Util.shutdownExecutors();
|
||||
+ net.minecraftforge.fml.config.ConfigTracker.INSTANCE.forceUnload();
|
||||
} catch (Throwable throwable) {
|
||||
LOGGER.error("Shutdown failure!", throwable);
|
||||
throw throwable;
|
||||
@@ -1215,9 +_,11 @@
|
||||
this.mouseHandler.handleAccumulatedMovement();
|
||||
profilerfiller.pop();
|
||||
@@ -157,7 +165,7 @@
|
||||
}
|
||||
|
||||
profilerfiller.push("blit");
|
||||
@@ -1339,10 +_,12 @@
|
||||
@@ -1342,10 +_,12 @@
|
||||
this.window.setGuiScale((double)i);
|
||||
if (this.screen != null) {
|
||||
this.screen.resize(this, this.window.getGuiScaledWidth(), this.window.getGuiScaledHeight());
|
||||
@@ -170,7 +178,7 @@
|
||||
this.gameRenderer.resize(this.window.getWidth(), this.window.getHeight());
|
||||
this.mouseHandler.setIgnoreFirstMove();
|
||||
}
|
||||
@@ -1483,6 +_,7 @@
|
||||
@@ -1486,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@@ -178,7 +186,7 @@
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
@@ -1511,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();
|
||||
@@ -200,7 +208,7 @@
|
||||
this.player.swing(InteractionHand.MAIN_HAND);
|
||||
}
|
||||
}
|
||||
@@ -1542,6 +_,8 @@
|
||||
@@ -1545,6 +_,8 @@
|
||||
return false;
|
||||
} else {
|
||||
boolean flag = false;
|
||||
@@ -209,7 +217,7 @@
|
||||
switch (this.hitResult.getType()) {
|
||||
case ENTITY:
|
||||
this.gameMode.attack(this.player, ((EntityHitResult)this.hitResult).getEntity());
|
||||
@@ -1549,7 +_,7 @@
|
||||
@@ -1552,7 +_,7 @@
|
||||
case BLOCK:
|
||||
BlockHitResult blockhitresult = (BlockHitResult)this.hitResult;
|
||||
BlockPos blockpos = blockhitresult.getBlockPos();
|
||||
@@ -218,7 +226,7 @@
|
||||
this.gameMode.startDestroyBlock(blockpos, blockhitresult.getDirection());
|
||||
if (this.level.getBlockState(blockpos).isAir()) {
|
||||
flag = true;
|
||||
@@ -1562,8 +_,10 @@
|
||||
@@ -1565,8 +_,10 @@
|
||||
}
|
||||
|
||||
this.player.resetAttackStrengthTicker();
|
||||
@@ -229,7 +237,7 @@
|
||||
this.player.swing(InteractionHand.MAIN_HAND);
|
||||
return flag;
|
||||
}
|
||||
@@ -1579,6 +_,12 @@
|
||||
@@ -1582,6 +_,12 @@
|
||||
}
|
||||
|
||||
for (InteractionHand interactionhand : InteractionHand.values()) {
|
||||
@@ -242,7 +250,7 @@
|
||||
ItemStack itemstack = this.player.getItemInHand(interactionhand);
|
||||
if (!itemstack.isItemEnabled(this.level.enabledFeatures())) {
|
||||
return;
|
||||
@@ -1599,7 +_,7 @@
|
||||
@@ -1602,7 +_,7 @@
|
||||
}
|
||||
|
||||
if (interactionresult instanceof InteractionResult.Success interactionresult$success2) {
|
||||
@@ -251,7 +259,7 @@
|
||||
this.player.swing(interactionhand);
|
||||
}
|
||||
|
||||
@@ -1611,7 +_,7 @@
|
||||
@@ -1614,7 +_,7 @@
|
||||
int i = itemstack.getCount();
|
||||
InteractionResult interactionresult1 = this.gameMode.useItemOn(this.player, interactionhand, blockhitresult);
|
||||
if (interactionresult1 instanceof InteractionResult.Success interactionresult$success) {
|
||||
@@ -260,7 +268,7 @@
|
||||
this.player.swing(interactionhand);
|
||||
if (!itemstack.isEmpty() && (itemstack.getCount() != i || this.gameMode.hasInfiniteItems())) {
|
||||
this.gameRenderer.itemInHandRenderer.itemUsed(interactionhand);
|
||||
@@ -1627,6 +_,9 @@
|
||||
@@ -1630,6 +_,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +278,7 @@
|
||||
if (!itemstack.isEmpty()
|
||||
&& this.gameMode.useItem(this.player, interactionhand) instanceof InteractionResult.Success interactionresult$success1) {
|
||||
if (interactionresult$success1.swingSource() == InteractionResult.SwingSource.CLIENT) {
|
||||
@@ -1656,6 +_,8 @@
|
||||
@@ -1659,6 +_,8 @@
|
||||
}
|
||||
|
||||
ProfilerFiller profilerfiller = Profiler.get();
|
||||
@@ -279,7 +287,7 @@
|
||||
profilerfiller.push("gui");
|
||||
this.chatListener.tick();
|
||||
this.gui.tick(this.pause);
|
||||
@@ -1745,6 +_,7 @@
|
||||
@@ -1748,6 +_,7 @@
|
||||
|
||||
this.tutorial.tick();
|
||||
|
||||
@@ -287,7 +295,7 @@
|
||||
try {
|
||||
this.level.tick(() -> true);
|
||||
} catch (Throwable throwable1) {
|
||||
@@ -1758,6 +_,7 @@
|
||||
@@ -1761,6 +_,7 @@
|
||||
|
||||
throw new ReportedException(crashreport1);
|
||||
}
|
||||
@@ -295,7 +303,7 @@
|
||||
}
|
||||
|
||||
profilerfiller.popPush("animateTick");
|
||||
@@ -1782,6 +_,7 @@
|
||||
@@ -1785,6 +_,7 @@
|
||||
profilerfiller.popPush("keyboard");
|
||||
this.keyboardHandler.tick();
|
||||
profilerfiller.pop();
|
||||
@@ -303,7 +311,7 @@
|
||||
}
|
||||
|
||||
private boolean isLevelRunningNormally() {
|
||||
@@ -1983,6 +_,7 @@
|
||||
@@ -1986,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void setLevel(ClientLevel p_91157_, ReceivingLevelScreen.Reason p_335893_) {
|
||||
@@ -311,7 +319,7 @@
|
||||
this.updateScreenAndTick(new ReceivingLevelScreen(() -> false, p_335893_));
|
||||
this.level = p_91157_;
|
||||
this.updateLevelInEngines(p_91157_);
|
||||
@@ -2020,6 +_,7 @@
|
||||
@@ -2023,6 +_,7 @@
|
||||
IntegratedServer integratedserver = this.singleplayerServer;
|
||||
this.singleplayerServer = null;
|
||||
this.gameRenderer.resetData();
|
||||
@@ -319,7 +327,7 @@
|
||||
this.gameMode = null;
|
||||
this.narrator.clear();
|
||||
this.clientLevelTeardownInProgress = true;
|
||||
@@ -2027,6 +_,7 @@
|
||||
@@ -2030,6 +_,7 @@
|
||||
try {
|
||||
this.updateScreenAndTick(p_335030_);
|
||||
if (this.level != null) {
|
||||
@@ -327,7 +335,7 @@
|
||||
if (integratedserver != null) {
|
||||
ProfilerFiller profilerfiller = Profiler.get();
|
||||
profilerfiller.push("waitForServer");
|
||||
@@ -2040,6 +_,7 @@
|
||||
@@ -2043,6 +_,7 @@
|
||||
|
||||
this.gui.onDisconnected();
|
||||
this.isLocalServer = false;
|
||||
@@ -335,40 +343,11 @@
|
||||
}
|
||||
|
||||
this.level = null;
|
||||
@@ -2187,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();
|
||||
@@ -2199,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;
|
||||
}
|
||||
@@ -2213,7 +_,7 @@
|
||||
}
|
||||
|
||||
Entity entity = ((EntityHitResult)this.hitResult).getEntity();
|
||||
- itemstack = entity.getPickResult();
|
||||
+ itemstack = entity.getPickedResult(this.hitResult);
|
||||
if (itemstack == null) {
|
||||
return;
|
||||
}
|
||||
@@ -2818,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,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();
|
||||
@@ -101,17 +_,20 @@
|
||||
(p_357654_, p_357655_) -> p_357655_ == 0 ? -1 : ARGB.opaque(p_357654_.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();
|
||||
@@ -0,0 +1,12 @@
|
||||
--- a/net/minecraft/client/data/models/ItemModelGenerators.java
|
||||
+++ b/net/minecraft/client/data/models/ItemModelGenerators.java
|
||||
@@ -852,6 +_,9 @@
|
||||
this.declareCustomModelItem(Items.COD);
|
||||
this.declareCustomModelItem(Items.FEATHER);
|
||||
this.declareCustomModelItem(Items.LEAD);
|
||||
+ // moved from validate to here, because it's just vanilla default blocks
|
||||
+ if (this.itemModelOutput instanceof ModelProvider.ItemInfoCollector collector)
|
||||
+ collector.generateDefaultBlockModels();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@@ -0,0 +1,111 @@
|
||||
--- a/net/minecraft/client/data/models/ModelProvider.java
|
||||
+++ b/net/minecraft/client/data/models/ModelProvider.java
|
||||
@@ -43,11 +_,11 @@
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> run(CachedOutput p_376268_) {
|
||||
- ModelProvider.ItemInfoCollector modelprovider$iteminfocollector = new ModelProvider.ItemInfoCollector();
|
||||
- ModelProvider.BlockStateGeneratorCollector modelprovider$blockstategeneratorcollector = new ModelProvider.BlockStateGeneratorCollector();
|
||||
+ ModelProvider.ItemInfoCollector modelprovider$iteminfocollector = new ModelProvider.ItemInfoCollector(this::getKnownItems);
|
||||
+ ModelProvider.BlockStateGeneratorCollector modelprovider$blockstategeneratorcollector = new ModelProvider.BlockStateGeneratorCollector(this::getKnownBlocks);
|
||||
ModelProvider.SimpleModelCollector modelprovider$simplemodelcollector = new ModelProvider.SimpleModelCollector();
|
||||
- new BlockModelGenerators(modelprovider$blockstategeneratorcollector, modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
|
||||
- new ItemModelGenerators(modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
|
||||
+ getBlockModelGenerators(modelprovider$blockstategeneratorcollector, modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
|
||||
+ getItemModelGenerators(modelprovider$iteminfocollector, modelprovider$simplemodelcollector).run();
|
||||
modelprovider$blockstategeneratorcollector.validate();
|
||||
modelprovider$iteminfocollector.finalizeAndValidate();
|
||||
return CompletableFuture.allOf(
|
||||
@@ -57,6 +_,22 @@
|
||||
);
|
||||
}
|
||||
|
||||
+ protected Stream<Block> getKnownBlocks() {
|
||||
+ return BuiltInRegistries.BLOCK.stream().filter(block -> "minecraft".equals(block.builtInRegistryHolder().key().location().getNamespace()));
|
||||
+ }
|
||||
+
|
||||
+ protected Stream<Item> getKnownItems() {
|
||||
+ return BuiltInRegistries.ITEM.stream().filter(item -> "minecraft".equals(item.builtInRegistryHolder().key().location().getNamespace()));
|
||||
+ }
|
||||
+
|
||||
+ protected BlockModelGenerators getBlockModelGenerators(BlockStateGeneratorCollector blocks, ItemInfoCollector items, SimpleModelCollector models) {
|
||||
+ return new BlockModelGenerators(blocks, items, models);
|
||||
+ }
|
||||
+
|
||||
+ protected ItemModelGenerators getItemModelGenerators(ItemInfoCollector items, SimpleModelCollector models) {
|
||||
+ return new ItemModelGenerators(items, models);
|
||||
+ }
|
||||
+
|
||||
static <T> CompletableFuture<?> saveAll(CachedOutput p_378816_, Function<T, Path> p_377914_, Map<T, ? extends Supplier<JsonElement>> p_377836_) {
|
||||
return DataProvider.saveAll(p_378816_, Supplier::get, p_377914_, p_377836_);
|
||||
}
|
||||
@@ -69,6 +_,15 @@
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class BlockStateGeneratorCollector implements Consumer<BlockStateGenerator> {
|
||||
private final Map<Block, BlockStateGenerator> generators = new HashMap<>();
|
||||
+ private final Supplier<Stream<Block>> known;
|
||||
+
|
||||
+ public BlockStateGeneratorCollector() {
|
||||
+ this(() -> BuiltInRegistries.BLOCK.stream().filter(block -> "minecraft".equals(block.builtInRegistryHolder().key().location().getNamespace())));
|
||||
+ }
|
||||
+
|
||||
+ public BlockStateGeneratorCollector(Supplier<Stream<Block>> known) {
|
||||
+ this.known = known;
|
||||
+ }
|
||||
|
||||
public void accept(BlockStateGenerator p_378147_) {
|
||||
Block block = p_378147_.getBlock();
|
||||
@@ -79,7 +_,7 @@
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
- Stream<Holder.Reference<Block>> stream = BuiltInRegistries.BLOCK.listElements().filter(p_376480_ -> true);
|
||||
+ Stream<Holder.Reference<Block>> stream = known.get().map(Block::builtInRegistryHolder);
|
||||
List<ResourceLocation> list = stream.filter(p_378423_ -> !this.generators.containsKey(p_378423_.value()))
|
||||
.map(p_378200_ -> p_378200_.key().location())
|
||||
.toList();
|
||||
@@ -97,6 +_,15 @@
|
||||
public static class ItemInfoCollector implements ItemModelOutput {
|
||||
private final Map<Item, ClientItem> itemInfos = new HashMap<>();
|
||||
private final Map<Item, Item> copies = new HashMap<>();
|
||||
+ private final Supplier<Stream<Item>> known;
|
||||
+
|
||||
+ public ItemInfoCollector() {
|
||||
+ this(() -> BuiltInRegistries.ITEM.stream().filter(item -> "minecraft".equals(item.builtInRegistryHolder().key().location().getNamespace())));
|
||||
+ }
|
||||
+
|
||||
+ public ItemInfoCollector(Supplier<Stream<Item>> known) {
|
||||
+ this.known = known;
|
||||
+ }
|
||||
|
||||
@Override
|
||||
public void accept(Item p_376450_, ItemModel.Unbaked p_378513_) {
|
||||
@@ -115,7 +_,7 @@
|
||||
this.copies.put(p_376965_, p_377438_);
|
||||
}
|
||||
|
||||
- public void finalizeAndValidate() {
|
||||
+ public void generateDefaultBlockModels() {
|
||||
BuiltInRegistries.ITEM.forEach(p_378629_ -> {
|
||||
if (!this.copies.containsKey(p_378629_)) {
|
||||
if (p_378629_ instanceof BlockItem blockitem && !this.itemInfos.containsKey(blockitem)) {
|
||||
@@ -124,6 +_,8 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
+ }
|
||||
+ public void finalizeAndValidate() {
|
||||
this.copies.forEach((p_376289_, p_375718_) -> {
|
||||
ClientItem clientitem = this.itemInfos.get(p_375718_);
|
||||
if (clientitem == null) {
|
||||
@@ -132,8 +_,8 @@
|
||||
this.register(p_376289_, clientitem);
|
||||
}
|
||||
});
|
||||
- List<ResourceLocation> list = BuiltInRegistries.ITEM
|
||||
- .listElements()
|
||||
+ List<ResourceLocation> list = known.get()
|
||||
+ .map(item -> item.builtInRegistryHolder())
|
||||
.filter(p_377225_ -> !this.itemInfos.containsKey(p_377225_.value()))
|
||||
.map(p_378591_ -> p_378591_.key().location())
|
||||
.toList();
|
||||
@@ -1,11 +1,11 @@
|
||||
--- a/net/minecraft/client/gui/Font.java
|
||||
+++ b/net/minecraft/client/gui/Font.java
|
||||
@@ -33,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;
|
||||
public static final float SHADOW_DEPTH = 0.03F;
|
||||
public static final int NO_SHADOW = 0;
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/GuiGraphics.java
|
||||
+++ b/net/minecraft/client/gui/GuiGraphics.java
|
||||
@@ -53,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;
|
||||
@@ -227,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_) {
|
||||
@@ -21,7 +21,7 @@
|
||||
return p_281896_ == null
|
||||
? 0
|
||||
: p_283343_.drawInBatch(
|
||||
@@ -248,6 +_,11 @@
|
||||
@@ -250,6 +_,11 @@
|
||||
}
|
||||
|
||||
public int drawString(Font p_282636_, FormattedCharSequence p_281596_, int p_281586_, int p_282816_, int p_281743_, boolean p_282394_) {
|
||||
@@ -33,7 +33,7 @@
|
||||
return p_282636_.drawInBatch(
|
||||
p_281596_,
|
||||
(float)p_281586_,
|
||||
@@ -872,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,7 +41,7 @@
|
||||
crashreportcategory.setDetail("Item Components", () -> String.valueOf(p_281675_.getComponents()));
|
||||
crashreportcategory.setDetail("Item Foil", () -> String.valueOf(p_281675_.hasFoil()));
|
||||
throw new ReportedException(crashreport);
|
||||
@@ -892,13 +_,24 @@
|
||||
@@ -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();
|
||||
@@ -66,7 +66,7 @@
|
||||
}
|
||||
|
||||
public void renderTooltip(Font p_283128_, List<Component> p_282716_, Optional<TooltipComponent> p_281682_, int p_283678_, int p_281696_) {
|
||||
@@ -908,8 +_,7 @@
|
||||
@@ -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_
|
||||
) {
|
||||
@@ -76,7 +76,7 @@
|
||||
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_) {
|
||||
@@ -100,7 +100,7 @@
|
||||
}
|
||||
|
||||
public void renderComponentTooltip(Font p_369090_, List<Component> p_365405_, int p_368143_, int p_366244_, @Nullable ResourceLocation p_364763_) {
|
||||
@@ -964,11 +_,13 @@
|
||||
@@ -951,11 +_,13 @@
|
||||
@Nullable ResourceLocation p_368234_
|
||||
) {
|
||||
if (!p_282615_.isEmpty()) {
|
||||
@@ -115,7 +115,7 @@
|
||||
if (k > i) {
|
||||
i = k;
|
||||
}
|
||||
@@ -978,18 +_,19 @@
|
||||
@@ -965,18 +_,19 @@
|
||||
|
||||
int i2 = i;
|
||||
int j2 = j;
|
||||
@@ -138,7 +138,7 @@
|
||||
k1 += clienttooltipcomponent1.getHeight(p_282675_) + (l1 == 0 ? 2 : 0);
|
||||
}
|
||||
|
||||
@@ -997,7 +_,7 @@
|
||||
@@ -984,7 +_,7 @@
|
||||
|
||||
for (int k2 = 0; k2 < p_282615_.size(); k2++) {
|
||||
ClientTooltipComponent clienttooltipcomponent2 = p_282615_.get(k2);
|
||||
@@ -147,7 +147,7 @@
|
||||
k1 += clienttooltipcomponent2.getHeight(p_282675_) + (k2 == 0 ? 2 : 0);
|
||||
}
|
||||
|
||||
@@ -1054,6 +_,10 @@
|
||||
@@ -1041,6 +_,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/components/AbstractWidget.java
|
||||
+++ b/net/minecraft/client/gui/components/AbstractWidget.java
|
||||
@@ -259,6 +_,25 @@
|
||||
@@ -250,6 +_,25 @@
|
||||
this.focused = p_93693_;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/screens/LoadingOverlay.java
|
||||
+++ b/net/minecraft/client/gui/screens/LoadingOverlay.java
|
||||
@@ -62,6 +_,8 @@
|
||||
@@ -61,6 +_,8 @@
|
||||
return p_169325_ & 16777215 | p_169326_ << 24;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
@Override
|
||||
public void render(GuiGraphics p_281839_, int p_282704_, int p_283650_, float p_283394_) {
|
||||
int i = p_281839_.guiWidth();
|
||||
@@ -100,6 +_,7 @@
|
||||
@@ -99,6 +_,7 @@
|
||||
f2 = 1.0F;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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;
|
||||
@@ -115,12 +_,14 @@
|
||||
@@ -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));
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
try {
|
||||
this.reload.checkExceptions();
|
||||
this.onFinish.accept(Optional.empty());
|
||||
@@ -128,7 +_,6 @@
|
||||
@@ -127,7 +_,6 @@
|
||||
this.onFinish.accept(Optional.of(throwable));
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +8,7 @@
|
||||
|
||||
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;
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
l = this.createTestWorldButton(l, 24);
|
||||
SpriteIconButton spriteiconbutton = this.addRenderableWidget(
|
||||
@@ -184,7 +_,7 @@
|
||||
@@ -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)))
|
||||
@@ -33,7 +33,7 @@
|
||||
.tooltip(tooltip)
|
||||
.build()
|
||||
)
|
||||
@@ -293,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);
|
||||
}
|
||||
@@ -308,10 +_,18 @@
|
||||
@@ -304,10 +_,18 @@
|
||||
s = s + I18n.get("menu.modded");
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java
|
||||
+++ b/net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java
|
||||
@@ -108,6 +_,7 @@
|
||||
@@ -106,6 +_,7 @@
|
||||
int i = this.leftPos;
|
||||
int j = this.topPos;
|
||||
super.render(p_283479_, p_283661_, p_281248_, p_281886_);
|
||||
@@ -8,7 +8,7 @@
|
||||
p_283479_.pose().pushPose();
|
||||
p_283479_.pose().translate((float)i, (float)j, 0.0F);
|
||||
Slot slot = this.hoveredSlot;
|
||||
@@ -119,6 +_,8 @@
|
||||
@@ -117,6 +_,8 @@
|
||||
this.onStopHovering(slot);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
this.renderLabels(p_283479_, p_283661_, p_281248_);
|
||||
ItemStack itemstack = this.draggingItem.isEmpty() ? this.menu.getCarried() : this.draggingItem;
|
||||
if (!itemstack.isEmpty()) {
|
||||
@@ -199,7 +_,7 @@
|
||||
@@ -197,7 +_,7 @@
|
||||
ItemStack itemstack = this.hoveredSlot.getItem();
|
||||
if (this.menu.getCarried().isEmpty() || this.showTooltipWithItemInHand(itemstack)) {
|
||||
p_283594_.renderTooltip(
|
||||
@@ -26,7 +26,7 @@
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -217,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_);
|
||||
@@ -36,7 +36,7 @@
|
||||
p_282567_.pose().popPose();
|
||||
}
|
||||
|
||||
@@ -324,7 +_,8 @@
|
||||
@@ -321,7 +_,8 @@
|
||||
if (super.mouseClicked(p_97748_, p_97749_, p_97750_)) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -46,7 +46,7 @@
|
||||
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_;
|
||||
@@ -335,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_);
|
||||
@@ -54,7 +54,7 @@
|
||||
int l = -1;
|
||||
if (slot != null) {
|
||||
l = slot.index;
|
||||
@@ -360,7 +_,7 @@
|
||||
@@ -357,7 +_,7 @@
|
||||
}
|
||||
} else if (!this.isQuickCrafting) {
|
||||
if (this.menu.getCarried().isEmpty()) {
|
||||
@@ -63,7 +63,7 @@
|
||||
this.slotClicked(slot, l, p_97750_, ClickType.CLONE);
|
||||
} else {
|
||||
boolean flag2 = l != -999
|
||||
@@ -388,7 +_,7 @@
|
||||
@@ -385,7 +_,7 @@
|
||||
this.quickCraftingType = 0;
|
||||
} else if (p_97750_ == 1) {
|
||||
this.quickCraftingType = 1;
|
||||
@@ -72,7 +72,7 @@
|
||||
this.quickCraftingType = 2;
|
||||
}
|
||||
}
|
||||
@@ -467,10 +_,13 @@
|
||||
@@ -464,10 +_,13 @@
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(double p_97812_, double p_97813_, int p_97814_) {
|
||||
@@ -86,7 +86,7 @@
|
||||
int k = -1;
|
||||
if (slot != null) {
|
||||
k = slot.index;
|
||||
@@ -487,7 +_,7 @@
|
||||
@@ -484,7 +_,7 @@
|
||||
if (slot2 != null
|
||||
&& slot2.mayPickup(this.minecraft.player)
|
||||
&& slot2.hasItem()
|
||||
@@ -95,7 +95,7 @@
|
||||
&& AbstractContainerMenu.canItemQuickReplace(slot2, this.lastQuickMoved, true)) {
|
||||
this.slotClicked(slot2, slot2.index, p_97814_, ClickType.QUICK_MOVE);
|
||||
}
|
||||
@@ -551,7 +_,7 @@
|
||||
@@ -548,7 +_,7 @@
|
||||
|
||||
this.slotClicked(null, -999, AbstractContainerMenu.getQuickcraftMask(2, this.quickCraftingType), ClickType.QUICK_CRAFT);
|
||||
} else if (!this.menu.getCarried().isEmpty()) {
|
||||
@@ -104,7 +104,7 @@
|
||||
this.slotClicked(slot, k, p_97814_, ClickType.CLONE);
|
||||
} else {
|
||||
boolean flag1 = k != -999
|
||||
@@ -631,9 +_,10 @@
|
||||
@@ -628,9 +_,10 @@
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int p_97765_, int p_97766_, int p_97767_) {
|
||||
@@ -116,7 +116,7 @@
|
||||
this.onClose();
|
||||
return true;
|
||||
} else {
|
||||
@@ -707,4 +_,11 @@
|
||||
@@ -704,4 +_,11 @@
|
||||
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
+25
-25
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java
|
||||
+++ b/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java
|
||||
@@ -115,6 +_,8 @@
|
||||
@@ -114,6 +_,8 @@
|
||||
private final Set<TagKey<Item>> visibleTags = new HashSet<>();
|
||||
private final boolean displayOperatorCreativeTab;
|
||||
private final EffectsInInventory effects;
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
public CreativeModeInventoryScreen(LocalPlayer p_344408_, FeatureFlagSet p_260074_, boolean p_259569_) {
|
||||
super(new CreativeModeInventoryScreen.ItemPickerMenu(p_344408_), p_344408_.getInventory(), CommonComponents.EMPTY);
|
||||
@@ -163,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_);
|
||||
@@ -331,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);
|
||||
@@ -377,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();
|
||||
@@ -396,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());
|
||||
@@ -432,6 +_,7 @@
|
||||
@@ -431,6 +_,7 @@
|
||||
}
|
||||
|
||||
private void refreshSearchResults() {
|
||||
@@ -80,7 +80,7 @@
|
||||
this.menu.items.clear();
|
||||
this.visibleTags.clear();
|
||||
String s = this.searchBox.getValue();
|
||||
@@ -444,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)));
|
||||
@@ -479,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 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,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;
|
||||
}
|
||||
@@ -511,7 +_,7 @@
|
||||
@@ -510,7 +_,7 @@
|
||||
double d1 = p_98623_ - (double)this.topPos;
|
||||
this.scrolling = false;
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
if (this.checkTabClicked(creativemodetab, d0, d1)) {
|
||||
this.selectTab(creativemodetab);
|
||||
return true;
|
||||
@@ -605,13 +_,15 @@
|
||||
@@ -604,13 +_,15 @@
|
||||
this.originalSlots = null;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
this.refreshSearchResults();
|
||||
} else {
|
||||
@@ -677,7 +_,15 @@
|
||||
@@ -676,7 +_,15 @@
|
||||
super.render(p_283000_, p_281317_, p_282770_, p_281295_);
|
||||
this.effects.render(p_283000_, p_281317_, p_282770_, p_281295_);
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
if (this.checkTabHovering(p_283000_, creativemodetab, p_281317_, p_282770_)) {
|
||||
break;
|
||||
}
|
||||
@@ -689,6 +_,7 @@
|
||||
@@ -688,6 +_,7 @@
|
||||
p_283000_.renderTooltip(this.font, TRASH_SLOT_TOOLTIP, p_281317_, p_282770_);
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
this.renderTooltip(p_283000_, p_281317_, p_282770_);
|
||||
}
|
||||
|
||||
@@ -701,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;
|
||||
@@ -172,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);
|
||||
@@ -720,7 +_,7 @@
|
||||
@@ -719,7 +_,7 @@
|
||||
int i = 1;
|
||||
|
||||
for (CreativeModeTab creativemodetab : CreativeModeTabs.tabs()) {
|
||||
@@ -181,7 +181,7 @@
|
||||
list1.add(i++, creativemodetab.getDisplayName().copy().withStyle(ChatFormatting.BLUE));
|
||||
}
|
||||
}
|
||||
@@ -731,7 +_,7 @@
|
||||
@@ -730,7 +_,7 @@
|
||||
|
||||
@Override
|
||||
protected void renderBg(GuiGraphics p_282663_, float p_282504_, int p_282089_, int p_282249_) {
|
||||
@@ -190,7 +190,7 @@
|
||||
if (creativemodetab != selectedTab) {
|
||||
this.renderTabButton(p_282663_, creativemodetab);
|
||||
}
|
||||
@@ -747,6 +_,7 @@
|
||||
@@ -746,6 +_,7 @@
|
||||
p_282663_.blitSprite(RenderType::guiTextured, resourcelocation, j, k + (int)((float)(i - k - 17) * this.scrollOffs), 12, 15);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
this.renderTabButton(p_282663_, selectedTab);
|
||||
if (selectedTab.getType() == CreativeModeTab.Type.INVENTORY) {
|
||||
InventoryScreen.renderEntityInInventoryFollowsMouse(
|
||||
@@ -765,7 +_,7 @@
|
||||
@@ -764,7 +_,7 @@
|
||||
}
|
||||
|
||||
private int getTabX(CreativeModeTab p_260136_) {
|
||||
@@ -207,7 +207,7 @@
|
||||
int j = 27;
|
||||
int k = 27 * i;
|
||||
if (p_260136_.isAlignedRight()) {
|
||||
@@ -777,7 +_,7 @@
|
||||
@@ -776,7 +_,7 @@
|
||||
|
||||
private int getTabY(CreativeModeTab p_260181_) {
|
||||
int i = 0;
|
||||
@@ -216,7 +216,7 @@
|
||||
i -= 32;
|
||||
} else {
|
||||
i += this.imageHeight;
|
||||
@@ -805,8 +_,8 @@
|
||||
@@ -804,8 +_,8 @@
|
||||
|
||||
protected void renderTabButton(GuiGraphics p_283590_, CreativeModeTab p_283489_) {
|
||||
boolean flag = p_283489_ == selectedTab;
|
||||
@@ -227,7 +227,7 @@
|
||||
int j = this.leftPos + this.getTabX(p_283489_);
|
||||
int k = this.topPos - (flag1 ? 28 : -(this.imageHeight - 4));
|
||||
ResourceLocation[] aresourcelocation;
|
||||
@@ -816,6 +_,7 @@
|
||||
@@ -815,6 +_,7 @@
|
||||
aresourcelocation = flag ? SELECTED_BOTTOM_TABS : UNSELECTED_BOTTOM_TABS;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@
|
||||
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);
|
||||
@@ -857,6 +_,14 @@
|
||||
@@ -856,6 +_,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,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_) {
|
||||
@@ -1038,6 +_,22 @@
|
||||
@@ -1037,6 +_,22 @@
|
||||
@Override
|
||||
public boolean mayPickup(Player p_98665_) {
|
||||
return this.target.mayPickup(p_98665_);
|
||||
@@ -267,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
-1
@@ -8,7 +8,7 @@
|
||||
+ 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{
|
||||
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);
|
||||
p_282430_.drawWordWrap(this.font, formattedtext, j1, j + 16 + 19 * l, l1, (i2 & 16711422) >> 1, false);
|
||||
@@ -175,13 +_,16 @@
|
||||
.registryAccess()
|
||||
.lookupOrThrow(Registries.ENCHANTMENT)
|
||||
|
||||
+1
-1
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
+3
-15
@@ -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,7 +12,7 @@
|
||||
.createNarration(
|
||||
p_342179_ -> p_343088_.isUnbound()
|
||||
? Component.translatable("narrator.controls.unbound", p_343976_)
|
||||
@@ -163,7 +_,7 @@
|
||||
@@ -158,7 +_,7 @@
|
||||
)
|
||||
.build();
|
||||
this.resetButton = Button.builder(RESET_BUTTON_TITLE, p_357685_ -> {
|
||||
@@ -33,7 +21,7 @@
|
||||
KeyBindsList.this.resetMappingAndUpdateButtons();
|
||||
}).bounds(0, 0, 50, 20).createNarration(p_344192_ -> Component.translatable("narrator.controls.reset", p_343976_)).build();
|
||||
this.refreshEntry();
|
||||
@@ -215,7 +_,7 @@
|
||||
@@ -210,7 +_,7 @@
|
||||
MutableComponent mutablecomponent = Component.empty();
|
||||
if (!this.key.isUnbound()) {
|
||||
for (KeyMapping keymapping : KeyBindsList.this.minecraft.options.keyMappings) {
|
||||
|
||||
+2
-2
@@ -6,6 +6,6 @@
|
||||
p_100014_.setSelected(null);
|
||||
- p_100015_.forEach(
|
||||
+ p_100015_.filter(PackSelectionModel.Entry::notHidden).forEach(
|
||||
p_357689_ -> {
|
||||
p_374582_ -> {
|
||||
TransferableSelectionList.PackEntry transferableselectionlist$packentry1 = new TransferableSelectionList.PackEntry(
|
||||
this.minecraft, p_100014_, p_357689_
|
||||
this.minecraft, p_100014_, p_374582_
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java
|
||||
+++ b/net/minecraft/client/gui/screens/worldselection/CreateWorldScreen.java
|
||||
@@ -169,6 +_,7 @@
|
||||
@@ -168,6 +_,7 @@
|
||||
) {
|
||||
queueLoadScreen(p_369292_, PREPARING_WORLD_DATA);
|
||||
PackRepository packrepository = new PackRepository(new ServerPacksSource(p_369292_.directoryValidator()));
|
||||
@@ -8,7 +8,7 @@
|
||||
WorldLoader.InitConfig worldloader$initconfig = createDefaultLoadConfig(packrepository, WorldDataConfiguration.DEFAULT);
|
||||
CompletableFuture<WorldCreationContext> completablefuture = WorldLoader.load(
|
||||
worldloader$initconfig,
|
||||
@@ -479,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"),
|
||||
@@ -593,6 +_,7 @@
|
||||
@@ -582,6 +_,7 @@
|
||||
if (path != null) {
|
||||
if (this.tempDataPackRepository == null) {
|
||||
this.tempDataPackRepository = ServerPacksSource.createPackRepository(path, this.packValidator);
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@
|
||||
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);
|
||||
@@ -400,6 +_,7 @@
|
||||
p_281612_.drawString(this.minecraft.font, s1, p_282820_ + 32 + 3, p_283181_ + 9 + 3, -8355712, false);
|
||||
p_281612_.drawString(this.minecraft.font, component, p_282820_ + 32 + 3, p_283181_ + 9 + 9 + 3, -8355712, false);
|
||||
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_) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
--- a/net/minecraft/client/main/Main.java
|
||||
+++ b/net/minecraft/client/main/Main.java
|
||||
@@ -120,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(optionspec29);
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/model/HumanoidModel.java
|
||||
+++ b/net/minecraft/client/model/HumanoidModel.java
|
||||
@@ -259,6 +_,8 @@
|
||||
@@ -255,6 +_,8 @@
|
||||
case BRUSH:
|
||||
this.rightArm.xRot = this.rightArm.xRot * 0.5F - (float) (Math.PI / 5);
|
||||
this.rightArm.yRot = 0.0F;
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +_,8 @@
|
||||
@@ -299,6 +_,8 @@
|
||||
case BRUSH:
|
||||
this.leftArm.xRot = this.leftArm.xRot * 0.5F - (float) (Math.PI / 5);
|
||||
this.leftArm.yRot = 0.0F;
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +_,7 @@
|
||||
@@ -377,7 +_,7 @@
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@@ -27,7 +27,7 @@
|
||||
EMPTY(false),
|
||||
ITEM(false),
|
||||
BLOCK(false),
|
||||
@@ -397,10 +_,28 @@
|
||||
@@ -393,10 +_,28 @@
|
||||
|
||||
private ArmPose(final boolean p_102896_) {
|
||||
this.twoHanded = p_102896_;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
--- a/net/minecraft/client/model/geom/LayerDefinitions.java
|
||||
+++ b/net/minecraft/client/model/geom/LayerDefinitions.java
|
||||
@@ -449,6 +_,7 @@
|
||||
builder.put(ModelLayers.createWallSignModelName(p_357774_), layerdefinition54);
|
||||
builder.put(ModelLayers.createHangingSignModelName(p_357774_), layerdefinition55);
|
||||
@@ -464,6 +_,7 @@
|
||||
builder.put(ModelLayers.createHangingSignModelName(p_374591_, hangingsignrenderer$attachmenttype), layerdefinition55);
|
||||
}
|
||||
});
|
||||
+ net.minecraftforge.client.ForgeHooksClient.loadLayerDefinitions(builder);
|
||||
ImmutableMap<ModelLayerLocation, LayerDefinition> immutablemap = builder.build();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/model/geom/ModelLayers.java
|
||||
+++ b/net/minecraft/client/model/geom/ModelLayers.java
|
||||
@@ -301,15 +_,18 @@
|
||||
@@ -308,15 +_,18 @@
|
||||
}
|
||||
|
||||
public static ModelLayerLocation createStandingSignModelName(WoodType p_171292_) {
|
||||
@@ -15,10 +15,10 @@
|
||||
+ return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(location.getNamespace(), "sign/wall/" + location.getPath()), "main");
|
||||
}
|
||||
|
||||
public static ModelLayerLocation createHangingSignModelName(WoodType p_252225_) {
|
||||
- return createLocation("hanging_sign/" + p_252225_.name(), "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() {
|
||||
@@ -8,7 +8,7 @@
|
||||
this.storage.drop(i, levelchunk);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +_,7 @@
|
||||
@@ -124,6 +_,7 @@
|
||||
}
|
||||
|
||||
this.level.onChunkLoaded(chunkpos);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/multiplayer/ClientLevel.java
|
||||
+++ b/net/minecraft/client/multiplayer/ClientLevel.java
|
||||
@@ -118,6 +_,7 @@
|
||||
@@ -123,6 +_,7 @@
|
||||
p_194170_.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache(p_194181_ -> this.calculateBlockTint(p_194181_, BiomeColors.GRASS_COLOR_RESOLVER)));
|
||||
p_194170_.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache(p_194177_ -> this.calculateBlockTint(p_194177_, BiomeColors.FOLIAGE_COLOR_RESOLVER)));
|
||||
p_194170_.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache(p_194168_ -> this.calculateBlockTint(p_194168_, BiomeColors.WATER_COLOR_RESOLVER)));
|
||||
@@ -8,7 +8,7 @@
|
||||
});
|
||||
private final ClientChunkCache chunkSource;
|
||||
private final Deque<Runnable> lightUpdateQueue = Queues.newArrayDeque();
|
||||
@@ -126,6 +_,8 @@
|
||||
@@ -131,6 +_,8 @@
|
||||
private final int seaLevel;
|
||||
private boolean tickDayTime;
|
||||
private static final Set<Item> MARKER_PARTICLE_ITEMS = Set.of(Items.BARRIER, Items.LIGHT);
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
public void handleBlockChangedAck(int p_233652_) {
|
||||
this.blockStatePredictionHandler.endPredictionsUpTo(p_233652_, this);
|
||||
@@ -192,6 +_,8 @@
|
||||
@@ -197,6 +_,8 @@
|
||||
this.serverSimulationDistance = p_364305_;
|
||||
this.updateSkyBrightness();
|
||||
this.prepareWeather();
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
|
||||
public void queueLightUpdate(Runnable p_194172_) {
|
||||
@@ -274,6 +_,7 @@
|
||||
@@ -279,6 +_,7 @@
|
||||
p_104640_.setOldPosAndRot();
|
||||
p_104640_.tickCount++;
|
||||
Profiler.get().push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(p_104640_.getType()).toString());
|
||||
@@ -34,7 +34,7 @@
|
||||
p_104640_.tick();
|
||||
Profiler.get().pop();
|
||||
|
||||
@@ -326,8 +_,10 @@
|
||||
@@ -330,8 +_,10 @@
|
||||
}
|
||||
|
||||
public void addEntity(Entity p_104741_) {
|
||||
@@ -45,7 +45,7 @@
|
||||
}
|
||||
|
||||
public void removeEntity(int p_171643_, Entity.RemovalReason p_171644_) {
|
||||
@@ -498,6 +_,12 @@
|
||||
@@ -502,6 +_,12 @@
|
||||
float p_263349_,
|
||||
long p_263408_
|
||||
) {
|
||||
@@ -58,7 +58,7 @@
|
||||
if (p_263381_ == this.minecraft.player) {
|
||||
this.playSound(p_263372_, p_263404_, p_263365_, p_263335_.value(), p_263417_, p_263416_, p_263349_, false, p_263408_);
|
||||
}
|
||||
@@ -507,6 +_,12 @@
|
||||
@@ -511,6 +_,12 @@
|
||||
public void playSeededSound(
|
||||
@Nullable Player p_263514_, Entity p_263536_, Holder<SoundEvent> p_263518_, SoundSource p_263487_, float p_263538_, float p_263524_, long p_263509_
|
||||
) {
|
||||
@@ -71,7 +71,7 @@
|
||||
if (p_263514_ == this.minecraft.player) {
|
||||
this.minecraft.getSoundManager().play(new EntityBoundSoundInstance(p_263518_.value(), p_263487_, p_263538_, p_263524_, p_263536_, p_263509_));
|
||||
}
|
||||
@@ -943,6 +_,24 @@
|
||||
@@ -953,6 +_,24 @@
|
||||
return this.seaLevel;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class ClientLevelData implements WritableLevelData {
|
||||
private final boolean hardcore;
|
||||
@@ -1031,6 +_,7 @@
|
||||
@@ -1041,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void setDifficulty(Difficulty p_104852_) {
|
||||
@@ -104,9 +104,9 @@
|
||||
this.difficulty = p_104852_;
|
||||
}
|
||||
|
||||
@@ -1067,11 +_,26 @@
|
||||
if (p_171712_ instanceof AbstractClientPlayer) {
|
||||
ClientLevel.this.players.add((AbstractClientPlayer)p_171712_);
|
||||
@@ -1084,6 +_,12 @@
|
||||
break;
|
||||
default:
|
||||
}
|
||||
+
|
||||
+ if (p_171712_.isMultipartEntity()) {
|
||||
@@ -117,8 +117,11 @@
|
||||
}
|
||||
|
||||
public void onTrackingEnd(Entity p_171716_) {
|
||||
p_171716_.unRide();
|
||||
ClientLevel.this.players.remove(p_171716_);
|
||||
@@ -1097,6 +_,15 @@
|
||||
ClientLevel.this.dragonParts.removeAll(Arrays.asList(enderdragon.getSubEntities()));
|
||||
break;
|
||||
default:
|
||||
+ }
|
||||
+
|
||||
+ p_171716_.onRemovedFromWorld();
|
||||
+ net.minecraftforge.event.ForgeEventFactory.onEntityLeaveLevel(p_171716_, ClientLevel.this);
|
||||
@@ -127,7 +130,6 @@
|
||||
+ for (var part : p_171716_.getParts()) {
|
||||
+ ClientLevel.this.partEntities.remove(part.getId());
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
public void onSectionChange(Entity p_233660_) {
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/multiplayer/ClientPacketListener.java
|
||||
+++ b/net/minecraft/client/multiplayer/ClientPacketListener.java
|
||||
@@ -451,6 +_,7 @@
|
||||
@@ -452,6 +_,7 @@
|
||||
|
||||
this.minecraft.debugRenderer.clear();
|
||||
this.minecraft.player.resetPos();
|
||||
@@ -57,7 +57,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2516,6 +_,8 @@
|
||||
@@ -2530,6 +_,8 @@
|
||||
}
|
||||
|
||||
public void sendChat(String p_249888_) {
|
||||
@@ -66,7 +66,7 @@
|
||||
Instant instant = Instant.now();
|
||||
long i = Crypt.SaltSupplier.getLong();
|
||||
LastSeenMessagesTracker.Update lastseenmessagestracker$update = this.lastSeenMessages.generateAndApplyUpdate();
|
||||
@@ -2524,6 +_,7 @@
|
||||
@@ -2538,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void sendCommand(String p_250092_) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/multiplayer/MultiPlayerGameMode.java
|
||||
+++ b/net/minecraft/client/multiplayer/MultiPlayerGameMode.java
|
||||
@@ -106,6 +_,7 @@
|
||||
@@ -107,6 +_,7 @@
|
||||
}
|
||||
|
||||
public boolean destroyBlock(BlockPos p_105268_) {
|
||||
@@ -8,7 +8,7 @@
|
||||
if (this.minecraft.player.blockActionRestricted(this.minecraft.level, p_105268_, this.localPlayerMode)) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -120,9 +_,8 @@
|
||||
@@ -121,9 +_,8 @@
|
||||
} else if (blockstate.isAir()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -19,7 +19,7 @@
|
||||
if (flag) {
|
||||
block.destroy(level, p_105268_, blockstate);
|
||||
}
|
||||
@@ -143,6 +_,7 @@
|
||||
@@ -144,6 +_,7 @@
|
||||
BlockState blockstate = this.minecraft.level.getBlockState(p_105270_);
|
||||
this.minecraft.getTutorial().onDestroyBlock(this.minecraft.level, p_105270_, blockstate, 1.0F);
|
||||
this.startPrediction(this.minecraft.level, p_233757_ -> {
|
||||
@@ -27,7 +27,7 @@
|
||||
this.destroyBlock(p_105270_);
|
||||
return new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, p_105270_, p_105271_, p_233757_);
|
||||
});
|
||||
@@ -152,15 +_,18 @@
|
||||
@@ -153,15 +_,18 @@
|
||||
this.connection
|
||||
.send(new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK, this.destroyBlockPos, p_105271_));
|
||||
}
|
||||
@@ -46,7 +46,7 @@
|
||||
if (flag && blockstate1.getDestroyProgress(this.minecraft.player, this.minecraft.player.level(), p_105270_) >= 1.0F) {
|
||||
this.destroyBlock(p_105270_);
|
||||
} else {
|
||||
@@ -171,6 +_,7 @@
|
||||
@@ -172,6 +_,7 @@
|
||||
this.destroyTicks = 0.0F;
|
||||
this.minecraft.level.destroyBlockProgress(this.minecraft.player.getId(), this.destroyBlockPos, this.getDestroyStage());
|
||||
}
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
return new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, p_105270_, p_105271_, p_233728_);
|
||||
});
|
||||
@@ -203,6 +_,7 @@
|
||||
@@ -204,6 +_,7 @@
|
||||
BlockState blockstate1 = this.minecraft.level.getBlockState(p_105284_);
|
||||
this.minecraft.getTutorial().onDestroyBlock(this.minecraft.level, p_105284_, blockstate1, 1.0F);
|
||||
this.startPrediction(this.minecraft.level, p_233753_ -> {
|
||||
@@ -62,7 +62,7 @@
|
||||
this.destroyBlock(p_105284_);
|
||||
return new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, p_105284_, p_105285_, p_233753_);
|
||||
});
|
||||
@@ -215,7 +_,7 @@
|
||||
@@ -216,7 +_,7 @@
|
||||
} else {
|
||||
this.destroyProgress = this.destroyProgress + blockstate.getDestroyProgress(this.minecraft.player, this.minecraft.player.level(), p_105284_);
|
||||
if (this.destroyTicks % 4.0F == 0.0F) {
|
||||
@@ -71,7 +71,7 @@
|
||||
this.minecraft
|
||||
.getSoundManager()
|
||||
.play(
|
||||
@@ -232,6 +_,7 @@
|
||||
@@ -233,6 +_,7 @@
|
||||
|
||||
this.destroyTicks++;
|
||||
this.minecraft.getTutorial().onDestroyBlock(this.minecraft.level, p_105284_, blockstate, Mth.clamp(this.destroyProgress, 0.0F, 1.0F));
|
||||
@@ -79,7 +79,7 @@
|
||||
if (this.destroyProgress >= 1.0F) {
|
||||
this.isDestroying = false;
|
||||
this.startPrediction(this.minecraft.level, p_233739_ -> {
|
||||
@@ -270,7 +_,7 @@
|
||||
@@ -271,7 +_,7 @@
|
||||
|
||||
private boolean sameDestroyTarget(BlockPos p_105282_) {
|
||||
ItemStack itemstack = this.minecraft.player.getMainHandItem();
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
|
||||
private void ensureHasSentCarriedItem() {
|
||||
@@ -298,12 +_,23 @@
|
||||
@@ -299,12 +_,23 @@
|
||||
private InteractionResult performUseItemOn(LocalPlayer p_233747_, InteractionHand p_233748_, BlockHitResult p_233749_) {
|
||||
BlockPos blockpos = p_233749_.getBlockPos();
|
||||
ItemStack itemstack = p_233747_.getItemInHand(p_233748_);
|
||||
@@ -114,7 +114,7 @@
|
||||
BlockState blockstate = this.minecraft.level.getBlockState(blockpos);
|
||||
if (!this.connection.isFeatureEnabled(blockstate.getBlock().requiredFeatures())) {
|
||||
return InteractionResult.FAIL;
|
||||
@@ -324,8 +_,10 @@
|
||||
@@ -325,8 +_,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
InteractionResult interactionresult2;
|
||||
if (this.localPlayerMode.isCreative()) {
|
||||
int i = itemstack.getCount();
|
||||
@@ -359,6 +_,11 @@
|
||||
@@ -360,6 +_,11 @@
|
||||
mutableobject.setValue(InteractionResult.PASS);
|
||||
return serverbounduseitempacket;
|
||||
} else {
|
||||
@@ -139,7 +139,7 @@
|
||||
InteractionResult interactionresult = itemstack.use(this.minecraft.level, p_233722_, p_233723_);
|
||||
ItemStack itemstack1;
|
||||
if (interactionresult instanceof InteractionResult.Success interactionresult$success) {
|
||||
@@ -369,6 +_,9 @@
|
||||
@@ -370,6 +_,9 @@
|
||||
|
||||
if (itemstack1 != itemstack) {
|
||||
p_233722_.setItemInHand(p_233723_, itemstack1);
|
||||
@@ -149,7 +149,7 @@
|
||||
}
|
||||
|
||||
mutableobject.setValue(interactionresult);
|
||||
@@ -400,6 +_,10 @@
|
||||
@@ -401,6 +_,10 @@
|
||||
public InteractionResult interact(Player p_105227_, Entity p_105228_, InteractionHand p_105229_) {
|
||||
this.ensureHasSentCarriedItem();
|
||||
this.connection.send(ServerboundInteractPacket.createInteractionPacket(p_105228_, p_105227_.isShiftKeyDown(), p_105229_));
|
||||
@@ -160,7 +160,7 @@
|
||||
return (InteractionResult)(this.localPlayerMode == GameType.SPECTATOR ? InteractionResult.PASS : p_105227_.interactOn(p_105228_, p_105229_));
|
||||
}
|
||||
|
||||
@@ -407,6 +_,10 @@
|
||||
@@ -408,6 +_,10 @@
|
||||
this.ensureHasSentCarriedItem();
|
||||
Vec3 vec3 = p_105233_.getLocation().subtract(p_105232_.getX(), p_105232_.getY(), p_105232_.getZ());
|
||||
this.connection.send(ServerboundInteractPacket.createInteractionPacket(p_105232_, p_105231_.isShiftKeyDown(), p_105234_, vec3));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/multiplayer/PlayerInfo.java
|
||||
+++ b/net/minecraft/client/multiplayer/PlayerInfo.java
|
||||
@@ -86,6 +_,7 @@
|
||||
@@ -88,6 +_,7 @@
|
||||
}
|
||||
|
||||
protected void setGameMode(GameType p_105318_) {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/net/minecraft/client/particle/BreakingItemParticle.java
|
||||
+++ b/net/minecraft/client/particle/BreakingItemParticle.java
|
||||
@@ -33,7 +_,7 @@
|
||||
|
||||
protected BreakingItemParticle(ClientLevel p_105665_, double p_105666_, double p_105667_, double p_105668_, ItemStack p_105669_) {
|
||||
super(p_105665_, p_105666_, p_105667_, p_105668_, 0.0, 0.0, 0.0);
|
||||
- this.setSprite(Minecraft.getInstance().getItemRenderer().getModel(p_105669_, p_105665_, null, 0).getParticleIcon());
|
||||
+ this.setSprite(Minecraft.getInstance().getItemRenderer().getModel(p_105669_, p_105665_, null, 0).getParticleIcon(net.minecraftforge.client.model.data.ModelData.EMPTY));
|
||||
this.gravity = 1.0F;
|
||||
this.quadSize /= 2.0F;
|
||||
this.uo = this.random.nextFloat() * 3.0F;
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/particle/Particle.java
|
||||
+++ b/net/minecraft/client/particle/Particle.java
|
||||
@@ -243,6 +_,18 @@
|
||||
@@ -248,6 +_,18 @@
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
--- a/net/minecraft/client/particle/ParticleEngine.java
|
||||
+++ b/net/minecraft/client/particle/ParticleEngine.java
|
||||
@@ -77,11 +_,11 @@
|
||||
ParticleRenderType.TERRAIN_SHEET, ParticleRenderType.PARTICLE_SHEET_OPAQUE, ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT, ParticleRenderType.CUSTOM
|
||||
);
|
||||
@@ -72,11 +_,11 @@
|
||||
private static final int MAX_PARTICLES_PER_LAYER = 16384;
|
||||
private static final List<ParticleRenderType> RENDER_ORDER = List.of(ParticleRenderType.TERRAIN_SHEET, ParticleRenderType.PARTICLE_SHEET_OPAQUE, ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT);
|
||||
protected ClientLevel level;
|
||||
- private final Map<ParticleRenderType, Queue<Particle>> particles = Maps.newIdentityHashMap();
|
||||
+ private final Map<ParticleRenderType, Queue<Particle>> particles = Maps.newTreeMap(net.minecraftforge.client.ForgeHooksClient.makeParticleRenderTypeComparator(RENDER_ORDER));
|
||||
@@ -14,7 +14,7 @@
|
||||
private final Queue<Particle> particlesToAdd = Queues.newArrayDeque();
|
||||
private final Map<ResourceLocation, ParticleEngine.MutableSpriteSet> spriteSets = Maps.newHashMap();
|
||||
private final TextureAtlas textureAtlas;
|
||||
@@ -214,10 +_,14 @@
|
||||
@@ -205,10 +_,14 @@
|
||||
this.register(ParticleTypes.BLOCK_CRUMBLE, new TerrainParticle.CrumblingProvider());
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
public <T extends ParticleOptions> void register(ParticleType<T> p_273423_, ParticleProvider.Sprite<T> p_273134_) {
|
||||
this.register(
|
||||
p_273423_,
|
||||
@@ -234,10 +_,12 @@
|
||||
@@ -225,10 +_,12 @@
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -357,7 +_,7 @@
|
||||
@@ -348,7 +_,7 @@
|
||||
private <T extends ParticleOptions> Particle makeParticle(
|
||||
T p_107396_, double p_107397_, double p_107398_, double p_107399_, double p_107400_, double p_107401_, double p_107402_
|
||||
) {
|
||||
@@ -53,35 +53,61 @@
|
||||
return particleprovider == null
|
||||
? null
|
||||
: particleprovider.createParticle(p_107396_, this.level, p_107397_, p_107398_, p_107399_, p_107400_, p_107401_, p_107402_);
|
||||
@@ -433,17 +_,26 @@
|
||||
@@ -424,28 +_,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
+ /**@deprecated Forge: use {@link #render(LightTexture, Camera, float, net.minecraft.client.renderer.culling.Frustum)} with Frustum as additional parameter*/
|
||||
+ /**@deprecated Forge: use {@link #render(Camera, float, net.minecraft.client.renderer.culling.Frustum)} with Frustum as additional parameter*/
|
||||
+ @Deprecated
|
||||
public void render(LightTexture p_107339_, Camera p_107340_, float p_107341_) {
|
||||
+ render(p_107339_, p_107340_, p_107341_, null);
|
||||
public void render(Camera p_107340_, float p_107341_, MultiBufferSource.BufferSource p_377798_) {
|
||||
- for (ParticleRenderType particlerendertype : RENDER_ORDER) {
|
||||
+ render(p_107340_, p_107341_, p_377798_, null);
|
||||
+ }
|
||||
+
|
||||
+ public void render(LightTexture p_107339_, Camera p_107340_, float p_107341_, @Nullable net.minecraft.client.renderer.culling.Frustum frustum) {
|
||||
p_107339_.turnOnLightLayer();
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
- for (ParticleRenderType particlerendertype : RENDER_ORDER) {
|
||||
+ public void render(Camera p_107340_, float p_107341_, MultiBufferSource.BufferSource p_377798_, @Nullable net.minecraft.client.renderer.culling.Frustum frustum) {
|
||||
+ for (ParticleRenderType particlerendertype : this.particles.keySet()) { // Forge: allow custom IParticleRenderType's
|
||||
+ if (particlerendertype == ParticleRenderType.NO_RENDER) continue;
|
||||
+ if (particlerendertype.renderType() == null) continue;
|
||||
Queue<Particle> queue = this.particles.get(particlerendertype);
|
||||
if (queue != null && !queue.isEmpty()) {
|
||||
Tesselator tesselator = Tesselator.getInstance();
|
||||
BufferBuilder bufferbuilder = particlerendertype.begin(tesselator, this.textureManager);
|
||||
if (bufferbuilder != null) {
|
||||
for (Particle particle : queue) {
|
||||
+ if (frustum != null && particle.shouldCull() && !frustum.isVisible(particle.getBoundingBox())) continue;
|
||||
try {
|
||||
particle.render(bufferbuilder, p_107340_, p_107341_);
|
||||
} catch (Throwable throwable) {
|
||||
@@ -475,7 +_,7 @@
|
||||
- renderParticleType(p_107340_, p_107341_, p_377798_, particlerendertype, queue);
|
||||
+ renderParticleType(p_107340_, p_107341_, p_377798_, particlerendertype, queue, frustum);
|
||||
}
|
||||
}
|
||||
|
||||
Queue<Particle> queue1 = this.particles.get(ParticleRenderType.CUSTOM);
|
||||
if (queue1 != null && !queue1.isEmpty()) {
|
||||
- renderCustomParticles(p_107340_, p_107341_, p_377798_, queue1);
|
||||
+ renderCustomParticles(p_107340_, p_107341_, p_377798_, queue1, frustum);
|
||||
}
|
||||
|
||||
p_377798_.endBatch();
|
||||
}
|
||||
|
||||
private static void renderParticleType(
|
||||
- Camera p_376120_, float p_375470_, MultiBufferSource.BufferSource p_377543_, ParticleRenderType p_378369_, Queue<Particle> p_376283_
|
||||
+ Camera p_376120_, float p_375470_, MultiBufferSource.BufferSource p_377543_, ParticleRenderType p_378369_, Queue<Particle> p_376283_, @Nullable net.minecraft.client.renderer.culling.Frustum frustum
|
||||
) {
|
||||
VertexConsumer vertexconsumer = p_377543_.getBuffer(Objects.requireNonNull(p_378369_.renderType()));
|
||||
|
||||
for (Particle particle : p_376283_) {
|
||||
+ if (frustum != null && particle.shouldCull() && !frustum.isVisible(particle.getBoundingBox())) continue;
|
||||
try {
|
||||
particle.render(vertexconsumer, p_376120_, p_375470_);
|
||||
} catch (Throwable throwable) {
|
||||
@@ -458,10 +_,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
- private static void renderCustomParticles(Camera p_377913_, float p_376893_, MultiBufferSource.BufferSource p_376978_, Queue<Particle> p_375784_) {
|
||||
+ private static void renderCustomParticles(Camera p_377913_, float p_376893_, MultiBufferSource.BufferSource p_376978_, Queue<Particle> p_375784_, @Nullable net.minecraft.client.renderer.culling.Frustum frustum) {
|
||||
PoseStack posestack = new PoseStack();
|
||||
|
||||
for (Particle particle : p_375784_) {
|
||||
+ if (frustum != null && particle.shouldCull() && !frustum.isVisible(particle.getBoundingBox())) continue;
|
||||
try {
|
||||
particle.renderCustom(posestack, p_376978_, p_377913_, p_376893_);
|
||||
} catch (Throwable throwable) {
|
||||
@@ -481,7 +_,7 @@
|
||||
}
|
||||
|
||||
public void destroy(BlockPos p_107356_, BlockState p_107357_) {
|
||||
@@ -90,7 +116,7 @@
|
||||
VoxelShape voxelshape = p_107357_.getShape(this.level, p_107356_);
|
||||
double d0 = 0.25;
|
||||
voxelshape.forAllBoxes(
|
||||
@@ -508,6 +_,7 @@
|
||||
@@ -514,6 +_,7 @@
|
||||
p_107357_,
|
||||
p_107356_
|
||||
)
|
||||
@@ -98,7 +124,7 @@
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -517,6 +_,13 @@
|
||||
@@ -523,6 +_,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +138,7 @@
|
||||
public void crack(BlockPos p_107368_, Direction p_107369_) {
|
||||
BlockState blockstate = this.level.getBlockState(p_107368_);
|
||||
if (blockstate.getRenderShape() != RenderShape.INVISIBLE && blockstate.shouldSpawnTerrainParticles()) {
|
||||
@@ -552,7 +_,7 @@
|
||||
@@ -558,7 +_,7 @@
|
||||
d0 = (double)i + aabb.maxX + 0.1F;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/player/LocalPlayer.java
|
||||
+++ b/net/minecraft/client/player/LocalPlayer.java
|
||||
@@ -303,6 +_,7 @@
|
||||
@@ -308,6 +_,7 @@
|
||||
ServerboundPlayerActionPacket.Action serverboundplayeractionpacket$action = p_108701_
|
||||
? ServerboundPlayerActionPacket.Action.DROP_ALL_ITEMS
|
||||
: ServerboundPlayerActionPacket.Action.DROP_ITEM;
|
||||
@@ -8,7 +8,7 @@
|
||||
ItemStack itemstack = this.getInventory().removeFromSelected(p_108701_);
|
||||
this.connection.send(new ServerboundPlayerActionPacket(serverboundplayeractionpacket$action, BlockPos.ZERO, Direction.DOWN));
|
||||
return !itemstack.isEmpty();
|
||||
@@ -488,7 +_,11 @@
|
||||
@@ -493,7 +_,11 @@
|
||||
|
||||
@Override
|
||||
public void playSound(SoundEvent p_108651_, float p_108652_, float p_108653_) {
|
||||
@@ -21,43 +21,43 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -682,6 +_,7 @@
|
||||
@@ -686,6 +_,7 @@
|
||||
&& this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.CROUCHING)
|
||||
&& (this.isShiftKeyDown() || !this.isSleeping() && !this.canPlayerFitWithinBlocksAndEntitiesWhen(Pose.STANDING));
|
||||
float f = (float)this.getAttributeValue(Attributes.SNEAKING_SPEED);
|
||||
this.input.tick(this.isMovingSlowly(), f);
|
||||
this.input.tick();
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onMovementInputUpdate(this, this.input);
|
||||
this.minecraft.getTutorial().onInput(this.input);
|
||||
if (this.isUsingItem() && !this.isPassenger()) {
|
||||
this.input.leftImpulse *= 0.2F;
|
||||
@@ -710,7 +_,7 @@
|
||||
boolean flag4 = this.canStartSprinting();
|
||||
boolean flag5 = this.isPassenger() ? this.getVehicle().onGround() : this.onGround();
|
||||
boolean flag6 = !flag1 && !flag2;
|
||||
- if ((flag5 || this.isUnderWater()) && flag6 && flag4) {
|
||||
+ if ((flag5 || this.isUnderWater() || this.canStartSwimming()) && flag6 && flag4) {
|
||||
if (this.shouldStopSprinting()) {
|
||||
this.setSprinting(false);
|
||||
@@ -724,7 +_,7 @@
|
||||
boolean flag3 = this.canStartSprinting();
|
||||
boolean flag4 = this.isPassenger() ? this.getVehicle().onGround() : this.onGround();
|
||||
boolean flag5 = !flag1 && !flag2;
|
||||
- if ((flag4 || this.isUnderWater()) && flag5 && flag3) {
|
||||
+ if ((flag4 || this.isUnderWater() || this.canStartSwimming()) && flag5 && flag3) {
|
||||
if (this.sprintTriggerTime <= 0 && !this.minecraft.options.keySprint.isDown()) {
|
||||
this.sprintTriggerTime = 7;
|
||||
} else {
|
||||
@@ -718,15 +_,15 @@
|
||||
@@ -732,15 +_,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
- if ((!this.isInWater() || this.isUnderWater()) && flag4 && this.minecraft.options.keySprint.isDown()) {
|
||||
+ if (!this.isSprinting() && (!(this.isInWater() || this.isInFluidType((fluidType, height) -> this.canSwimInFluidType(fluidType))) || (this.isUnderWater() || this.canStartSwimming())) && this.hasEnoughImpulseToStartSprinting() && flag4 && !this.isUsingItem() && !this.hasEffect(MobEffects.BLINDNESS) && this.minecraft.options.keySprint.isDown()) {
|
||||
- if ((!this.isInWater() || this.isUnderWater()) && flag3 && this.minecraft.options.keySprint.isDown()) {
|
||||
+ if ((!this.isInWaterOrSwimmable() || this.isUnderWater() || this.canStartSwimming()) && flag3 && this.minecraft.options.keySprint.isDown()) {
|
||||
this.setSprinting(true);
|
||||
}
|
||||
|
||||
if (this.isSprinting()) {
|
||||
boolean flag7 = !this.input.hasForwardImpulse() || !this.hasEnoughFoodToStartSprinting();
|
||||
- boolean flag8 = flag7 || this.horizontalCollision && !this.minorHorizontalCollision || this.isInWater() && !this.isUnderWater();
|
||||
+ boolean flag8 = flag7 || this.horizontalCollision && !this.minorHorizontalCollision || this.isInWater() && !this.isUnderWater() || (this.isInFluidType((fluidType, height) -> this.canSwimInFluidType(fluidType)) && !this.canStartSwimming());
|
||||
boolean flag6 = !this.input.hasForwardImpulse() || !this.hasEnoughFoodToStartSprinting();
|
||||
boolean flag7 = flag6 || this.horizontalCollision && !this.minorHorizontalCollision || this.isInWater() && !this.isUnderWater();
|
||||
+ flag7 = flag7 || (this.isInFluidType((fluidType, height) -> this.canSwimInFluidType(fluidType)) && !this.canStartSwimming());
|
||||
if (this.isSwimming()) {
|
||||
- if (!this.onGround() && !this.input.keyPresses.shift() && flag7 || !this.isInWater()) {
|
||||
+ if (!this.onGround() && !this.input.keyPresses.shift() && flag7 || !(this.isInWater() || this.isInFluidType((fluidType, height) -> this.canSwimInFluidType(fluidType)))) {
|
||||
- if (!this.onGround() && !this.input.keyPresses.shift() && flag6 || !this.isInWater()) {
|
||||
+ if (!this.onGround() && !this.input.keyPresses.shift() && flag7 || !this.isInWaterOrSwimmable()) {
|
||||
this.setSprinting(false);
|
||||
}
|
||||
} else if (flag8) {
|
||||
@@ -763,8 +_,9 @@
|
||||
} else if (flag7) {
|
||||
@@ -777,8 +_,9 @@
|
||||
}
|
||||
|
||||
this.wasFallFlying = this.isFallFlying();
|
||||
@@ -69,7 +69,7 @@
|
||||
}
|
||||
|
||||
if (this.isEyeInFluid(FluidTags.WATER)) {
|
||||
@@ -870,6 +_,8 @@
|
||||
@@ -900,6 +_,8 @@
|
||||
@Override
|
||||
public void rideTick() {
|
||||
super.rideTick();
|
||||
@@ -78,7 +78,7 @@
|
||||
this.handsBusy = false;
|
||||
if (this.getControlledVehicle() instanceof AbstractBoat abstractboat) {
|
||||
abstractboat.setInput(
|
||||
@@ -1146,6 +_,18 @@
|
||||
@@ -1177,6 +_,18 @@
|
||||
@Override
|
||||
public float getVisualRotationYInDegrees() {
|
||||
return this.getYRot();
|
||||
|
||||
@@ -11,15 +11,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,8 +_,11 @@
|
||||
@@ -171,8 +_,13 @@
|
||||
if (!(f < 1.0F)) {
|
||||
PostChain postchain = this.minecraft.getShaderManager().getPostChain(BLUR_POST_CHAIN_ID, LevelTargetBundle.MAIN_TARGETS);
|
||||
if (postchain != null) {
|
||||
+ // FORGE: Blending the blur was removed in 1.21. This is necessary for screen layering to work properly. https://github.com/MinecraftForge/MinecraftForge/issues/10114
|
||||
+ RenderSystem.enableBlend();
|
||||
+ boolean wasBlendEnabled = RenderSystem.isBlendEnabled();
|
||||
+ if (wasBlendEnabled)
|
||||
+ RenderSystem.disableBlend();
|
||||
postchain.setUniform("Radius", f);
|
||||
postchain.process(this.minecraft.getMainRenderTarget(), this.resourcePool);
|
||||
+ RenderSystem.disableBlend();
|
||||
+ if (wasBlendEnabled)
|
||||
+ RenderSystem.enableBlend();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +34,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,12 +_,12 @@
|
||||
@@ -470,12 +_,12 @@
|
||||
(float)((double)window.getHeight() / window.getGuiScale()),
|
||||
0.0F,
|
||||
1000.0F,
|
||||
@@ -47,7 +49,7 @@
|
||||
Lighting.setupFor3DItems();
|
||||
GuiGraphics guigraphics = new GuiGraphics(this.minecraft, this.renderBuffers.bufferSource());
|
||||
if (flag && p_109096_ && this.minecraft.level != null) {
|
||||
@@ -499,7 +_,7 @@
|
||||
@@ -501,7 +_,7 @@
|
||||
}
|
||||
} else if (flag && this.minecraft.screen != null) {
|
||||
try {
|
||||
@@ -56,7 +58,7 @@
|
||||
} catch (Throwable throwable1) {
|
||||
CrashReport crashreport1 = CrashReport.forThrowable(throwable1, "Rendering screen");
|
||||
CrashReportCategory crashreportcategory1 = crashreport1.addCategory("Screen render details");
|
||||
@@ -655,6 +_,9 @@
|
||||
@@ -657,6 +_,9 @@
|
||||
if (this.minecraft.options.bobView().get()) {
|
||||
this.bobView(posestack, camera.getPartialTickTime());
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ItemBlockRenderTypes {
|
||||
+ @Deprecated
|
||||
private static final Map<Block, RenderType> TYPE_BY_BLOCK = Util.make(Maps.newHashMap(), p_357825_ -> {
|
||||
private static final Map<Block, RenderType> TYPE_BY_BLOCK = Util.make(Maps.newHashMap(), p_374604_ -> {
|
||||
RenderType rendertype = RenderType.tripwire();
|
||||
p_357825_.put(Blocks.TRIPWIRE, rendertype);
|
||||
@@ -340,6 +_,7 @@
|
||||
p_357825_.put(Blocks.BUBBLE_COLUMN, rendertype3);
|
||||
p_357825_.put(Blocks.TINTED_GLASS, rendertype3);
|
||||
p_374604_.put(Blocks.TRIPWIRE, rendertype);
|
||||
@@ -345,6 +_,7 @@
|
||||
p_374604_.put(Blocks.BUBBLE_COLUMN, rendertype3);
|
||||
p_374604_.put(Blocks.TINTED_GLASS, rendertype3);
|
||||
});
|
||||
+ @Deprecated
|
||||
private static final Map<Fluid, RenderType> TYPE_BY_FLUID = Util.make(Maps.newHashMap(), p_109290_ -> {
|
||||
RenderType rendertype = RenderType.translucent();
|
||||
p_109290_.put(Fluids.FLOWING_WATER, rendertype);
|
||||
@@ -347,6 +_,8 @@
|
||||
@@ -352,6 +_,8 @@
|
||||
});
|
||||
private static boolean renderCutout;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
public static RenderType getChunkRenderType(BlockState p_109283_) {
|
||||
Block block = p_109283_.getBlock();
|
||||
if (block instanceof LeavesBlock) {
|
||||
@@ -357,6 +_,8 @@
|
||||
@@ -362,6 +_,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,21 +34,26 @@
|
||||
public static RenderType getMovingBlockRenderType(BlockState p_109294_) {
|
||||
Block block = p_109294_.getBlock();
|
||||
if (block instanceof LeavesBlock) {
|
||||
@@ -371,6 +_,8 @@
|
||||
@@ -376,11 +_,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /** @deprecated Forge: Use {@link net.minecraftforge.client.RenderTypeHelper#getEntityRenderType(RenderType, boolean)} while iterating through {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */
|
||||
+ /** @deprecated Forge: Use {@link net.minecraftforge.client.RenderTypeHelper#getEntityRenderType(RenderType)} while iterating through {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */
|
||||
+ @Deprecated // Note: this method does NOT support model-based render types
|
||||
public static RenderType getRenderType(BlockState p_364446_) {
|
||||
RenderType rendertype = getChunkRenderType(p_364446_);
|
||||
return rendertype == RenderType.translucent() ? Sheets.translucentItemSheet() : Sheets.cutoutBlockSheet();
|
||||
@@ -385,12 +_,77 @@
|
||||
}
|
||||
|
||||
+ /* Forge: Use {@link net.minecraft.client.resources.model.BakedModel#getRenderPasses(ItemStack, boolean)} and {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(ItemStack, boolean)}. */
|
||||
public static RenderType getRenderType(ItemStack p_363859_) {
|
||||
if (p_363859_.getItem() instanceof BlockItem blockitem) {
|
||||
Block block = blockitem.getBlock();
|
||||
@@ -390,12 +_,81 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /** @deprecated Forge: Use {@link net.minecraft.client.resources.model.BakedModel#getRenderPasses(ItemStack, boolean)} and {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(ItemStack, boolean)}. */
|
||||
+ @Deprecated // Note: this method does NOT support model-based render types
|
||||
+ // Note: this method does NOT support model-based render types
|
||||
public static RenderType getRenderLayer(FluidState p_109288_) {
|
||||
- RenderType rendertype = TYPE_BY_FLUID.get(p_109288_.getType());
|
||||
+ RenderType rendertype = FLUID_RENDER_TYPES.get(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(p_109288_.getType()));
|
||||
@@ -59,6 +64,11 @@
|
||||
renderCutout = p_109292_;
|
||||
+ }
|
||||
+
|
||||
+ /** Forge: Check if we are running in {@linkplain net.minecraft.client.Minecraft#useFancyGraphics() fancy graphics} to account for fast graphics render types */
|
||||
+ public static boolean isFancy() {
|
||||
+ return renderCutout;
|
||||
+ }
|
||||
+
|
||||
+ private static final net.minecraftforge.client.ChunkRenderTypeSet CUTOUT_MIPPED = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.cutoutMipped());
|
||||
+ private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.solid());
|
||||
+ private static final Map<net.minecraft.core.Holder.Reference<Block>, net.minecraftforge.client.ChunkRenderTypeSet> BLOCK_RENDER_TYPES = Util.make(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(TYPE_BY_BLOCK.size(), 0.5F), map -> {
|
||||
@@ -75,7 +85,7 @@
|
||||
+ });
|
||||
+
|
||||
+ /** @deprecated Use {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */
|
||||
+ //@Deprecated(since = "1.19", forRemoval = true)
|
||||
+ @Deprecated(forRemoval = true, since = "1.21.4")
|
||||
+ public static net.minecraftforge.client.ChunkRenderTypeSet getRenderLayers(BlockState state) {
|
||||
+ Block block = state.getBlock();
|
||||
+ if (block instanceof LeavesBlock) {
|
||||
@@ -86,20 +96,20 @@
|
||||
+ }
|
||||
+
|
||||
+ /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
|
||||
+ //@Deprecated(since = "1.19", forRemoval = true)
|
||||
+ @Deprecated(forRemoval = true, since = "1.21.4")
|
||||
+ public static void setRenderLayer(Block block, RenderType type) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers().");
|
||||
+ setRenderLayer(block, net.minecraftforge.client.ChunkRenderTypeSet.of(type));
|
||||
+ }
|
||||
+
|
||||
+ /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
|
||||
+ //@Deprecated(since = "1.19", forRemoval = true)
|
||||
+ @Deprecated(forRemoval = true, since = "1.21.4")
|
||||
+ public static synchronized void setRenderLayer(Block block, java.util.function.Predicate<RenderType> predicate) {
|
||||
+ setRenderLayer(block, createSetFromPredicate(predicate));
|
||||
+ }
|
||||
+
|
||||
+ /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */
|
||||
+ //@Deprecated(since = "1.19", forRemoval = true)
|
||||
+ @Deprecated(forRemoval = true, since = "1.21.4")
|
||||
+ public static synchronized void setRenderLayer(Block block, net.minecraftforge.client.ChunkRenderTypeSet layers) {
|
||||
+ checkClientLoading();
|
||||
+ BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/renderer/ItemInHandRenderer.java
|
||||
+++ b/net/minecraft/client/renderer/ItemInHandRenderer.java
|
||||
@@ -339,12 +_,14 @@
|
||||
@@ -343,12 +_,14 @@
|
||||
if (iteminhandrenderer$handrenderselection.renderMainHand) {
|
||||
float f4 = interactionhand == InteractionHand.MAIN_HAND ? f : 0.0F;
|
||||
float f5 = 1.0F - Mth.lerp(p_109315_, this.oMainHandHeight, this.mainHandHeight);
|
||||
@@ -15,7 +15,7 @@
|
||||
this.renderArmWithItem(p_109318_, p_109315_, f1, InteractionHand.OFF_HAND, f6, this.offHandItem, f7, p_109316_, p_109317_, p_109319_);
|
||||
}
|
||||
|
||||
@@ -410,7 +_,7 @@
|
||||
@@ -414,7 +_,7 @@
|
||||
} else {
|
||||
this.renderOneHandedMap(p_109379_, p_109380_, p_109381_, p_109378_, humanoidarm, p_109376_, p_109377_);
|
||||
}
|
||||
@@ -25,19 +25,20 @@
|
||||
boolean flag2 = humanoidarm == HumanoidArm.RIGHT;
|
||||
int i = flag2 ? 1 : -1;
|
||||
@@ -460,6 +_,7 @@
|
||||
);
|
||||
} else {
|
||||
boolean flag3 = humanoidarm == HumanoidArm.RIGHT;
|
||||
int j = flag3 ? 1 : -1;
|
||||
+ if (!net.minecraftforge.client.extensions.common.IClientItemExtensions.of(p_109377_).applyForgeHandTransform(p_109379_, minecraft.player, humanoidarm, p_109377_, p_109373_, p_109378_, p_109376_)) // FORGE: Allow items to define custom arm animation
|
||||
if (p_109372_.isUsingItem() && p_109372_.getUseItemRemainingTicks() > 0 && p_109372_.getUsedItemHand() == p_109375_) {
|
||||
int k = flag3 ? 1 : -1;
|
||||
switch (p_109377_.getUseAnimation()) {
|
||||
@@ -574,8 +_,16 @@
|
||||
case NONE:
|
||||
@@ -588,8 +_,18 @@
|
||||
this.offHandHeight = Mth.clamp(this.offHandHeight - 0.4F, 0.0F, 1.0F);
|
||||
} else {
|
||||
float f = localplayer.getAttackStrengthScale(1.0F);
|
||||
- this.mainHandHeight = this.mainHandHeight + Mth.clamp((this.mainHandItem == itemstack ? f * f * f : 0.0F) - this.mainHandHeight, -0.4F, 0.4F);
|
||||
- this.offHandHeight = this.offHandHeight + Mth.clamp((float)(this.offHandItem == itemstack1 ? 1 : 0) - this.offHandHeight, -0.4F, 0.4F);
|
||||
- float f1 = this.mainHandItem != itemstack ? 0.0F : f * f * f;
|
||||
- float f2 = this.offHandItem != itemstack1 ? 0.0F : 1.0F;
|
||||
+
|
||||
+ boolean requipM = net.minecraftforge.client.ForgeHooksClient.shouldCauseReequipAnimation(this.mainHandItem, itemstack, localplayer.getInventory().selected);
|
||||
+ boolean requipO = net.minecraftforge.client.ForgeHooksClient.shouldCauseReequipAnimation(this.offHandItem, itemstack1, -1);
|
||||
+
|
||||
@@ -46,8 +47,9 @@
|
||||
+ if (!requipO && this.offHandItem != itemstack1)
|
||||
+ this.offHandItem = itemstack1;
|
||||
+
|
||||
+ this.mainHandHeight += Mth.clamp((!requipM ? f * f * f : 0.0F) - this.mainHandHeight, -0.4F, 0.4F);
|
||||
+ this.offHandHeight += Mth.clamp((float)(!requipO ? 1 : 0) - this.offHandHeight, -0.4F, 0.4F);
|
||||
+ float f1 = requipM ? 0.0F : f * f * f;
|
||||
+ float f2 = requipO ? 0.0F : 1.0F;
|
||||
+
|
||||
this.mainHandHeight = this.mainHandHeight + Mth.clamp(f1 - this.mainHandHeight, -0.4F, 0.4F);
|
||||
this.offHandHeight = this.offHandHeight + Mth.clamp(f2 - this.offHandHeight, -0.4F, 0.4F);
|
||||
}
|
||||
|
||||
if (this.mainHandHeight < 0.1F) {
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/renderer/LevelRenderer.java
|
||||
+++ b/net/minecraft/client/renderer/LevelRenderer.java
|
||||
@@ -111,7 +_,7 @@
|
||||
@@ -109,7 +_,7 @@
|
||||
private final SkyRenderer skyRenderer = new SkyRenderer();
|
||||
private final CloudRenderer cloudRenderer = new CloudRenderer();
|
||||
private final WorldBorderRenderer worldBorderRenderer = new WorldBorderRenderer();
|
||||
@@ -9,16 +9,16 @@
|
||||
@Nullable
|
||||
private ClientLevel level;
|
||||
private final SectionOcclusionGraph sectionOcclusionGraph = new SectionOcclusionGraph();
|
||||
@@ -487,7 +_,7 @@
|
||||
@@ -482,7 +_,7 @@
|
||||
postchain1.addToFrame(framegraphbuilder, i, j, this.targets);
|
||||
}
|
||||
|
||||
- this.addParticlesPass(framegraphbuilder, p_109604_, p_109606_, f, fogparameters);
|
||||
+ this.addParticlesPass(framegraphbuilder, p_109604_, p_109606_, f, fogparameters, frustum);
|
||||
- this.addParticlesPass(framegraphbuilder, p_109604_, f, fogparameters);
|
||||
+ this.addParticlesPass(framegraphbuilder, p_109604_, f, fogparameters, frustum);
|
||||
CloudStatus cloudstatus = this.minecraft.options.getCloudsType();
|
||||
if (cloudstatus != CloudStatus.OFF) {
|
||||
float f2 = this.level.effects().getCloudHeight();
|
||||
@@ -569,7 +_,11 @@
|
||||
@@ -564,7 +_,11 @@
|
||||
double d2 = vec3.z();
|
||||
p_369478_.push("terrain");
|
||||
this.renderSectionLayer(RenderType.solid(), d0, d1, d2, p_361439_, p_369924_);
|
||||
@@ -30,7 +30,7 @@
|
||||
this.renderSectionLayer(RenderType.cutout(), d0, d1, d2, p_361439_, p_369924_);
|
||||
if (this.level.effects().constantAmbientLight()) {
|
||||
Lighting.setupNetherLevel();
|
||||
@@ -603,7 +_,7 @@
|
||||
@@ -598,7 +_,7 @@
|
||||
multibuffersource$buffersource.endLastBatch();
|
||||
this.checkPoseStack(posestack);
|
||||
p_369478_.popPush("blockentities");
|
||||
@@ -39,7 +39,7 @@
|
||||
multibuffersource$buffersource.endLastBatch();
|
||||
this.checkPoseStack(posestack);
|
||||
multibuffersource$buffersource.endBatch(RenderType.solid());
|
||||
@@ -617,8 +_,8 @@
|
||||
@@ -612,8 +_,8 @@
|
||||
multibuffersource$buffersource.endBatch(Sheets.hangingSignSheet());
|
||||
multibuffersource$buffersource.endBatch(Sheets.chestSheet());
|
||||
this.renderBuffers.outlineBufferSource().endOutlineBatch();
|
||||
@@ -50,7 +50,7 @@
|
||||
}
|
||||
|
||||
p_369478_.popPush("debug");
|
||||
@@ -648,8 +_,8 @@
|
||||
@@ -643,8 +_,8 @@
|
||||
this.renderSectionLayer(RenderType.translucent(), d0, d1, d2, p_361439_, p_369924_);
|
||||
p_369478_.popPush("string");
|
||||
this.renderSectionLayer(RenderType.tripwire(), d0, d1, d2, p_361439_, p_369924_);
|
||||
@@ -61,25 +61,25 @@
|
||||
}
|
||||
|
||||
multibuffersource$buffersource.endBatch();
|
||||
@@ -657,7 +_,7 @@
|
||||
@@ -652,7 +_,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
- private void addParticlesPass(FrameGraphBuilder p_366471_, Camera p_363128_, LightTexture p_366434_, float p_365755_, FogParameters p_363695_) {
|
||||
+ private void addParticlesPass(FrameGraphBuilder p_366471_, Camera p_363128_, LightTexture p_366434_, float p_365755_, FogParameters p_363695_, Frustum frustum) {
|
||||
- private void addParticlesPass(FrameGraphBuilder p_366471_, Camera p_363128_, float p_365755_, FogParameters p_363695_) {
|
||||
+ private void addParticlesPass(FrameGraphBuilder p_366471_, Camera p_363128_, float p_365755_, FogParameters p_363695_, Frustum frustum) {
|
||||
FramePass framepass = p_366471_.addPass("particles");
|
||||
if (this.targets.particles != null) {
|
||||
this.targets.particles = framepass.readsAndWrites(this.targets.particles);
|
||||
@@ -677,7 +_,7 @@
|
||||
@@ -671,7 +_,7 @@
|
||||
resourcehandle1.get().copyDepthFrom(resourcehandle.get());
|
||||
}
|
||||
|
||||
RenderStateShard.PARTICLES_TARGET.setupRenderState();
|
||||
- this.minecraft.particleEngine.render(p_366434_, p_363128_, p_365755_);
|
||||
+ this.minecraft.particleEngine.render(p_366434_, p_363128_, p_365755_, frustum);
|
||||
RenderStateShard.PARTICLES_TARGET.clearRenderState();
|
||||
- this.minecraft.particleEngine.render(p_363128_, p_365755_, this.renderBuffers.bufferSource());
|
||||
+ this.minecraft.particleEngine.render(p_363128_, p_365755_, this.renderBuffers.bufferSource(), frustum);
|
||||
});
|
||||
}
|
||||
@@ -766,9 +_,9 @@
|
||||
|
||||
@@ -759,9 +_,9 @@
|
||||
|| p_365712_.isDetached()
|
||||
|| p_365712_.getEntity() instanceof LivingEntity && ((LivingEntity)p_365712_.getEntity()).isSleeping()
|
||||
)
|
||||
@@ -91,7 +91,7 @@
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
@@ -808,9 +_,10 @@
|
||||
@@ -801,9 +_,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
Vec3 vec3 = p_369847_.getPosition();
|
||||
double d0 = vec3.x();
|
||||
double d1 = vec3.y();
|
||||
@@ -820,6 +_,7 @@
|
||||
@@ -813,6 +_,7 @@
|
||||
List<BlockEntity> list = sectionrenderdispatcher$rendersection.getCompiled().getRenderableBlockEntities();
|
||||
if (!list.isEmpty()) {
|
||||
for (BlockEntity blockentity : list) {
|
||||
@@ -112,7 +112,7 @@
|
||||
BlockPos blockpos = blockentity.getBlockPos();
|
||||
MultiBufferSource multibuffersource = p_362022_;
|
||||
p_366168_.pushPose();
|
||||
@@ -839,6 +_,9 @@
|
||||
@@ -832,6 +_,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
this.blockEntityRenderDispatcher.render(blockentity, p_367074_, p_366168_, multibuffersource);
|
||||
p_366168_.popPose();
|
||||
}
|
||||
@@ -847,13 +_,18 @@
|
||||
@@ -840,13 +_,18 @@
|
||||
|
||||
synchronized (this.globalBlockEntities) {
|
||||
for (BlockEntity blockentity1 : this.globalBlockEntities) {
|
||||
@@ -141,7 +141,7 @@
|
||||
}
|
||||
|
||||
private void renderBlockDestroyAnimation(PoseStack p_366956_, Camera p_369324_, MultiBufferSource.BufferSource p_365998_) {
|
||||
@@ -872,14 +_,14 @@
|
||||
@@ -865,14 +_,14 @@
|
||||
p_366956_.translate((double)blockpos.getX() - d0, (double)blockpos.getY() - d1, (double)blockpos.getZ() - d2);
|
||||
PoseStack.Pose posestack$pose = p_366956_.last();
|
||||
VertexConsumer vertexconsumer = new SheetedDecalTextureGenerator(p_365998_.getBuffer(ModelBakery.DESTROY_TYPES.get(i)), posestack$pose, 1.0F);
|
||||
@@ -158,7 +158,7 @@
|
||||
if (this.minecraft.hitResult instanceof BlockHitResult blockhitresult) {
|
||||
if (blockhitresult.getType() != HitResult.Type.MISS) {
|
||||
BlockPos blockpos = blockhitresult.getBlockPos();
|
||||
@@ -890,6 +_,9 @@
|
||||
@@ -883,6 +_,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
Vec3 vec3 = p_367935_.getPosition();
|
||||
Boolean obool = this.minecraft.options.highContrastBlockOutline().get();
|
||||
if (obool) {
|
||||
@@ -905,6 +_,8 @@
|
||||
@@ -898,6 +_,8 @@
|
||||
p_367206_.endLastBatch();
|
||||
}
|
||||
}
|
||||
@@ -177,16 +177,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1112,7 +_,7 @@
|
||||
boolean flag = false;
|
||||
if (this.minecraft.options.prioritizeChunkUpdates().get() == PrioritizeChunkUpdates.NEARBY) {
|
||||
BlockPos blockpos1 = sectionrenderdispatcher$rendersection.getOrigin().offset(8, 8, 8);
|
||||
- flag = blockpos1.distSqr(blockpos) < 768.0 || sectionrenderdispatcher$rendersection.isDirtyFromPlayer();
|
||||
+ flag = !net.minecraftforge.common.ForgeConfig.CLIENT.alwaysSetupTerrainOffThread.get() && (blockpos1.distSqr(blockpos) < 768.0D || sectionrenderdispatcher$rendersection.isDirtyFromPlayer()); // the target is the else block below, so invert the forge addition to get there early
|
||||
} else if (this.minecraft.options.prioritizeChunkUpdates().get() == PrioritizeChunkUpdates.PLAYER_AFFECTED) {
|
||||
flag = sectionrenderdispatcher$rendersection.isDirtyFromPlayer();
|
||||
}
|
||||
@@ -1391,7 +_,7 @@
|
||||
@@ -1367,7 +_,7 @@
|
||||
} else {
|
||||
int i = p_109538_.getBrightness(LightLayer.SKY, p_109540_);
|
||||
int j = p_109538_.getBrightness(LightLayer.BLOCK, p_109540_);
|
||||
@@ -195,7 +186,7 @@
|
||||
if (j < k) {
|
||||
j = k;
|
||||
}
|
||||
@@ -1453,5 +_,21 @@
|
||||
@@ -1429,5 +_,21 @@
|
||||
|
||||
public CloudRenderer getCloudRenderer() {
|
||||
return this.cloudRenderer;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/client/renderer/RenderType.java
|
||||
+++ b/net/minecraft/client/renderer/RenderType.java
|
||||
@@ -800,11 +_,22 @@
|
||||
@@ -929,11 +_,22 @@
|
||||
.createCompositeState(false)
|
||||
);
|
||||
private static final ImmutableList<RenderType> CHUNK_BUFFER_LAYERS = ImmutableList.of(solid(), cutoutMipped(), cutout(), translucent(), tripwire());
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
public static RenderType solid() {
|
||||
return SOLID;
|
||||
@@ -1025,7 +_,7 @@
|
||||
@@ -1154,7 +_,7 @@
|
||||
}
|
||||
|
||||
public static RenderType text(ResourceLocation p_110498_) {
|
||||
@@ -32,7 +32,7 @@
|
||||
}
|
||||
|
||||
public static RenderType textBackground() {
|
||||
@@ -1033,19 +_,19 @@
|
||||
@@ -1162,19 +_,19 @@
|
||||
}
|
||||
|
||||
public static RenderType textIntensity(ResourceLocation p_173238_) {
|
||||
@@ -56,7 +56,7 @@
|
||||
}
|
||||
|
||||
public static RenderType textBackgroundSeeThrough() {
|
||||
@@ -1053,7 +_,7 @@
|
||||
@@ -1182,7 +_,7 @@
|
||||
}
|
||||
|
||||
public static RenderType textIntensitySeeThrough(ResourceLocation p_173241_) {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
--- a/net/minecraft/client/renderer/ScreenEffectRenderer.java
|
||||
+++ b/net/minecraft/client/renderer/ScreenEffectRenderer.java
|
||||
@@ -31,17 +_,24 @@
|
||||
@@ -27,17 +_,24 @@
|
||||
Player player = p_110719_.player;
|
||||
if (!player.noPhysics) {
|
||||
BlockState blockstate = getViewBlockingState(player);
|
||||
- if (blockstate != null) {
|
||||
- renderTex(p_110719_.getBlockRenderer().getBlockModelShaper().getParticleIcon(blockstate), p_110720_);
|
||||
- renderTex(p_110719_.getBlockRenderer().getBlockModelShaper().getParticleIcon(blockstate), p_110720_, p_378238_);
|
||||
+ var overlay = getOverlayBlock(player);
|
||||
+ if (overlay != null) {
|
||||
+ if (!net.minecraftforge.client.ForgeHooksClient.renderBlockOverlay(player, p_110720_, net.minecraftforge.client.event.RenderBlockScreenEffectEvent.OverlayType.BLOCK, overlay.getLeft(), overlay.getRight())) {
|
||||
+ renderTex(p_110719_.getBlockRenderer().getBlockModelShaper().getTexture(overlay.getLeft(), p_110719_.level, overlay.getRight()), p_110720_);
|
||||
+ renderTex(p_110719_.getBlockRenderer().getBlockModelShaper().getTexture(overlay.getLeft(), p_110719_.level, overlay.getRight()), p_110720_, p_378238_);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
@@ -17,17 +17,17 @@
|
||||
if (!p_110719_.player.isSpectator()) {
|
||||
if (p_110719_.player.isEyeInFluid(FluidTags.WATER)) {
|
||||
+ if (!net.minecraftforge.client.ForgeHooksClient.renderWaterOverlay(player, p_110720_))
|
||||
renderWater(p_110719_, p_110720_);
|
||||
renderWater(p_110719_, p_110720_, p_378238_);
|
||||
+ } else if (!player.getEyeInFluidType().isAir()) {
|
||||
+ net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions.of(player.getEyeInFluidType()).renderOverlay(p_110719_, p_110720_);
|
||||
+ net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions.of(player.getEyeInFluidType()).renderOverlay(p_110719_, p_110720_, p_378238_);
|
||||
}
|
||||
|
||||
if (p_110719_.player.isOnFire()) {
|
||||
+ if (!net.minecraftforge.client.ForgeHooksClient.renderFireOverlay(player, p_110720_))
|
||||
renderFire(p_110719_, p_110720_);
|
||||
renderFire(p_110720_, p_378238_);
|
||||
}
|
||||
}
|
||||
@@ -49,6 +_,12 @@
|
||||
@@ -45,6 +_,12 @@
|
||||
|
||||
@Nullable
|
||||
private static BlockState getViewBlockingState(Player p_110717_) {
|
||||
@@ -40,7 +40,7 @@
|
||||
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
@@ -58,7 +_,7 @@
|
||||
@@ -54,7 +_,7 @@
|
||||
blockpos$mutableblockpos.set(d0, d1, d2);
|
||||
BlockState blockstate = p_110717_.level().getBlockState(blockpos$mutableblockpos);
|
||||
if (blockstate.getRenderShape() != RenderShape.INVISIBLE && blockstate.isViewBlocking(p_110717_.level(), blockpos$mutableblockpos)) {
|
||||
@@ -49,17 +49,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +_,12 @@
|
||||
@@ -82,6 +_,10 @@
|
||||
}
|
||||
|
||||
private static void renderWater(Minecraft p_110726_, PoseStack p_110727_) {
|
||||
+ renderFluid(p_110726_, p_110727_, UNDERWATER_LOCATION);
|
||||
private static void renderWater(Minecraft p_110726_, PoseStack p_110727_, MultiBufferSource p_376402_) {
|
||||
+ renderFluid(p_110726_, p_110727_, p_376402_, UNDERWATER_LOCATION);
|
||||
+ }
|
||||
+
|
||||
+ public static void renderFluid(Minecraft p_110726_, PoseStack p_110727_, ResourceLocation texture) {
|
||||
RenderSystem.setShader(CoreShaders.POSITION_TEX);
|
||||
- RenderSystem.setShaderTexture(0, UNDERWATER_LOCATION);
|
||||
+ RenderSystem.setShaderTexture(0, texture);
|
||||
+ public static void renderFluid(Minecraft p_110726_, PoseStack p_110727_, MultiBufferSource p_376402_, ResourceLocation texture) {
|
||||
BlockPos blockpos = BlockPos.containing(p_110726_.player.getX(), p_110726_.player.getEyeY(), p_110726_.player.getZ());
|
||||
float f = LightTexture.getBrightness(p_110726_.player.level().dimensionType(), p_110726_.player.level().getMaxLocalRawBrightness(blockpos));
|
||||
RenderSystem.enableBlend();
|
||||
int i = ARGB.colorFromFloat(0.1F, f, f, f);
|
||||
@@ -94,7 +_,7 @@
|
||||
float f7 = -p_110726_.player.getYRot() / 64.0F;
|
||||
float f8 = p_110726_.player.getXRot() / 64.0F;
|
||||
Matrix4f matrix4f = p_110727_.last().pose();
|
||||
- VertexConsumer vertexconsumer = p_376402_.getBuffer(RenderType.blockScreenEffect(UNDERWATER_LOCATION));
|
||||
+ VertexConsumer vertexconsumer = p_376402_.getBuffer(RenderType.blockScreenEffect(texture));
|
||||
vertexconsumer.addVertex(matrix4f, -1.0F, -1.0F, -0.5F).setUv(4.0F + f7, 4.0F + f8).setColor(i);
|
||||
vertexconsumer.addVertex(matrix4f, 1.0F, -1.0F, -0.5F).setUv(0.0F + f7, 4.0F + f8).setColor(i);
|
||||
vertexconsumer.addVertex(matrix4f, 1.0F, 1.0F, -0.5F).setUv(0.0F + f7, 0.0F + f8).setColor(i);
|
||||
@@ -1,20 +1,24 @@
|
||||
--- a/net/minecraft/client/renderer/Sheets.java
|
||||
+++ b/net/minecraft/client/renderer/Sheets.java
|
||||
@@ -140,11 +_,11 @@
|
||||
@@ -155,7 +_,7 @@
|
||||
}
|
||||
|
||||
private static Material createSignMaterial(WoodType p_173386_) {
|
||||
- return new Material(SIGN_SHEET, ResourceLocation.withDefaultNamespace("entity/signs/" + p_173386_.name()));
|
||||
+ return new Material(SIGN_SHEET, ResourceLocation.parse(p_173386_.name()).withPrefix("entity/signs/"));
|
||||
- return createSignMaterial(ResourceLocation.withDefaultNamespace(p_173386_.name()));
|
||||
+ return createSignMaterial(ResourceLocation.parse(p_173386_.name()));
|
||||
}
|
||||
|
||||
public static Material createSignMaterial(ResourceLocation p_378064_) {
|
||||
@@ -163,7 +_,7 @@
|
||||
}
|
||||
|
||||
private static Material createHangingSignMaterial(WoodType p_251735_) {
|
||||
- return new Material(SIGN_SHEET, ResourceLocation.withDefaultNamespace("entity/signs/hanging/" + p_251735_.name()));
|
||||
+ return new Material(SIGN_SHEET, ResourceLocation.parse(p_251735_.name()).withPrefix("entity/signs/hanging/"));
|
||||
- return createHangingSignMaterial(ResourceLocation.withDefaultNamespace(p_251735_.name()));
|
||||
+ return createHangingSignMaterial(ResourceLocation.parse(p_251735_.name()));
|
||||
}
|
||||
|
||||
public static Material getSignMaterial(WoodType p_173382_) {
|
||||
@@ -203,6 +_,23 @@
|
||||
public static Material createHangingSignMaterial(ResourceLocation p_377324_) {
|
||||
@@ -230,6 +_,23 @@
|
||||
case SINGLE:
|
||||
default:
|
||||
return p_110773_;
|
||||
|
||||
+13
-31
@@ -2,7 +2,7 @@
|
||||
+++ b/net/minecraft/client/renderer/block/BlockRenderDispatcher.java
|
||||
@@ -37,7 +_,7 @@
|
||||
this.blockModelShaper = p_173399_;
|
||||
this.blockEntityRenderer = p_173400_;
|
||||
this.specialBlockModelRenderer = p_378785_;
|
||||
this.blockColors = p_173401_;
|
||||
- this.modelRenderer = new ModelBlockRenderer(this.blockColors);
|
||||
+ this.modelRenderer = new net.minecraftforge.client.model.lighting.ForgeModelBlockRenderer(this.blockColors);
|
||||
@@ -67,34 +67,16 @@
|
||||
+ public void renderSingleBlock(BlockState p_110913_, PoseStack p_110914_, MultiBufferSource p_110915_, int p_110916_, int p_110917_, net.minecraftforge.client.model.data.ModelData modelData, net.minecraft.client.renderer.RenderType renderType) {
|
||||
RenderShape rendershape = p_110913_.getRenderShape();
|
||||
if (rendershape != RenderShape.INVISIBLE) {
|
||||
switch (rendershape) {
|
||||
@@ -113,21 +_,26 @@
|
||||
float f = (float)(i >> 16 & 0xFF) / 255.0F;
|
||||
float f1 = (float)(i >> 8 & 0xFF) / 255.0F;
|
||||
float f2 = (float)(i & 0xFF) / 255.0F;
|
||||
+ for (var rt : bakedmodel.getRenderTypes(p_110913_, RandomSource.create(42), modelData))
|
||||
this.modelRenderer
|
||||
.renderModel(
|
||||
p_110914_.last(),
|
||||
- p_110915_.getBuffer(ItemBlockRenderTypes.getRenderType(p_110913_)),
|
||||
+ p_110915_.getBuffer(renderType != null ? renderType : net.minecraftforge.client.RenderTypeHelper.getEntityRenderType(rt)),
|
||||
p_110913_,
|
||||
bakedmodel,
|
||||
f,
|
||||
f1,
|
||||
f2,
|
||||
p_110916_,
|
||||
- p_110917_
|
||||
+ p_110917_,
|
||||
+ modelData,
|
||||
+ rt
|
||||
);
|
||||
break;
|
||||
case ENTITYBLOCK_ANIMATED:
|
||||
- this.blockEntityRenderer.renderByItem(new ItemStack(p_110913_.getBlock()), ItemDisplayContext.NONE, p_110914_, p_110915_, p_110916_, p_110917_);
|
||||
+ ItemStack stack = new ItemStack(p_110913_.getBlock());
|
||||
+ var renderer = net.minecraftforge.client.extensions.common.IClientItemExtensions.of(stack).getCustomRenderer();
|
||||
+ renderer.renderByItem(stack, ItemDisplayContext.NONE, p_110914_, p_110915_, p_110916_, p_110917_);
|
||||
}
|
||||
BakedModel bakedmodel = this.getBlockModel(p_110913_);
|
||||
@@ -111,9 +_,10 @@
|
||||
float f = (float)(i >> 16 & 0xFF) / 255.0F;
|
||||
float f1 = (float)(i >> 8 & 0xFF) / 255.0F;
|
||||
float f2 = (float)(i & 0xFF) / 255.0F;
|
||||
+ for (var rt : bakedmodel.getRenderTypes(p_110913_, RandomSource.create(42), modelData))
|
||||
this.modelRenderer
|
||||
.renderModel(
|
||||
- p_110914_.last(), p_110915_.getBuffer(ItemBlockRenderTypes.getRenderType(p_110913_)), p_110913_, bakedmodel, f, f1, f2, p_110916_, p_110917_
|
||||
+ p_110914_.last(), p_110915_.getBuffer(renderType != null ? renderType : net.minecraftforge.client.RenderTypeHelper.getEntityRenderType(rt)), p_110913_, bakedmodel, f, f1, f2, p_110916_, p_110917_, modelData, rt
|
||||
);
|
||||
this.specialBlockModelRenderer.get().renderByBlock(p_110913_.getBlock(), ItemDisplayContext.NONE, p_110914_, p_110915_, p_110916_, p_110917_);
|
||||
}
|
||||
}
|
||||
@@ -1,74 +1,52 @@
|
||||
--- a/net/minecraft/client/renderer/block/model/BlockModel.java
|
||||
+++ b/net/minecraft/client/renderer/block/model/BlockModel.java
|
||||
@@ -72,9 +_,10 @@
|
||||
public BlockModel parent;
|
||||
@@ -49,6 +_,7 @@
|
||||
public UnbakedModel parent;
|
||||
@Nullable
|
||||
protected ResourceLocation parentLocation;
|
||||
private final ResourceLocation parentLocation;
|
||||
+ public final net.minecraftforge.client.model.geometry.BlockGeometryBakingContext customData = new net.minecraftforge.client.model.geometry.BlockGeometryBakingContext(this);
|
||||
|
||||
public static BlockModel fromStream(Reader p_111462_) {
|
||||
- return GsonHelper.fromJson(GSON, p_111462_, BlockModel.class);
|
||||
+ return GsonHelper.fromJson(net.minecraftforge.client.model.ExtendedBlockModelDeserializer.INSTANCE, p_111462_, BlockModel.class);
|
||||
return GsonHelper.fromJson(GSON, p_111462_, BlockModel.class);
|
||||
@@ -85,6 +_,8 @@
|
||||
@Override
|
||||
public void resolveDependencies(ResolvableModel.Resolver p_377823_) {
|
||||
if (this.parentLocation != null) {
|
||||
+ if (customData.hasCustomGeometry())
|
||||
+ customData.getCustomGeometry().resolveDependencies(p_377823_, customData);
|
||||
this.parent = p_377823_.resolve(this.parentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockModel(
|
||||
@@ -95,10 +_,17 @@
|
||||
this.overrides = p_273099_;
|
||||
}
|
||||
|
||||
+ @Deprecated
|
||||
public List<BlockElement> getElements() {
|
||||
+ if (customData.hasCustomGeometry()) return java.util.Collections.emptyList();
|
||||
return this.elements.isEmpty() && this.parent != null ? this.parent.getElements() : this.elements;
|
||||
}
|
||||
|
||||
+ @Nullable
|
||||
+ public ResourceLocation getParentLocation() {
|
||||
+ return parentLocation;
|
||||
+ }
|
||||
@@ -110,14 +_,20 @@
|
||||
public BakedModel bake(
|
||||
TextureSlots p_378598_, ModelBaker p_378458_, ModelState p_111453_, boolean p_111455_, boolean p_377435_, ItemTransforms p_378085_
|
||||
) {
|
||||
+ if (this.customData.getCustomGeometry() != null)
|
||||
+ return this.customData.getCustomGeometry().bake(customData, p_378458_, p_378598_, p_111453_);
|
||||
+
|
||||
public boolean hasAmbientOcclusion() {
|
||||
if (this.hasAmbientOcclusion != null) {
|
||||
return this.hasAmbientOcclusion;
|
||||
@@ -130,6 +_,10 @@
|
||||
throw new IllegalStateException("BlockModel parent has to be a block model.");
|
||||
+ var wrapped = net.minecraftforge.client.ForgeHooksClient.wrapRenderType(p_378458_, this.customData.getRenderType(), this.customData.getRenderTypeFast());
|
||||
+
|
||||
return this.elements.isEmpty() && this.parent != null
|
||||
- ? this.parent.bake(p_378598_, p_378458_, p_111453_, p_111455_, p_377435_, p_378085_)
|
||||
- : SimpleBakedModel.bakeElements(this.elements, p_378598_, p_378458_.sprites(), p_111453_, p_111455_, p_377435_, true, p_378085_);
|
||||
+ ? this.parent.bake(p_378598_, wrapped, p_111453_, p_111455_, p_377435_, p_378085_)
|
||||
+ : SimpleBakedModel.bakeElements(this.elements, p_378598_, p_378458_.sprites(), p_111453_, p_111455_, p_377435_, true, p_378085_, wrapped.renderType(), wrapped.renderTypeFast());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
List<BlockElement> getElements() {
|
||||
+ if (customData.hasCustomGeometry()) return java.util.Collections.emptyList();
|
||||
return this.elements;
|
||||
}
|
||||
|
||||
@@ -147,7 +_,8 @@
|
||||
}
|
||||
|
||||
+ if (customData.hasCustomGeometry()) {
|
||||
+ customData.getCustomGeometry().resolveDependencies(p_365651_, customData);
|
||||
+ }
|
||||
+
|
||||
this.parent = blockmodel;
|
||||
ResourceLocation resourcelocation = s.isEmpty() ? null : ResourceLocation.parse(s);
|
||||
- return new BlockModel(resourcelocation, list, textureslots$data, obool, unbakedmodel$guilight, itemtransforms);
|
||||
+ var ret = new BlockModel(resourcelocation, list, textureslots$data, obool, unbakedmodel$guilight, itemtransforms);
|
||||
+ return net.minecraftforge.client.ForgeHooksClient.deserializeBlockModel(ret, ret.getElements(), jsonobject, p_111500_);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +_,18 @@
|
||||
ItemTransform itemtransform5 = this.getTransform(ItemDisplayContext.GUI);
|
||||
ItemTransform itemtransform6 = this.getTransform(ItemDisplayContext.GROUND);
|
||||
ItemTransform itemtransform7 = this.getTransform(ItemDisplayContext.FIXED);
|
||||
- return new ItemTransforms(itemtransform, itemtransform1, itemtransform2, itemtransform3, itemtransform4, itemtransform5, itemtransform6, itemtransform7);
|
||||
+
|
||||
+ var builder = com.google.common.collect.ImmutableMap.<ItemDisplayContext, ItemTransform>builder();
|
||||
+ for (ItemDisplayContext type : ItemDisplayContext.values()) {
|
||||
+ if (type.isModded()) {
|
||||
+ var transform = this.getTransform(type);
|
||||
+ if (transform != ItemTransform.NO_TRANSFORM) {
|
||||
+ builder.put(type, transform);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return new ItemTransforms(itemtransform, itemtransform1, itemtransform2, itemtransform3, itemtransform4, itemtransform5, itemtransform6, itemtransform7, builder.build());
|
||||
}
|
||||
|
||||
private ItemTransform getTransform(ItemDisplayContext p_270662_) {
|
||||
@@ -347,6 +_,10 @@
|
||||
|
||||
public boolean lightLikeBlock() {
|
||||
return this == SIDE;
|
||||
+ }
|
||||
+
|
||||
+ public String getSerializedName() {
|
||||
+ return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
private TextureSlots.Data getTextureMap(JsonObject p_111510_) {
|
||||
@@ -1,12 +1,11 @@
|
||||
--- a/net/minecraft/client/renderer/block/model/FaceBakery.java
|
||||
+++ b/net/minecraft/client/renderer/block/model/FaceBakery.java
|
||||
@@ -58,7 +_,14 @@
|
||||
this.recalculateWinding(aint, direction);
|
||||
@@ -58,7 +_,13 @@
|
||||
recalculateWinding(aint, direction);
|
||||
}
|
||||
|
||||
- return new BakedQuad(aint, p_111603_.tintIndex(), direction, p_111604_, p_111608_, p_364904_);
|
||||
+ var data = p_111603_.data();
|
||||
+ //net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction, data.calculateNormals());
|
||||
+ var quad = new BakedQuad(aint, p_111603_.tintIndex(), direction, p_111604_, p_111608_, p_364904_, data.ambientOcclusion());
|
||||
+ if (!net.minecraftforge.client.model.ForgeFaceData.DEFAULT.equals(data)) {
|
||||
+ net.minecraftforge.client.model.QuadTransformers.applyingLightmap(data.blockLight(), data.skyLight()).processInPlace(quad);
|
||||
|
||||
Loaded 100 of 432 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user