Compare commits

...
39 Commits
Author SHA1 Message Date
Jonathing 6ae39c8597 1.21.4 RB 1
https://forums.minecraftforge.net/topic/154394-forge-541-minecraft-1214/
2025-02-12 12:29:03 -08:00
Jonathing dcafb4f633 Fix corrupted and invalidly symlinked worlds crashing on level select (#10406) 2025-02-12 11:52:53 -08:00
Jonathing 1ea7ce9831 Add fast graphics render type to block model jsons (#10394)
Make modded leaves behave like vanilla leaves by default (Fixes #10389)
2025-02-12 11:47:09 -08:00
Jonathing 674f2efd54 Add updated tag context to AddReloadListenerEvent (#10412)
Fixes using custom tags in GlobalLootModifiers.
2025-02-12 11:02:22 -08:00
Jonathing 02e82c672d Give ItemStack context to IForgeItem.getCapabilityProvider (#10404) 2025-02-05 09:15:37 -08:00
RealMangoRage b25f6e3a7c Re-introduce ItemStack Capabilities (#10324) 2025-02-03 18:44:44 -08:00
LexManos e69b07a54a Fix redstone updates for comparators going up/down incorrectly. Related: #9973 2025-02-03 18:32:53 -08:00
Jonathing 79efe2ac36 Fix forced chunks never being ticked by the server (#10325) 2025-02-03 13:47:36 -08:00
LexManos 464483db5b Fix redstone update order not matching vanilla. (#10392) 2025-02-03 13:36:45 -08:00
LexManos f49adb285f Fix game test structure rotations being inconsistant (#10391) 2025-02-03 13:31:20 -08:00
Jonathing 55862dfd1d Re-introduce IForgeItem.damageItem when an item takes damage, Fixes #10344 (#10371) 2025-02-03 13:17:38 -08:00
Jonathing 124b9bd8d3 Gate client test mods behind clientSideOnly (#10390) 2025-02-03 13:17:01 -08:00
Jonathing bae3915728 Fix issue with superclass event listeners by updating EventBus (#10384) 2025-02-03 11:13:33 -08:00
Jonathing b3c2c62c7e Bump dependencies, most notably EventBus (#10370)
- CoreMods 5.2.4 -> 5.2.6
- EventBus 6.2.15 -> 6.2.26
    - Reduced memory usage
    - Further performance improvements
    - Fixed EventBus#39, unregistered listeners are now immediately reclaimable by the GC
- Apache MavenArtifact 3.8.5 -> 3.8.8
- NightConfig 3.7.3 -> 3.7.4
2025-01-28 21:00:16 +00:00
Jonathing 68698d70c1 Fix shield disabling being completely ignored (#10316) 2025-01-27 15:24:30 -08:00
Jonathing d55dee9394 Update Gradle to 8.12.1 2025-01-27 09:17:02 -08:00
Jonathing 2d114f2719 Fix JOpt Simple by updating ModLauncher (#10347) 2025-01-27 09:16:24 -08:00
JonathingandLexManos 3e6583af01 GameTestHelper additions (#10338)
Co-authored-by: LexManos <[email protected]>
2025-01-27 09:15:57 -08:00
Paint_NinjaandTelepathicGrunt 762f6a7d78 Add c:flowers, c:flowers/tall, and c:flowers/small block and item tags (#10335)
Co-authored-by: TelepathicGrunt <[email protected]>
2025-01-25 20:55:58 +00:00
Jonathing 3c5a534b7a Fix JOpt Simple needing a strict version requirement declaration (#10311) 2025-01-25 17:49:11 +00:00
Jonathing bc62d1693a Fix incorrect method reference in TntBlock.explode() (#10326) 2025-01-25 17:48:54 +00:00
Joseph T. McQuigg 554ead8d4a Fix issues in VillagerTrades.EmeraldsForVillagerTypeItem related to custom Villager Types (#10298)
Add VillagerType#registerBiomeType
2025-01-21 16:07:56 -08:00
LexManos ec5ac91389 Fix render_type in block models not being used. Fixes #10294 2025-01-13 13:27:47 -08:00
Jonathing f63813d929 Bump dependencies (#10274)
- EventBus 6.2.8 -> 6.2.15
- Bootstrap 2.1.7 -> 2.1.8
- SecureModules 2.2.20 -> 2.2.21
- AccessTransformers 8.2.0 -> 8.2.1
- ModLauncher 10.2.2 -> 10.2.3
These bumps include further clean-up and optimisations.
2025-01-04 16:04:31 +00:00
Jonathing 5d4825ac4b Simplify Title Screen Brandings (#10287) 2025-01-02 14:31:05 -08:00
Jonathing 3024ef7707 Clean and fix Forge's internal coremods, fixes finalizeSpawn hook. (#10271) 2024-12-30 11:18:20 -08:00
Gabriel Harris-Rouquette 0d3b488728 Update jline for better darwin/arm64 support Fixes #10107 (#10279) 2024-12-29 09:25:21 -08:00
Jonathing a01012f20c Bump CoreMods to 5.2.4 (#10262) 2024-12-23 15:25:21 -08:00
Jonathing d4e3ef4a22 Allow mipmap lowering to be disabled (#10242) 2024-12-23 11:46:59 -08:00
Jonathing d7293a78dc Manage FileWatcher instance per ConfigFileTypeHandler (#10213) 2024-12-22 11:59:00 -08:00
Paint_Ninja 8e4e02e258 Skip processing Forge classes in RuntimeDistCleaner (#10199)
Mod classes are still transformed as usual
2024-12-21 22:20:21 +00:00
Paint_Ninja 2f5a6fee48 Skip Forge classes in the RuntimeEnumExtender transformer (#10197)
Mod classes are still transformed as usual
2024-12-21 22:19:07 +00:00
LexManos 0e74886f8d Add hooks for using Vanilla's new Client data generator (#10206)
Add new hook for custom block models that do not have real blocks backing them
Some workspace cleanup fixing log4j annotation processor
2024-12-19 10:41:21 -08:00
Paint_Ninja 07977ba242 Deprecate @ObjectHolder, add a couple of fast-paths (#10195) 2024-12-06 18:18:53 +00:00
LexManos a894c244fe Bump Bootstrap which has a slight performance boost during dev time. 2024-12-06 10:13:49 -08:00
LexManos cf32a799a4 Speed up mod annotation scanning by ~30% 2024-12-06 10:11:04 -08:00
Paint_Ninja 0fda1d9393 Skip Vanilla classes for the CapabilityTokenSubclass transformer (#10196) 2024-12-06 17:35:09 +00:00
Paint_NinjaandTelepathicGrunt c7f0acbe38 Simplify memory usage display on loading screen (#10193)
Co-authored-by: TelepathicGrunt <[email protected]>
2024-12-06 17:34:33 +00:00
LexManos 9c06c20023 Fix custom particles causing crash 2024-12-05 16:40:29 -08:00
158 changed files with 4460 additions and 434 deletions

No files matched your search

+1
View File
@@ -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
+5
View File
@@ -41,3 +41,8 @@ src/*/generated/**/.cache/
/ForgeRoot.ipr
/ForgeRoot.iws
# APT stuff
/*/.gitignore
/*/.factorypath
/*/.apt_generated/
@@ -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.') }()
}
}
+48 -16
View File
@@ -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)
@@ -1059,7 +1091,7 @@ publishing {
license gradleutils.pom.Licenses.LGPLv2_1
}
}
repositories {
maven gradleutils.publishingForgeMaven
}
+25 -6
View File
@@ -2,16 +2,15 @@
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.20.6-&query=$.promos["1.20.6-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.20.6-&query=$.promos["1.20.6-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.21.4-&query=$.promos["1.21.4-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)][Download]
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.21.4-&query=$.promos["1.21.4-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)][Download] [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)][Discord] [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)][Patreon]
Forge is a free, open-source modding API all of your favourite mods use!
| Version | Support |
|---------| ------------- |
| 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/
@@ -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);
}
@@ -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
View File
@@ -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'
}
}
}
}
@@ -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
@@ -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"))
@@ -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",
@@ -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.
@@ -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;
}
@@ -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
@@ -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,7 +76,7 @@ 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) {};
@@ -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");
@@ -62,4 +64,10 @@ sealed abstract class ForgeDevLaunchHandler extends CommonDevLaunchHandler {
super(SERVER_GAMETEST);
}
}
public static final class Custom extends ForgeDevLaunchHandler {
public Custom() {
super("forge_dev");
}
}
}
@@ -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,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
+1 -1
View File
@@ -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"/>
Binary file not shown.
+2 -1
View File
@@ -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
Vendored
+13 -9
View File
@@ -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
View File
@@ -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
+4 -3
View File
@@ -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
@@ -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();
@@ -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();
@@ -66,7 +66,7 @@
+
+ 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()) {
- renderParticleType(p_107340_, p_107341_, p_377798_, particlerendertype, queue);
@@ -34,21 +34,26 @@
public static RenderType getMovingBlockRenderType(BlockState p_109294_) {
Block block = p_109294_.getBlock();
if (block instanceof LeavesBlock) {
@@ -376,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();
@@ -390,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);
@@ -17,17 +17,22 @@
this.parent = p_377823_.resolve(this.parentLocation);
}
}
@@ -110,6 +_,9 @@
@@ -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_);
+
+ 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_);
@@ -118,6 +_,7 @@
- ? 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() {
@@ -1,6 +1,6 @@
--- a/net/minecraft/client/renderer/entity/EntityRenderDispatcher.java
+++ b/net/minecraft/client/renderer/entity/EntityRenderDispatcher.java
@@ -243,12 +_,12 @@
@@ -246,12 +_,12 @@
) {
AABB aabb = p_114444_.getBoundingBox().move(-p_114444_.getX(), -p_114444_.getY(), -p_114444_.getZ());
ShapeRenderer.renderLineBox(p_114442_, p_114443_, aabb, p_343193_, p_342304_, p_342638_, 1.0F);
@@ -15,7 +15,7 @@
p_114442_.pushPose();
double d3 = d0 + Mth.lerp((double)p_114445_, enderdragonpart.xOld, enderdragonpart.getX());
double d4 = d1 + Mth.lerp((double)p_114445_, enderdragonpart.yOld, enderdragonpart.getY());
@@ -481,6 +_,10 @@
@@ -484,6 +_,10 @@
return this.itemInHandRenderer;
}
@@ -26,7 +26,7 @@
@Override
public void onResourceManagerReload(ResourceManager p_174004_) {
EntityRendererProvider.Context entityrendererprovider$context = new EntityRendererProvider.Context(
@@ -488,5 +_,6 @@
@@ -491,5 +_,6 @@
);
this.renderers = EntityRenderers.createEntityRenderers(entityrendererprovider$context);
this.playerRenderers = EntityRenderers.createPlayerRenderers(entityrendererprovider$context);
@@ -5,7 +5,7 @@
int k1 = Mth.log2(j1);
int l1;
- if (k1 < p_261919_) {
+ if (false) { // Forge: Do not lower the mipmap level
+ if (k1 < p_261919_ && net.minecraftforge.common.ForgeConfig.CLIENT.allowMipmapLowering()) { // Forge: Do not lower the mipmap level
LOGGER.warn("{}: dropping miplevel from {} to {}, because of minimum power of two: {}", this.location, p_261919_, k1, j1);
l1 = k1;
} else {
@@ -0,0 +1,11 @@
--- a/net/minecraft/client/resources/model/BlockStateModelLoader.java
+++ b/net/minecraft/client/resources/model/BlockStateModelLoader.java
@@ -52,6 +_,8 @@
private static Function<ResourceLocation, StateDefinition<Block, BlockState>> definitionLocationToBlockMapper() {
Map<ResourceLocation, StateDefinition<Block, BlockState>> map = new HashMap<>(STATIC_DEFINITIONS);
+ var event = net.minecraftforge.client.event.ForgeEventFactoryClient.onRegisterModeStateDefinitions();
+ map.putAll(event.getStates());
for (Block block : BuiltInRegistries.BLOCK) {
map.put(block.builtInRegistryHolder().key().location(), block.getStateDefinition());
@@ -0,0 +1,19 @@
--- a/net/minecraft/client/resources/model/ModelBaker.java
+++ b/net/minecraft/client/resources/model/ModelBaker.java
@@ -13,4 +_,16 @@
@VisibleForDebug
ModelDebugName rootName();
+
+ /** Forge: Return the render type to use when baking this model, its a dirty hack to pass down this value to parents */
+ @org.jetbrains.annotations.Nullable
+ default net.minecraftforge.client.RenderTypeGroup renderType() {
+ return null;
+ }
+
+ /** Forge: Return the fast graphics render type to use when baking this model, its a dirty hack to pass down this value to parents */
+ @org.jetbrains.annotations.Nullable
+ default net.minecraftforge.client.RenderTypeGroup renderTypeFast() {
+ return null;
+ }
}
@@ -1,84 +1,149 @@
--- a/net/minecraft/client/resources/model/SimpleBakedModel.java
+++ b/net/minecraft/client/resources/model/SimpleBakedModel.java
@@ -29,6 +_,19 @@
@@ -29,7 +_,26 @@
private final boolean usesBlockLight;
private final TextureAtlasSprite particleIcon;
private final ItemTransforms transforms;
+ /*
-
+ /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} */
+ protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypes;
+ protected final List<net.minecraft.client.renderer.RenderType> itemRenderTypes;
+ protected final List<net.minecraft.client.renderer.RenderType> fabulousItemRenderTypes;
+ */
+ /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */
+ protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypesFast;
+ /** Forge: If this model's {@linkplain #blockRenderTypes block render types} are rendering cutout, to account for older leaves model JSONs */
+ protected final boolean isRenderingCutout;
+
+ /* @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/
+ /*
+ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/
+ @Deprecated
+ public SimpleBakedModel(List<BakedQuad> p_119489_, Map<Direction, List<BakedQuad>> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_) {
+ this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, net.minecraftforge.client.RenderTypeGroup.EMPTY);
+ }
+ */
+
+ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup for fast graphics} **/
+ @Deprecated(forRemoval = true, since = "1.21.4")
+ public SimpleBakedModel(List<BakedQuad> p_119489_, Map<Direction, List<BakedQuad>> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, net.minecraftforge.client.RenderTypeGroup renderTypes) {
+ this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY);
+ }
+
+ /** Constructor with {@link net.minecraftforge.client.RenderTypeGroup RenderTypeGroup} for fancy and fast graphics. Preferred over {@link net.minecraft.client.renderer.ItemBlockRenderTypes#setRenderLayer(net.minecraft.world.level.block.Block, net.minecraft.client.renderer.RenderType) ItemBlockRenderTypes.setRenderLayer(Block, RenderType)}. */
public SimpleBakedModel(
List<BakedQuad> p_119489_,
@@ -38,6 +_,7 @@
Map<Direction, List<BakedQuad>> p_119490_,
@@ -37,7 +_,9 @@
boolean p_119492_,
boolean p_119493_,
TextureAtlasSprite p_119494_,
ItemTransforms p_119495_
+ //net.minecraftforge.client.RenderTypeGroup renderTypes
- ItemTransforms p_119495_
+ ItemTransforms p_119495_,
+ net.minecraftforge.client.RenderTypeGroup renderTypes,
+ net.minecraftforge.client.RenderTypeGroup renderTypesFast
) {
this.unculledFaces = p_119489_;
this.culledFaces = p_119490_;
@@ -46,6 +_,11 @@
@@ -46,6 +_,20 @@
this.usesBlockLight = p_119492_;
this.particleIcon = p_119494_;
this.transforms = p_119495_;
+ /*
+ this.blockRenderTypes = !renderTypes.isEmpty() ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null;
+ this.itemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entity()) : null;
+ this.fabulousItemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entityFabulous()) : null;
+ */
+
+ boolean hasRenderTypes = renderTypes != null && !renderTypes.isEmpty();
+ boolean hasRenderTypesFast = renderTypesFast != null && !renderTypesFast.isEmpty();
+ this.blockRenderTypes = hasRenderTypes ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null;
+ this.blockRenderTypesFast = hasRenderTypesFast ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypesFast.block()) : null;
+ this.isRenderingCutout = hasRenderTypes && (renderTypes.block() == net.minecraft.client.renderer.RenderType.cutout() || renderTypes.block() == net.minecraft.client.renderer.RenderType.cutoutMipped());
+ }
+
+ public static BakedModel bakeElements(List<BlockElement> p_377425_, TextureSlots p_378525_, SpriteGetter p_375793_, ModelState p_376680_, boolean p_375745_, boolean p_376866_, boolean p_376846_, ItemTransforms p_376883_) {
+ return bakeElements(p_377425_, p_378525_, p_375793_, p_376680_, p_375745_, p_376866_, p_376846_, p_376883_, null);
+ }
+
+ public static BakedModel bakeElements(List<BlockElement> p_377425_, TextureSlots p_378525_, SpriteGetter p_375793_, ModelState p_376680_, boolean p_375745_, boolean p_376866_, boolean p_376846_, ItemTransforms p_376883_, @Nullable net.minecraftforge.client.RenderTypeGroup renderType) {
+ return bakeElements(p_377425_, p_378525_, p_375793_, p_376680_, p_375745_, p_376866_, p_376846_, p_376883_, renderType, null);
}
public static BakedModel bakeElements(
@@ -123,6 +_,27 @@
@@ -56,7 +_,9 @@
boolean p_375745_,
boolean p_376866_,
boolean p_376846_,
- ItemTransforms p_376883_
+ ItemTransforms p_376883_,
+ @Nullable net.minecraftforge.client.RenderTypeGroup renderType,
+ @Nullable net.minecraftforge.client.RenderTypeGroup renderTypeFast
) {
TextureAtlasSprite textureatlassprite = findSprite(p_375793_, p_378525_, "particle");
SimpleBakedModel.Builder simplebakedmodel$builder = new SimpleBakedModel.Builder(p_375745_, p_376866_, p_376846_, p_376883_)
@@ -77,6 +_,13 @@
}
}
+ if (renderType != null && !renderType.isEmpty()) {
+ if (renderTypeFast != null && !renderTypeFast.isEmpty())
+ simplebakedmodel$builder.renderTypes(renderType, renderTypeFast);
+ else
+ simplebakedmodel$builder.renderTypes(renderType);
+ }
+
return simplebakedmodel$builder.build();
}
@@ -123,6 +_,19 @@
return this.transforms;
}
+ /*
+ @Override
+ public net.minecraftforge.client.ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, net.minecraftforge.client.model.data.ModelData data) {
+ return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data);
+ }
+ private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID_BLOCK = net.minecraftforge.client.ChunkRenderTypeSet.of(net.minecraft.client.renderer.RenderType.solid());
+
+ @Override
+ public List<net.minecraft.client.renderer.RenderType> getRenderTypes(net.minecraft.world.item.ItemStack itemStack, boolean fabulous) {
+ if (!fabulous) {
+ if (itemRenderTypes != null) {
+ return itemRenderTypes;
+ }
+ } else {
+ if (fabulousItemRenderTypes != null) {
+ return fabulousItemRenderTypes;
+ }
+ }
+ return BakedModel.super.getRenderTypes(itemStack, fabulous);
+ public net.minecraftforge.client.ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, net.minecraftforge.client.model.data.ModelData data) {
+ if (!net.minecraft.client.renderer.ItemBlockRenderTypes.isFancy()) {
+ if (blockRenderTypesFast != null)
+ return blockRenderTypesFast;
+ if (isRenderingCutout && state.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock)
+ return SOLID_BLOCK;
+ }
+ return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data);
+ }
+ */
+
@OnlyIn(Dist.CLIENT)
public static class Builder {
private final ImmutableList.Builder<BakedQuad> unculledFaces = ImmutableList.builder();
@@ -164,13 +_,21 @@
@@ -164,13 +_,50 @@
return this;
}
+ /*
+ private net.minecraftforge.client.RenderTypeGroup renderTypes = net.minecraftforge.client.RenderTypeGroup.EMPTY;
+ private net.minecraftforge.client.RenderTypeGroup renderTypesFast = net.minecraftforge.client.RenderTypeGroup.EMPTY;
+
+ /**
+ * Sets the render type to be used for this model, and will be used for any graphics setting.
+ * <p>
+ * If you need to set a specific render type for
+ * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}, consider using
+ * {@link #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup)
+ * renderTypes(RenderTypeGroup, RenderTypeGroup)} instead which allows choosing render types for both fancy and
+ * fast graphics.
+ *
+ * @apiNote If this model is for {@linkplain net.minecraft.world.level.block.LeavesBlock leaves} and if the
+ * given render type is either {@linkplain net.minecraft.client.renderer.RenderType#cutout() cutout} or
+ * {@linkplain net.minecraft.client.renderer.RenderType#cutoutMipped() cutout mipped}, it will be overridden
+ * with {@linkplain net.minecraft.client.renderer.RenderType#solid() solid} when fast graphics is enabled.
+ * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup)
+ * renderTypes(RenderTypeGroup, RenderTypeGroup)
+ */
+ public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes) {
+ return this.renderTypes(renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY);
+ }
+
+ /**
+ * Sets the render types to be used for this model: one for
+ * {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} and one for
+ * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
+ *
+ * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup)
+ */
+ public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes, net.minecraftforge.client.RenderTypeGroup renderTypesFast) {
+ this.renderTypes = renderTypes;
+ this.renderTypesFast = renderTypesFast;
+ return this;
+ }
+ */
+
public BakedModel build() {
if (this.particleIcon == null) {
@@ -87,7 +152,8 @@
Map<Direction, List<BakedQuad>> map = Maps.transformValues(this.culledFaces, ImmutableList.Builder::build);
return new SimpleBakedModel(
- this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms
+ this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms/*, this.renderTypes*/
+ // Forge: Account for render types in model JSONs
+ this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.renderTypes, this.renderTypesFast
);
}
}
@@ -1,12 +1,17 @@
--- a/net/minecraft/core/Direction.java
+++ b/net/minecraft/core/Direction.java
@@ -49,6 +_,10 @@
@@ -49,6 +_,15 @@
private final Vec3i normal;
private final Vec3 normalVec3;
private static final Direction[] VALUES = values();
+ private static final List<Direction> VALUES_VIEW = java.util.Collections.unmodifiableList(Arrays.asList(VALUES));
+ public static final List<Direction> valuesView() {
+ return VALUES_VIEW;
+ }
+ // In vanilla updates are notified only on the horizontal plane, in Forge we also notify up and down
+ private static final List<Direction> UPDATE_ORDER = java.util.Collections.unmodifiableList(Stream.concat(Plane.HORIZONTAL.stream(), Plane.VERTICAL.stream()).toList());
+ public static final List<Direction> getUpdateOrder() {
+ return UPDATE_ORDER;
+ }
private static final Direction[] BY_3D_DATA = Arrays.stream(VALUES)
.sorted(Comparator.comparingInt(p_235687_ -> p_235687_.data3d))
@@ -9,3 +9,29 @@
private final GameTestInfo testInfo;
private boolean finalCheckAdded;
@@ -996,5 +_,25 @@
if (either.right().isPresent()) {
this.fail("Failed to set biome for test");
}
+ }
+
+ /**
+ * Adds a cleanup handler that will be called when the test is done, pass or fail.
+ */
+ public void addCleanup(Consumer<Boolean> handler) {
+ this.testInfo.addListener(new GameTestListener() {
+ @Override
+ public void testPassed(GameTestInfo info, GameTestRunner runner) {
+ handler.accept(true);
+ }
+
+ @Override
+ public void testFailed(GameTestInfo info, GameTestRunner runner) {
+ handler.accept(false);
+ }
+
+ @Override public void testStructureLoaded(GameTestInfo info) { }
+ @Override public void testAddedForRerun(GameTestInfo oldInfo, GameTestInfo newInfo, GameTestRunner runner) { }
+ });
}
}
@@ -0,0 +1,11 @@
--- a/net/minecraft/gametest/framework/GameTestInfo.java
+++ b/net/minecraft/gametest/framework/GameTestInfo.java
@@ -265,7 +_,7 @@
BlockPos blockpos = this.getOrCalculateNorthwestCorner();
this.structureBlockEntity = StructureUtils.prepareTestStructure(this, blockpos, this.getRotation(), this.level);
this.structureBlockPos = this.structureBlockEntity.getBlockPos();
- StructureUtils.addCommandBlockAndButtonToStartTest(this.structureBlockPos, new BlockPos(1, 0, -1), this.getRotation(), this.level);
+ StructureUtils.addCommandBlockAndButtonToStartTest(this.structureBlockPos, new BlockPos(1, 0, -1), Rotation.NONE, this.level); // Forge: The control blocks are always in the North West Corner
StructureUtils.encaseStructure(this.getStructureBounds(), this.level, !this.testFunction.skyAccess());
this.listeners.forEach(p_127630_ -> p_127630_.testStructureLoaded(this));
return this;
@@ -0,0 +1,22 @@
--- a/net/minecraft/gametest/framework/ReportGameListener.java
+++ b/net/minecraft/gametest/framework/ReportGameListener.java
@@ -151,7 +_,7 @@
private static BlockPos getBeaconPos(GameTestInfo p_344999_) {
BlockPos blockpos = p_344999_.getStructureBlockPos();
BlockPos blockpos1 = new BlockPos(-1, -2, -1);
- return StructureTemplate.transform(blockpos.offset(blockpos1), Mirror.NONE, p_344999_.getRotation(), blockpos);
+ return blockpos.offset(blockpos1); // Forge: The control blocks are always in the North West Corner
}
private static void updateBeaconGlass(GameTestInfo p_343978_, Block p_344076_) {
@@ -167,8 +_,8 @@
ServerLevel serverlevel = p_177739_.getLevel();
BlockPos blockpos = p_177739_.getStructureBlockPos();
BlockPos blockpos1 = new BlockPos(-1, 0, -1);
- BlockPos blockpos2 = StructureTemplate.transform(blockpos.offset(blockpos1), Mirror.NONE, p_177739_.getRotation(), blockpos);
- serverlevel.setBlockAndUpdate(blockpos2, Blocks.LECTERN.defaultBlockState().rotate(p_177739_.getRotation()));
+ BlockPos blockpos2 = blockpos.offset(blockpos1); // Forge: The control blocks are always in the North West Corner
+ serverlevel.setBlockAndUpdate(blockpos2, Blocks.LECTERN.defaultBlockState());
BlockState blockstate = serverlevel.getBlockState(blockpos2);
ItemStack itemstack = createBook(p_177739_.getTestName(), p_177739_.isRequired(), p_177740_);
LecternBlock.tryPlaceBook(null, serverlevel, blockpos2, blockstate, itemstack);
@@ -0,0 +1,21 @@
--- a/net/minecraft/gametest/framework/StructureUtils.java
+++ b/net/minecraft/gametest/framework/StructureUtils.java
@@ -132,10 +_,16 @@
.orElseThrow(() -> new IllegalStateException("Missing test structure: " + p_311701_.getStructureName()))
.getSize();
BoundingBox boundingbox = getStructureBoundingBox(p_311042_, vec3i, p_310584_);
- BlockPos blockpos = getStartCorner(p_311701_, p_311042_, p_310584_, p_312330_);
+ BlockPos blockpos = getStartCorner(p_311701_, p_311042_, Rotation.NONE, p_312330_); // Forge: The control blocks are always in the North West Corner
forceLoadChunks(boundingbox, p_312330_);
clearSpaceForStructure(boundingbox, p_312330_);
- return createStructureBlock(p_311701_, blockpos.below(), p_310584_, p_312330_);
+ var entity = createStructureBlock(p_311701_, blockpos.below(), p_310584_, p_312330_);
+ //Forge: We need to offset the structure so that it will load within bounds.
+ if (p_310584_ != Rotation.NONE) {
+ var rotated = StructureTemplate.getZeroPositionWithTransform(BlockPos.ZERO, Mirror.NONE, p_310584_, entity.getStructureSize().getX(), entity.getStructureSize().getZ());
+ entity.setStructurePos(rotated.offset(new BlockPos(0, 1, 0)));
+ }
+ return entity;
}
public static void encaseStructure(AABB p_330422_, ServerLevel p_331249_, boolean p_328180_) {
@@ -0,0 +1,15 @@
--- a/net/minecraft/gametest/framework/TestCommand.java
+++ b/net/minecraft/gametest/framework/TestCommand.java
@@ -313,7 +_,11 @@
return Optional.empty();
} else {
TestFunction testfunction = optional.get();
- GameTestInfo gametestinfo = new GameTestInfo(testfunction, structureblockentity.getRotation(), p_328153_, p_330368_);
+ // Forge: The rotation is stored in the structure block, and added in the GameTestInfo constructor.
+ // So reverse it to find the manually specified rotation so the test runs the same every time.
+ var steps = StructureUtils.getRotationStepsForRotation(structureblockentity.getRotation()) - StructureUtils.getRotationStepsForRotation(testfunction.rotation());
+ if (steps < 0) steps += 4;
+ GameTestInfo gametestinfo = new GameTestInfo(testfunction, StructureUtils.getRotationForRotationSteps(steps), p_328153_, p_330368_);
gametestinfo.setStructureBlockPos(p_332856_);
return !verifyStructureExists(p_328153_, gametestinfo.getStructureName()) ? Optional.empty() : Optional.of(gametestinfo);
}
@@ -27,7 +27,7 @@
p_358539_.layers(), p_358539_.lookupWithUpdatedTags(), p_250212_, p_249301_, p_366334_, p_251126_
);
+ var listeners = new java.util.ArrayList<>(reloadableserverresources.listeners());
+ listeners.addAll(net.minecraftforge.event.ForgeEventFactory.onResourceReload(reloadableserverresources, p_330376_.compositeAccess()));
+ listeners.addAll(net.minecraftforge.event.ForgeEventFactory.onResourceReload(reloadableserverresources, p_358539_.lookupWithUpdatedTags(), p_330376_.compositeAccess()));
return SimpleReloadInstance.create(
- p_248588_, reloadableserverresources.listeners(), p_249136_, p_249601_, DATA_RELOAD_INITIAL_TASK, LOGGER.isDebugEnabled()
+ p_248588_, listeners, p_249136_, p_249601_, DATA_RELOAD_INITIAL_TASK, LOGGER.isDebugEnabled()
@@ -45,7 +45,7 @@
}
}
@@ -275,6 +_,11 @@
@@ -275,6 +_,13 @@
if (this.queryThreadGs4 != null) {
this.queryThreadGs4.stop();
}
@@ -54,6 +54,8 @@
+ this.dediLanPinger.interrupt();
+ this.dediLanPinger = null;
+ }
+
+ net.minecraftforge.fml.config.ConfigTracker.INSTANCE.forceUnload();
}
@Override
@@ -24,6 +24,35 @@
this.write(chunkpos, completablefuture::join).handle((p_358676_, p_358677_) -> {
if (p_358677_ != null) {
this.level.getServer().reportChunkSaveFailure(p_358677_, this.storageInfo(), chunkpos);
@@ -934,10 +_,27 @@
void forEachSpawnCandidateChunk(Consumer<ChunkHolder> p_364582_) {
LongIterator longiterator = this.distanceManager.getSpawnCandidateChunks();
+ // FORGE: separated forEach logic into its own method
+ this.forEachChunk(longiterator, this::anyPlayerCloseEnoughForSpawningInternal, p_364582_);
+ }
+
+ /** FORGE: grab forced chunks, use forEachChunk to avoid duplicate logic */
+ void forEachForcedChunk(Consumer<ChunkHolder> callback) {
+ LongIterator longiterator = this.distanceManager.forcedTickets.keySet().iterator();
+ this.forEachChunk(longiterator, pos -> true, callback);
+ }
+
+ /** FORGE: check if there are any forced chunks */
+ boolean hasForcedChunks() {
+ return !this.distanceManager.forcedTickets.isEmpty();
+ }
+
+ /** FORGE: commonize logic between forEachSpawnCandidateChunk and forEachForcedChunk */
+ private void forEachChunk(LongIterator longiterator, java.util.function.Predicate<ChunkPos> filter, Consumer<ChunkHolder> p_364582_) {
while (longiterator.hasNext()) {
long i = longiterator.nextLong();
ChunkHolder chunkholder = this.visibleChunkMap.get(i);
- if (chunkholder != null && this.anyPlayerCloseEnoughForSpawningInternal(chunkholder.getPos())) {
+ if (chunkholder != null && filter.test(chunkholder.getPos())) {
p_364582_.accept(chunkholder);
}
}
@@ -1102,7 +_,7 @@
}
@@ -4,7 +4,7 @@
final Executor mainThreadExecutor;
private long ticketTickCounter;
private int simulationDistance = 10;
+ private final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> forcedTickets = new Long2ObjectOpenHashMap<>();
+ final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> forcedTickets = new Long2ObjectOpenHashMap<>();
protected DistanceManager(Executor p_140774_, Executor p_140775_) {
TaskScheduler<Runnable> taskscheduler = TaskScheduler.wrapExecutor("player ticket throttler", p_140775_);
@@ -44,7 +44,7 @@
+ }
+
+ public <T> void addRegionTicket(TicketType<T> p_140841_, ChunkPos p_140842_, int p_140843_, T p_140844_, boolean forceTicks) {
+ Ticket<T> ticket = new Ticket<>(p_140841_, ChunkLevel.byStatus(FullChunkStatus.FULL) - p_140843_, p_140844_, forceTicks);
+ Ticket<T> ticket = new Ticket<>(p_140841_, ChunkLevel.byStatus(FullChunkStatus.FULL) - p_140843_, p_140844_, forceTicks);
long i = p_140842_.toLong();
this.addTicket(i, ticket);
this.tickingTicketsTracker.addTicket(i, ticket);
@@ -11,6 +11,34 @@
ChunkAccess chunkaccess1 = chunkholder.getChunkIfPresent(ChunkStatus.FULL);
if (chunkaccess1 != null) {
this.storeInCache(i, chunkaccess1, ChunkStatus.FULL);
@@ -368,9 +_,25 @@
}
private void collectTickingChunks(List<LevelChunk> p_368970_) {
- this.chunkMap.forEachSpawnCandidateChunk(p_358696_ -> {
+ // FORGE: If there are no forced chunks, just do the vanilla logic
+ if (!this.chunkMap.hasForcedChunks()) {
+ this.chunkMap.forEachSpawnCandidateChunk(this.getChunkCollector(p_368970_, chunk -> this.level.isNaturalSpawningAllowed(chunk.getPos())));
+ return;
+ }
+
+ // FORGE: We have forced chunks? Ok, use a linked hash set to preserve order
+ Set<LevelChunk> set = new java.util.LinkedHashSet<>();
+ this.chunkMap.forEachSpawnCandidateChunk(this.getChunkCollector(set, chunk -> this.level.isNaturalSpawningAllowed(chunk.getPos())));
+ this.chunkMap.forEachForcedChunk(this.getChunkCollector(set, chunk -> true));
+ p_368970_.addAll(set);
+ }
+
+ /** FORGE: Isolate chunk collection callback */
+ private Consumer<ChunkHolder> getChunkCollector(java.util.Collection<LevelChunk> p_368970_, java.util.function.Predicate<LevelChunk> predicate) {
+ return (p_358696_ -> {
LevelChunk levelchunk = p_358696_.getTickingChunk();
- if (levelchunk != null && this.level.isNaturalSpawningAllowed(p_358696_.getPos())) {
+ // FORGE: Use custom predicate instead of only checking isNaturalSpawningAllowed
+ if (levelchunk != null && predicate.test(levelchunk)) {
p_368970_.add(levelchunk);
}
});
@@ -466,11 +_,19 @@
}
@@ -0,0 +1,21 @@
--- a/net/minecraft/world/entity/npc/VillagerTrades.java
+++ b/net/minecraft/world/entity/npc/VillagerTrades.java
@@ -1367,6 +_,7 @@
private final int villagerXp;
public EmeraldsForVillagerTypeItem(int p_35669_, int p_35670_, int p_35671_, Map<VillagerType, Item> p_35672_) {
+ if (false) // FORGE: Modders can add custom villager types, so remove this validation
BuiltInRegistries.VILLAGER_TYPE.stream().filter(p_35680_ -> !p_35672_.containsKey(p_35680_)).findAny().ifPresent(p_327046_ -> {
throw new IllegalStateException("Missing trade for villager type: " + BuiltInRegistries.VILLAGER_TYPE.getKey(p_327046_));
});
@@ -1380,7 +_,9 @@
@Override
public MerchantOffer getOffer(Entity p_219685_, RandomSource p_219686_) {
if (p_219685_ instanceof VillagerDataHolder villagerdataholder) {
- ItemCost itemcost = new ItemCost(this.trades.get(villagerdataholder.getVillagerData().getType()), this.cost);
+ Item item = this.trades.get(villagerdataholder.getVillagerData().getType());
+ if (item == null) return null; // FORGE: Account for modded villager types by returning null if there is no trade
+ ItemCost itemcost = new ItemCost(item, this.cost);
return new MerchantOffer(itemcost, new ItemStack(Items.EMERALD), this.maxUses, this.villagerXp, 0.05F);
} else {
return null;
@@ -0,0 +1,12 @@
--- a/net/minecraft/world/entity/npc/VillagerType.java
+++ b/net/minecraft/world/entity/npc/VillagerType.java
@@ -69,4 +_,9 @@
public static VillagerType byBiome(Holder<Biome> p_204074_) {
return p_204074_.unwrapKey().map(BY_BIOME::get).orElse(PLAINS);
}
+
+ /** FORGE: Registers the VillagerType that will spawn in the given biome. This method should be called during FMLCommonSetupEvent using event.enqueueWork() */
+ public static void registerBiomeType(ResourceKey<Biome> biomeKey, VillagerType villagerType) {
+ BY_BIOME.put(biomeKey, villagerType);
+ }
}
@@ -129,7 +129,7 @@
super.blockUsingShield(p_36295_);
ItemStack itemstack = this.getItemBlockingWith();
- if (p_36295_.canDisableShield() && itemstack != null) {
+ if (itemstack != null && itemstack.canDisableShield(this.useItem, this, p_36295_)) {
+ if (itemstack != null && p_36295_.getWeaponItem().canDisableShield(itemstack, this, p_36295_)) {
this.disableShield(itemstack);
}
}
@@ -142,6 +142,19 @@
if (!this.level().isClientSide) {
this.awardStat(Stats.ITEM_USED.get(this.useItem.getItem()));
}
@@ -931,8 +_,11 @@
if (p_36383_ >= 3.0F) {
int i = 1 + Mth.floor(p_36383_);
InteractionHand interactionhand = this.getUsedItemHand();
+ // FORGE: cache this.useItem -- if this.stopUsingItem() is called, it will be set to ItemStack.EMPTY
+ ItemStack currentItem = this.useItem;
this.useItem.hurtAndBreak(i, this, getSlotForHand(interactionhand));
- if (this.useItem.isEmpty()) {
+ // FORGE: use cached item since this.useItem could be ItemStack.EMPTY
+ if (currentItem.isEmpty()) {
if (interactionhand == InteractionHand.MAIN_HAND) {
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
} else {
@@ -949,10 +_,13 @@
@Override
protected void actuallyHurt(ServerLevel p_365751_, DamageSource p_36312_, float p_36313_) {
@@ -10,7 +10,7 @@
if (optional.isEmpty()) {
return InteractionResult.PASS;
} else {
@@ -115,5 +_,16 @@
@@ -115,5 +_,21 @@
private Optional<BlockState> getStripped(BlockState p_150691_) {
return Optional.ofNullable(STRIPPABLES.get(p_150691_.getBlock()))
.map(p_359378_ -> p_359378_.defaultBlockState().setValue(RotatedPillarBlock.AXIS, p_150691_.getValue(RotatedPillarBlock.AXIS)));
@@ -25,5 +25,10 @@
+ public static BlockState getAxeStrippingState(BlockState originalState) {
+ Block block = STRIPPABLES.get(originalState.getBlock());
+ return block != null ? block.defaultBlockState().setValue(RotatedPillarBlock.AXIS, originalState.getValue(RotatedPillarBlock.AXIS)) : null;
+ }
+
+ @Override
+ public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) {
+ return true;
}
}
@@ -5,10 +5,27 @@
import org.slf4j.Logger;
-public final class ItemStack implements DataComponentHolder {
+public final class ItemStack implements DataComponentHolder, net.minecraftforge.common.extensions.IForgeItemStack {
+public final class ItemStack extends net.minecraftforge.common.capabilities.CapabilityProvider<ItemStack> implements DataComponentHolder, net.minecraftforge.common.extensions.IForgeItemStack {
private static final List<Component> OP_NBT_WARNING = List.of(
Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD),
Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED),
@@ -261,13 +_,16 @@
}
private ItemStack(ItemLike p_331826_, int p_332766_, PatchedDataComponentMap p_333722_) {
+ super(ItemStack.class, true);
this.item = p_331826_.asItem();
this.count = p_332766_;
this.components = p_333722_;
this.getItem().verifyComponentsAfterLoad(this);
+ gatherCapabilities(() -> this.item.getCapabilityProvider(this));
}
private ItemStack(@Nullable Void p_282703_) {
+ super(ItemStack.class, false);
this.item = null;
this.components = new PatchedDataComponentMap(DataComponentMap.EMPTY);
}
@@ -357,13 +_,22 @@
}
@@ -33,6 +50,34 @@
if (player != null && interactionresult instanceof InteractionResult.Success interactionresult$success && interactionresult$success.wasItemInteraction()) {
player.awardStat(Stats.ITEM_USED.get(item));
}
@@ -468,18 +_,26 @@
}
public void hurtAndBreak(int p_220158_, ServerLevel p_342197_, @Nullable ServerPlayer p_220160_, Consumer<Item> p_343361_) {
- int i = this.processDurabilityChange(p_220158_, p_342197_, p_220160_);
+ // FORGE: use context-sensitive sister of processDurabilityChange that calls IForgeItem.damageItem
+ int i = this.processDurabilityChange(p_220158_, p_342197_, p_220160_, true, p_343361_);
if (i != 0) {
this.applyDamage(this.getDamageValue() + i, p_220160_, p_343361_);
}
}
private int processDurabilityChange(int p_362423_, ServerLevel p_364910_, @Nullable ServerPlayer p_365570_) {
+ return this.processDurabilityChange(p_362423_, p_364910_, p_365570_, false, p_359411_ -> { });
+ }
+
+ /** FORGE: context-sensitive sister of processDurabilityChange that calls IForgeItem.damageItem */
+ private int processDurabilityChange(int p_362423_, ServerLevel p_364910_, @Nullable ServerPlayer p_365570_, boolean canBreak, Consumer<Item> onBreak) {
if (!this.isDamageableItem()) {
return 0;
} else if (p_365570_ != null && p_365570_.hasInfiniteMaterials()) {
return 0;
} else {
+ // FORGE: modify the base damage based on the item's impl of IForgeItem.damageItem
+ p_362423_ = this.damageItem(p_362423_, p_364910_, p_365570_, canBreak, onBreak);
return p_362423_ > 0 ? EnchantmentHelper.processDurabilityChange(p_364910_, this, p_362423_) : p_362423_;
}
}
@@ -516,7 +_,13 @@
p_41623_,
serverlevel,
@@ -41,7 +86,7 @@
+ p_341563_ -> {
+ if (p_41624_ instanceof Player player) {
+ net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, this, p_335324_);
+ player.stopUsingItem(); // Forge: fix MC-168573
+ if (player.getUseItem() == this) player.stopUsingItem(); // Forge: fix MC-168573
+ }
+ p_41624_.onEquippedItemBroken(p_341563_, p_335324_);
+ }
@@ -158,12 +158,12 @@
T t = p_261885_.tryCast(enderdragonpart);
if (t != null && p_261688_.test(t)) {
p_262071_.add(t);
@@ -932,16 +_,15 @@
@@ -932,17 +_,16 @@
public abstract Scoreboard getScoreboard();
public void updateNeighbourForOutputSignal(BlockPos p_46718_, Block p_46719_) {
- for (Direction direction : Direction.Plane.HORIZONTAL) {
+ for (Direction direction : Direction.valuesView()) {
+ for (Direction direction : Direction.getUpdateOrder()) {
BlockPos blockpos = p_46718_.relative(direction);
if (this.hasChunkAt(blockpos)) {
BlockState blockstate = this.getBlockState(blockpos);
@@ -175,10 +175,12 @@
blockpos = blockpos.relative(direction);
blockstate = this.getBlockState(blockpos);
- if (blockstate.is(Blocks.COMPARATOR)) {
- this.neighborChanged(blockstate, blockpos, p_46719_, null, false);
+ if (blockstate.getWeakChanges(this, blockpos)) {
this.neighborChanged(blockstate, blockpos, p_46719_, null, false);
+ blockstate.onNeighborChange(this, blockpos, p_46718_);
}
}
}
@@ -1044,6 +_,20 @@
}
@@ -31,12 +31,12 @@
p_368198_.addFreshEntity(primedtnt);
}
+ @Deprecated //Forge: Prefer using IForgeBlock#catchFire
+ @Deprecated //Forge: Prefer using IForgeBlock#onCaughtFire
public static void explode(Level p_57434_, BlockPos p_57435_) {
explode(p_57434_, p_57435_, null);
}
+ @Deprecated //Forge: Prefer using IForgeBlock#catchFire
+ @Deprecated //Forge: Prefer using IForgeBlock#onCaughtFire
private static void explode(Level p_57437_, BlockPos p_57438_, @Nullable LivingEntity p_57439_) {
if (!p_57437_.isClientSide) {
PrimedTnt primedtnt = new PrimedTnt(
@@ -1,13 +1,24 @@
--- a/net/minecraft/world/level/storage/LevelSummary.java
+++ b/net/minecraft/world/level/storage/LevelSummary.java
@@ -277,6 +_,10 @@
}
}
@@ -14,7 +_,7 @@
import net.minecraft.world.level.LevelSettings;
import org.apache.commons.lang3.StringUtils;
+ public boolean isLifecycleExperimental() {
+ return this.settings.getLifecycle().equals(com.mojang.serialization.Lifecycle.experimental());
-public class LevelSummary implements Comparable<LevelSummary> {
+public class LevelSummary implements Comparable<LevelSummary>, net.minecraftforge.common.extensions.IForgeLevelSummary {
public static final Component PLAY_WORLD = Component.translatable("selectWorld.select");
private final LevelSettings settings;
private final LevelVersion levelVersion;
@@ -275,6 +_,12 @@
public boolean canRecreate() {
return false;
}
+ }
+
+ // TODO Forge: Remove in 1.22. It is kept here for binary compatibility, but already exists in IForgeLevelSummary
+ @Deprecated(forRemoval = true, since = "1.21.4")
+ public boolean isLifecycleExperimental() {
+ return net.minecraftforge.common.extensions.IForgeLevelSummary.super.isLifecycleExperimental();
}
public static class SymlinkLevelSummary extends LevelSummary {
private static final Component MORE_INFO_BUTTON = Component.translatable("symlink_warning.more_info");
private static final Component INFO = Component.translatable("symlink_warning.title").withColor(-65536);
+14 -12
View File
@@ -23,27 +23,29 @@ plugins {
dependencyResolutionManagement {
versionCatalogs {
libs {
plugin('apt', 'com.diffplug.eclipse.apt').version('4.2.0')
library('forgespi', 'net.minecraftforge:forgespi:7.1.5') // Needs modlauncher
library('modlauncher', 'net.minecraftforge:modlauncher:10.2.2') // Needs securemodules
library('securemodules', 'net.minecraftforge:securemodules:2.2.20') // Needs unsafe
library('modlauncher', 'net.minecraftforge:modlauncher:10.2.4') // Needs securemodules
library('securemodules', 'net.minecraftforge:securemodules:2.2.21') // Needs unsafe
library('unsafe', 'net.minecraftforge:unsafe:0.9.2')
library('accesstransformers', 'net.minecraftforge:accesstransformers:8.2.0')
library('coremods', 'net.minecraftforge:coremods:5.2.1')
library('accesstransformers', 'net.minecraftforge:accesstransformers:8.2.2')
library('coremods', 'net.minecraftforge:coremods:5.2.6')
library('nashorn', 'org.openjdk.nashorn:nashorn-core:15.4') // Needed by coremods, because the JRE no longer ships JS
library('eventbus', 'net.minecraftforge:eventbus:6.2.8')
library('eventbus', 'net.minecraftforge:eventbus:6.2.27')
library('typetools', 'net.jodah:typetools:0.6.3') // Needed by EventBus because of lambdas
library('mergetool-api', 'net.minecraftforge:mergetool-api:1.0')
library('mixin', 'org.spongepowered:mixin:0.8.7')
library('nulls', 'org.jetbrains:annotations:24.1.0') // Got to have our null annotations!
library('slf4j-api', 'org.slf4j:slf4j-api:2.0.7')
library('maven-artifact', 'org.apache.maven:maven-artifact:3.8.5')
library('maven-artifact', 'org.apache.maven:maven-artifact:3.8.8')
// Google's InMemory File System. Used by ForgeDev Tests for now, but could be useful for a lot of things.
library('jimfs', 'com.google.jimfs:jimfs:1.3.0')
bundle('jimfs', ['guava', 'failureaccess'])
version('bootstrap', '2.1.3')
version('bootstrap', '2.1.8')
library('bootstrap', 'net.minecraftforge', 'bootstrap' ).versionRef('bootstrap') // Needs modlauncher
library('bootstrap-api', 'net.minecraftforge', 'bootstrap-api' ).versionRef('bootstrap')
library('bootstrap-dev', 'net.minecraftforge', 'bootstrap-dev' ).versionRef('bootstrap')
@@ -60,14 +62,14 @@ dependencyResolutionManagement {
// Terminal Console Appender.. essentually make pretty colors in the console, but it's been a PITA
library('terminalconsoleappender', 'net.minecrell:terminalconsoleappender:1.2.0')
version('jline', '3.12.1')
version('jline', '3.25.1')
library('jline-reader', 'org.jline', 'jline-reader' ).versionRef('jline')
library('jline-terminal', 'org.jline', 'jline-terminal' ).versionRef('jline')
library('jline-terminal-jna', 'org.jline', 'jline-terminal-jna').versionRef('jline') // Colors and tab completeion
bundle('terminalconsoleappender', ['terminalconsoleappender', 'jline-reader', 'jline-terminal', 'jline-terminal-jna'])
// The core of our configuration system, it has many flaws, but it works for the most part
version('night-config', '3.7.3')
version('night-config', '3.7.4')
library('night-config-toml', 'com.electronwill.night-config', 'toml').versionRef('night-config')
library('night-config-core', 'com.electronwill.night-config', 'core').versionRef('night-config')
bundle('night-config', ['night-config-toml', 'night-config-core'])
@@ -84,12 +86,12 @@ dependencyResolutionManagement {
library('gson', 'com.google.code.gson:gson:2.10.1')
library('guava', 'com.google.guava:guava:32.1.2-jre')
library('failureaccess', 'com.google.guava:failureaccess:1.0.1')
version('log4j', '2.22.1')
library('log4j-api', 'org.apache.logging.log4j', 'log4j-api' ).versionRef('log4j')
library('log4j-core', 'org.apache.logging.log4j', 'log4j-core').versionRef('log4j')
bundle('log4j', ['log4j-api', 'log4j-core'])
library('apache-commons', 'org.apache.commons:commons-lang3:3.14.0')
library('mojang-logging', 'com.mojang:logging:1.2.7')
library('jopt-simple', 'net.sf.jopt-simple:jopt-simple:5.0.4')
@@ -0,0 +1,16 @@
{
"values": [
"minecraft:flowering_azalea_leaves",
"minecraft:flowering_azalea",
"minecraft:mangrove_propagule",
"minecraft:pink_petals",
"minecraft:chorus_flower",
"minecraft:spore_blossom",
"#c:flowers/small",
"#c:flowers/tall",
{
"id": "#minecraft:flowers",
"required": false
}
]
}
@@ -0,0 +1,24 @@
{
"values": [
"minecraft:dandelion",
"minecraft:poppy",
"minecraft:blue_orchid",
"minecraft:allium",
"minecraft:azure_bluet",
"minecraft:red_tulip",
"minecraft:orange_tulip",
"minecraft:white_tulip",
"minecraft:pink_tulip",
"minecraft:oxeye_daisy",
"minecraft:cornflower",
"minecraft:lily_of_the_valley",
"minecraft:wither_rose",
"minecraft:torchflower",
"minecraft:open_eyeblossom",
"minecraft:closed_eyeblossom",
{
"id": "#minecraft:small_flowers",
"required": false
}
]
}
@@ -0,0 +1,13 @@
{
"values": [
"minecraft:sunflower",
"minecraft:lilac",
"minecraft:peony",
"minecraft:rose_bush",
"minecraft:pitcher_plant",
{
"id": "minecraft:tall_flowers",
"required": false
}
]
}
@@ -0,0 +1,16 @@
{
"values": [
"minecraft:flowering_azalea_leaves",
"minecraft:flowering_azalea",
"minecraft:mangrove_propagule",
"minecraft:pink_petals",
"minecraft:chorus_flower",
"minecraft:spore_blossom",
"#c:flowers/small",
"#c:flowers/tall",
{
"id": "#minecraft:flowers",
"required": false
}
]
}
@@ -0,0 +1,24 @@
{
"values": [
"minecraft:dandelion",
"minecraft:poppy",
"minecraft:blue_orchid",
"minecraft:allium",
"minecraft:azure_bluet",
"minecraft:red_tulip",
"minecraft:orange_tulip",
"minecraft:white_tulip",
"minecraft:pink_tulip",
"minecraft:oxeye_daisy",
"minecraft:cornflower",
"minecraft:lily_of_the_valley",
"minecraft:wither_rose",
"minecraft:torchflower",
"minecraft:open_eyeblossom",
"minecraft:closed_eyeblossom",
{
"id": "#minecraft:small_flowers",
"required": false
}
]
}
@@ -0,0 +1,13 @@
{
"values": [
"minecraft:sunflower",
"minecraft:lilac",
"minecraft:peony",
"minecraft:rose_bush",
"minecraft:pitcher_plant",
{
"id": "minecraft:tall_flowers",
"required": false
}
]
}
@@ -0,0 +1,132 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:any_of",
"terms": [
{
"action": "shears_dig",
"condition": "forge:can_tool_perform_action"
},
{
"condition": "minecraft:match_tool",
"predicate": {
"predicates": {
"minecraft:enchantments": [
{
"enchantments": "minecraft:silk_touch",
"levels": {
"min": 1
}
}
]
}
}
}
]
}
],
"name": "minecraft:pale_oak_leaves"
},
{
"type": "minecraft:item",
"conditions": [
{
"condition": "minecraft:survives_explosion"
},
{
"chances": [
0.05,
0.0625,
0.083333336,
0.1
],
"condition": "minecraft:table_bonus",
"enchantment": "minecraft:fortune"
}
],
"name": "minecraft:pale_oak_sapling"
}
]
}
],
"rolls": 1.0
},
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:any_of",
"terms": [
{
"action": "shears_dig",
"condition": "forge:can_tool_perform_action"
},
{
"condition": "minecraft:match_tool",
"predicate": {
"predicates": {
"minecraft:enchantments": [
{
"enchantments": "minecraft:silk_touch",
"levels": {
"min": 1
}
}
]
}
}
}
]
}
}
],
"entries": [
{
"type": "minecraft:item",
"conditions": [
{
"chances": [
0.02,
0.022222223,
0.025,
0.033333335,
0.1
],
"condition": "minecraft:table_bonus",
"enchantment": "minecraft:fortune"
}
],
"functions": [
{
"add": false,
"count": {
"type": "minecraft:uniform",
"max": 2.0,
"min": 1.0
},
"function": "minecraft:set_count"
},
{
"function": "minecraft:explosion_decay"
}
],
"name": "minecraft:stick"
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/pale_oak_leaves"
}
@@ -0,0 +1,13 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"group": "chest_boat",
"ingredients": [
"#c:chests/wooden",
"minecraft:pale_oak_boat"
],
"result": {
"count": 1,
"id": "minecraft:pale_oak_chest_boat"
}
}
@@ -0,0 +1,17 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"group": "wooden_fence",
"key": {
"#": "#c:rods/wooden",
"W": "minecraft:pale_oak_planks"
},
"pattern": [
"W#W",
"W#W"
],
"result": {
"count": 3,
"id": "minecraft:pale_oak_fence"
}
}
@@ -0,0 +1,17 @@
{
"type": "minecraft:crafting_shaped",
"category": "redstone",
"group": "wooden_fence_gate",
"key": {
"#": "#c:rods/wooden",
"W": "minecraft:pale_oak_planks"
},
"pattern": [
"#W#",
"#W#"
],
"result": {
"count": 1,
"id": "minecraft:pale_oak_fence_gate"
}
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"group": "wooden_sign",
"key": {
"#": "minecraft:pale_oak_planks",
"X": "#c:rods/wooden"
},
"pattern": [
"###",
"###",
" X "
],
"result": {
"count": 3,
"id": "minecraft:pale_oak_sign"
}
}
+1 -1
View File
@@ -3,6 +3,6 @@
"description": {
"translate": "pack.forge.description"
},
"pack_format": 57
"pack_format": 61
}
}
@@ -14,20 +14,14 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.shaders.FogShape;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.datafixers.util.Either;
import com.mojang.math.Constants;
import com.mojang.math.Transformation;
import net.minecraft.ChatFormatting;
import net.minecraft.FileUtil;
import net.minecraft.Util;
import net.minecraft.client.Camera;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.client.color.block.BlockColors;
@@ -35,7 +29,6 @@ import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.ChatComponent;
import net.minecraft.client.gui.components.LerpingBossEvent;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.screens.ConfirmScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.TitleScreen;
@@ -54,7 +47,6 @@ import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.player.ClientInput;
import net.minecraft.client.renderer.FogParameters;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
@@ -63,7 +55,6 @@ import net.minecraft.client.renderer.ShaderProgram;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.BlockElement;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.client.renderer.texture.SpriteContents;
import net.minecraft.client.renderer.texture.TextureAtlas;
@@ -71,14 +62,15 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.language.I18n;
import net.minecraft.client.resources.metadata.animation.FrameSize;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelDebugName;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.SpriteGetter;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.sounds.SoundEngine;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.locale.Language;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.ChatType;
@@ -100,10 +92,8 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Blocks;
@@ -113,20 +103,17 @@ import net.minecraft.world.level.material.FogType;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
import net.minecraftforge.client.event.ClientPauseChangeEvent;
import net.minecraftforge.client.event.ClientPlayerChangeGameTypeEvent;
import net.minecraftforge.client.event.SystemMessageReceivedEvent;
import net.minecraftforge.client.event.ComputeFovModifierEvent;
import net.minecraftforge.client.event.CustomizeGuiOverlayEvent;
import net.minecraftforge.client.event.EntityRenderersEvent;
import net.minecraftforge.client.event.ForgeEventFactoryClient;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.client.event.ModelEvent;
import net.minecraftforge.client.event.MovementInputUpdateEvent;
import net.minecraftforge.client.event.RecipesUpdatedEvent;
import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
import net.minecraftforge.client.event.RegisterColorHandlersEvent;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
@@ -137,7 +124,6 @@ import net.minecraftforge.client.event.RenderHighlightEvent;
import net.minecraftforge.client.event.RenderTooltipEvent;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.event.ToastAddEvent;
import net.minecraftforge.client.event.ViewportEvent;
import net.minecraftforge.client.event.sound.PlaySoundEvent;
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions;
@@ -150,16 +136,13 @@ import net.minecraftforge.client.model.geometry.GeometryLoaderManager;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
import net.minecraftforge.client.textures.ForgeTextureMetadata;
import net.minecraftforge.client.textures.TextureAtlasSpriteLoaderManager;
import net.minecraftforge.common.ForgeConfig;
import net.minecraftforge.common.ForgeI18n;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.IExtensionPoint;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.gametest.ForgeGameTestHooks;
import net.minecraftforge.network.NetworkContext;
import net.minecraftforge.network.NetworkInitialization;
@@ -174,13 +157,11 @@ import org.apache.logging.log4j.MarkerManager;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -188,7 +169,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -352,7 +332,10 @@ public class ForgeHooksClient {
return LazyInit.INSTANCE;
}
// NO-OP method, kept for bin-compat. Used in TitleScreen.java
@Deprecated(forRemoval = true, since = "1.21.4")
public static void renderMainMenu(TitleScreen gui, GuiGraphics graphics, Font font, int width, int height, int alpha) {
/*
VersionChecker.Status status = getForgeVersionStatus();
if (status == VersionChecker.Status.BETA || status == VersionChecker.Status.BETA_OUTDATED) {
@@ -362,6 +345,7 @@ public class ForgeHooksClient {
line = Component.translatable("forge.update.beta.2");
graphics.drawCenteredString(font, line, width / 2, 4 + (font.lineHeight + 1), 0xFFFFFF | alpha);
}
*/
}
public static String forgeStatusLine;
@@ -922,6 +906,11 @@ public class ForgeHooksClient {
model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName));
}
if (json.has("render_type_fast")) {
var renderTypeHintName = GsonHelper.getAsString(json, "render_type_fast");
model.customData.setRenderTypeFastHint(ResourceLocation.parse(renderTypeHintName));
}
if (json.has("visibility")) {
var visibility = GsonHelper.getAsJsonObject(json, "visibility");
for (var part : visibility.entrySet())
@@ -930,4 +919,44 @@ public class ForgeHooksClient {
return model;
}
/** This is a dirty fucking hack, but it needs to send in the top most render type. */
public static ModelBaker wrapRenderType(ModelBaker parent, RenderTypeGroup group) {
if (group == null || group == RenderTypeGroup.EMPTY || parent.renderType() != null)
return parent;
return new WrapedModelBaker(parent, group);
}
public static ModelBaker wrapRenderType(ModelBaker parent, RenderTypeGroup group, RenderTypeGroup groupFast) {
if (group == null || group == RenderTypeGroup.EMPTY || parent.renderType() != null)
return parent;
return new WrapedModelBaker(parent, group, groupFast);
}
// a record for performance reasons
private record WrapedModelBaker(ModelBaker parent, RenderTypeGroup group, RenderTypeGroup renderTypeFast) implements ModelBaker {
private WrapedModelBaker(ModelBaker parent, RenderTypeGroup group) {
this(parent, group, RenderTypeGroup.EMPTY);
}
@Override
public RenderTypeGroup renderType() {
return group;
}
@Override
public BakedModel bake(ResourceLocation name, ModelState state) {
return parent.bake(name, state);
}
@Override
public SpriteGetter sprites() {
return parent.sprites();
}
@Override
public ModelDebugName rootName() {
return parent.rootName();
}
}
}
@@ -94,14 +94,14 @@ public final class ForgeEventFactoryClient {
/**
* Post an event to the {@link ModLoader#get()} event bus
*/
private static <T extends Event & IModBusEvent> T postModBus(T e) {
private static <T extends Event & IModBusEvent> T fireModBus(T e) {
ML.postEvent(e);
return e;
}
public static void onGatherLayers(Map<EntityType<?>, EntityRenderer<?, ?>> renderers, Map<Model, EntityRenderer<? extends Player, ?>> playerRenderers, Context context) {
// TODO: Why is this a ModLoader event...
postModBus(new EntityRenderersEvent.AddLayers(renderers, playerRenderers, context));
fireModBus(new EntityRenderersEvent.AddLayers(renderers, playerRenderers, context));
}
public static boolean onScreenMouseReleased(Screen screen, double mouseX, double mouseY, int button) {
@@ -295,7 +295,12 @@ public final class ForgeEventFactoryClient {
public static Map<Type, Function<EntityModelSet, SkullModelBase>> onCreateSkullModels() {
var builder = ImmutableMap.<Type, Function<EntityModelSet, SkullModelBase>>builder();
postModBus(new EntityRenderersEvent.CreateSkullModels(builder));
fireModBus(new EntityRenderersEvent.CreateSkullModels(builder));
return builder.build();
}
public static ModelEvent.RegisterModelStateDefinitions onRegisterModeStateDefinitions() {
// This is on the mod bus because it happens during the initial texture reload, which is while the Forge bus is shut down.
return fireModBus(new ModelEvent.RegisterModelStateDefinitions());
}
}
@@ -6,11 +6,12 @@
package net.minecraftforge.client.event;
import com.google.common.base.Preconditions;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@@ -20,6 +21,8 @@ import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.jetbrains.annotations.ApiStatus;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
@@ -106,6 +109,37 @@ public abstract class ModelEvent extends Event {
}
}
/**
* Fired when the {@link net.minecraft.client.resources.model.BlockStateModelLoader BlockStateModelLoader} is notified of the resource manager reloading.
* Allows developers to register {@link net.minecraft.world.level.block.state.StateDefinition StateDefinitons} for blocks that are not in the normal Block registry.
* This is designed to allow for extra models to be loaded in connection with a blockstates json file. This is not intended to allow
* overriding or modification of StateDefinitions from registered Blocks
*
* <p>This event is fired on the {@linkplain FMLJavaModLoadingContext#getModEventBus() mod-specific event bus},
* only on the {@linkplain LogicalSide#CLIENT logical client}.</p>
*/
public static class RegisterModelStateDefinitions extends ModelEvent implements IModBusEvent {
private final Map<ResourceLocation, StateDefinition<Block, BlockState>> states = new HashMap<>();
private final Map<ResourceLocation, StateDefinition<Block, BlockState>> view = Collections.unmodifiableMap(states);
@ApiStatus.Internal
public RegisterModelStateDefinitions() { }
/**
* Returns a read only view of the extra registered models
*/
public Map<ResourceLocation, StateDefinition<Block, BlockState>> getStates() {
return this.view;
}
/**
* Registers a StateDefinition for a synthetic block.
*/
public void register(ResourceLocation key, StateDefinition<Block, BlockState> value) {
states.put(key, value);
}
}
/**
* Allows users to register their own {@link IGeometryLoader geometry loaders} for use in block/item models.
*
@@ -126,7 +160,9 @@ public abstract class ModelEvent extends Event {
* Registers a new geometry loader.
*/
public void register(String name, IGeometryLoader<?> loader) {
var key = ResourceLocation.fromNamespaceAndPath(ModLoadingContext.get().getActiveNamespace(), name);
@SuppressWarnings("removal")
var namespace = ModLoadingContext.get().getActiveNamespace();
var key = ResourceLocation.fromNamespaceAndPath(namespace, name);
Preconditions.checkArgument(!loaders.containsKey(key), "Geometry loader already registered: " + key);
loaders.put(key, loader);
}
@@ -9,8 +9,6 @@ import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
@@ -37,7 +35,6 @@ import java.util.function.Consumer;
* @see MouseInput
* @see KeyInput
*/
@OnlyIn(Dist.CLIENT)
public abstract class ScreenEvent extends Event {
private final Screen screen;
@@ -12,14 +12,11 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.client.loading.ClientModLoader;
import net.minecraftforge.api.distmarker.Dist;
@OnlyIn(Dist.CLIENT)
public class TitleScreenModUpdateIndicator extends Screen {
private static final ResourceLocation VERSION_CHECK_ICONS = ResourceLocation.fromNamespaceAndPath(ForgeVersion.MOD_ID, "textures/gui/version_check_icons.png");
@@ -24,15 +24,12 @@ import org.apache.logging.log4j.Logger;
import net.minecraft.client.Minecraft;
import net.minecraft.server.packs.PackType;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.ForgeConfig;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.client.gui.LoadingErrorScreen;
import net.minecraftforge.resource.ResourcePackLoader;
import net.minecraftforge.server.LanguageHook;
@OnlyIn(Dist.CLIENT)
public class ClientModLoader {
private static final Logger LOGGER = LogManager.getLogger();
private static boolean loading;
@@ -198,6 +198,7 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
private final ItemTransforms transforms;
private TextureAtlasSprite particle;
private RenderTypeGroup lastRenderTypes = RenderTypeGroup.EMPTY;
private RenderTypeGroup lastRenderTypesFast = RenderTypeGroup.EMPTY;
private Builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemTransforms transforms) {
this.isAmbientOcclusion = isAmbientOcclusion;
@@ -208,23 +209,32 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
}
public void addLayer(BakedModel model) {
flushQuads(null);
flushQuads(RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY);
children.add(model);
}
private void addLayer(RenderTypeGroup renderTypes, List<BakedQuad> quads) {
var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle/*, renderTypes*/);
this.addLayer(renderTypes, RenderTypeGroup.EMPTY, quads);
}
private void addLayer(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, List<BakedQuad> quads) {
var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle, renderTypes, renderTypesFast);
quads.forEach(modelBuilder::addUnculledFace);
children.add(modelBuilder.build());
}
private void flushQuads(RenderTypeGroup renderTypes) {
this.flushQuads(renderTypes, RenderTypeGroup.EMPTY);
}
private void flushQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast) {
if (!Objects.equals(renderTypes, lastRenderTypes)) {
if (!quads.isEmpty()) {
addLayer(lastRenderTypes, quads);
addLayer(lastRenderTypes, lastRenderTypesFast, quads);
quads.clear();
}
lastRenderTypes = renderTypes;
lastRenderTypesFast = renderTypesFast;
}
}
@@ -234,20 +244,28 @@ public class CompositeModel implements IUnbakedGeometry<CompositeModel> {
}
public Builder addQuads(RenderTypeGroup renderTypes, BakedQuad... quadsToAdd) {
flushQuads(renderTypes);
return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd);
}
public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, BakedQuad... quadsToAdd) {
flushQuads(renderTypes, renderTypesFast);
Collections.addAll(quads, quadsToAdd);
return this;
}
public Builder addQuads(RenderTypeGroup renderTypes, Collection<BakedQuad> quadsToAdd) {
flushQuads(renderTypes);
return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd);
}
public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, Collection<BakedQuad> quadsToAdd) {
flushQuads(renderTypes, renderTypesFast);
quads.addAll(quadsToAdd);
return this;
}
public BakedModel build() {
if (!quads.isEmpty()) {
addLayer(lastRenderTypes, quads);
addLayer(lastRenderTypes, lastRenderTypesFast, quads);
}
var childrenBuilder = ImmutableMap.<String, BakedModel>builder();
var itemPassesBuilder = ImmutableList.<BakedModel>builder();
@@ -17,6 +17,7 @@ import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraftforge.client.RenderTypeGroup;
import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
import net.minecraftforge.client.model.geometry.IGeometryLoader;
import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
@@ -49,7 +50,7 @@ public class EmptyModel extends SimpleUnbakedGeometry<EmptyModel> {
private static final Material MISSING_TEXTURE = new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation());
public Baked() {
super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS/*, RenderTypeGroup.EMPTY*/);
super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY);
}
@Override
@@ -11,6 +11,8 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.SimpleBakedModel;
import net.minecraft.core.Direction;
import net.minecraftforge.client.RenderTypeGroup;
import java.util.List;
/**
@@ -30,7 +32,30 @@ public interface IModelBuilder<T extends IModelBuilder<T>> {
ItemTransforms transforms,
TextureAtlasSprite particle
){
return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle);
return of(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, RenderTypeGroup.EMPTY);
}
static IModelBuilder<?> of(
boolean hasAmbientOcclusion,
boolean usesBlockLight,
boolean isGui3d,
ItemTransforms transforms,
TextureAtlasSprite particle,
RenderTypeGroup renderTypes
){
return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes);
}
static IModelBuilder<?> of(
boolean hasAmbientOcclusion,
boolean usesBlockLight,
boolean isGui3d,
ItemTransforms transforms,
TextureAtlasSprite particle,
RenderTypeGroup renderTypes,
RenderTypeGroup renderTypesFast
){
return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes, renderTypesFast);
}
/**
@@ -52,9 +77,17 @@ public interface IModelBuilder<T extends IModelBuilder<T>> {
private Simple(
boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
ItemTransforms transforms, TextureAtlasSprite particle
ItemTransforms transforms, TextureAtlasSprite particle, RenderTypeGroup renderTypes
) {
this(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes, RenderTypeGroup.EMPTY);
}
private Simple(
boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d,
ItemTransforms transforms, TextureAtlasSprite particle, RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast
) {
this.builder = new SimpleBakedModel.Builder(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms).particle(particle);
this.builder.renderTypes(renderTypes, renderTypesFast);
}
@Override
@@ -69,7 +102,6 @@ public interface IModelBuilder<T extends IModelBuilder<T>> {
return this;
}
@Deprecated
@Override
public BakedModel build() {
return builder.build();
@@ -37,10 +37,16 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel> {
@Nullable
private ImmutableList<Material> textures;
private final Int2ObjectMap<ResourceLocation> renderTypeNames;
private final Int2ObjectMap<ResourceLocation> renderTypeFastNames;
private ItemLayerModel(@Nullable ImmutableList<Material> textures, Int2ObjectMap<ResourceLocation> renderTypeNames) {
this(textures, renderTypeNames, new Int2ObjectOpenHashMap<>());
}
private ItemLayerModel(@Nullable ImmutableList<Material> textures, Int2ObjectMap<ResourceLocation> renderTypeNames, Int2ObjectMap<ResourceLocation> renderTypeFastNames) {
this.textures = textures;
this.renderTypeNames = renderTypeNames;
this.renderTypeFastNames = renderTypeFastNames;
}
@Override
@@ -69,7 +75,9 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel> {
var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, modelState);
var renderTypeName = renderTypeNames.get(i);
var renderTypes = renderTypeName != null ? context.getRenderType(renderTypeName) : null;
builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, quads);
var renderTypeFastName = renderTypeFastNames.get(i);
var renderTypesFast = renderTypeFastName != null ? context.getRenderType(renderTypeFastName) : null;
builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, renderTypesFast != null ? renderTypesFast : RenderTypeGroup.EMPTY, quads);
}
return builder.build();
@@ -80,20 +88,27 @@ public class ItemLayerModel implements IUnbakedGeometry<ItemLayerModel> {
@Override
public ItemLayerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) {
var renderTypeNames = readRenderTypeNames(jsonObject, "render_types");
var renderTypeFastNames = readRenderTypeNames(jsonObject, "render_types_fast");
return new ItemLayerModel(null, renderTypeNames, renderTypeFastNames);
}
private static Int2ObjectMap<ResourceLocation> readRenderTypeNames(JsonObject jsonObject, String key) {
var renderTypeNames = new Int2ObjectOpenHashMap<ResourceLocation>();
if (jsonObject.has("render_types")) {
var renderTypes = jsonObject.getAsJsonObject("render_types");
if (jsonObject.has(key)) {
var renderTypes = jsonObject.getAsJsonObject(key);
for (var entry : renderTypes.entrySet()) {
var renderType = ResourceLocation.parse(entry.getKey());
for (var layer : entry.getValue().getAsJsonArray())
if (renderTypeNames.put(layer.getAsInt(), renderType) != null)
throw new JsonParseException("Registered duplicate render type for layer " + layer);
throw new JsonParseException("Registered duplicate " + key + " for layer " + layer);
}
}
return new ItemLayerModel(null, renderTypeNames);
return renderTypeNames;
}
@Deprecated(forRemoval = true, since = "1.21.4")
protected void readLayerData(JsonObject jsonObject, String name, Int2ObjectOpenHashMap<ResourceLocation> renderTypeNames, Int2ObjectMap<ForgeFaceData> layerData, boolean logWarning) {
if (!jsonObject.has(name))
return;
@@ -11,31 +11,8 @@ import net.minecraft.client.resources.model.ModelState;
/**
* Simple implementation of {@link ModelState}.
*/
public final class SimpleModelState implements ModelState
{
private final Transformation transformation;
private final boolean uvLocked;
public SimpleModelState(Transformation transformation, boolean uvLocked)
{
this.transformation = transformation;
this.uvLocked = uvLocked;
}
public SimpleModelState(Transformation transformation)
{
public record SimpleModelState(Transformation getRotation, boolean isUvLocked) implements ModelState {
public SimpleModelState(Transformation transformation) {
this(transformation, false);
}
@Override
public Transformation getRotation()
{
return transformation;
}
@Override
public boolean isUvLocked()
{
return uvLocked;
}
}
@@ -16,7 +16,12 @@ import net.minecraftforge.common.data.ExistingFileHelper;
*
* @see ModelProvider
* @see ModelBuilder
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public class BlockModelBuilder extends ModelBuilder<BlockModelBuilder>
{
public BlockModelBuilder(ResourceLocation outputLocation, ExistingFileHelper existingFileHelper)
@@ -12,7 +12,12 @@ import org.jetbrains.annotations.NotNull;
/**
* Stub class to extend for block model data providers, eliminates some
* boilerplate constructor parameters.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class BlockModelProvider extends ModelProvider<BlockModelBuilder> {
public BlockModelProvider(PackOutput output, String modid, ExistingFileHelper existingFileHelper) {
@@ -63,10 +63,17 @@ import org.jetbrains.annotations.VisibleForTesting;
/**
* Data provider for blockstate files. Extends {@link BlockModelProvider} so that
* blockstates and their referenced models can be provided in tandem.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class BlockStateProvider implements DataProvider {
@SuppressWarnings("unused")
private static final Logger LOGGER = LogManager.getLogger();
@SuppressWarnings("unused")
private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create();
@VisibleForTesting
@@ -250,6 +257,42 @@ public abstract class BlockStateProvider implements DataProvider {
models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType));
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast);
}
public void logBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast);
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, String renderType, String renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast);
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, String renderType, String renderTypeFast) {
axisBlock(block,
models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast),
models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast));
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast);
}
public void logBlockWithRenderType(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast);
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, ResourceLocation renderType, ResourceLocation renderTypeFast) {
axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast);
}
public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, ResourceLocation renderType, ResourceLocation renderTypeFast) {
axisBlock(block,
models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast),
models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast));
}
public void axisBlock(RotatedPillarBlock block, ModelFile vertical, ModelFile horizontal) {
getVariantBuilder(block)
.partialState().with(RotatedPillarBlock.AXIS, Axis.Y)
@@ -381,6 +424,38 @@ public abstract class BlockStateProvider implements DataProvider {
stairsBlockInternalWithRenderType(block, name + "_stairs", side, bottom, top, renderType);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, renderType, renderTypeFast);
}
public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, renderType, renderTypeFast);
}
private void stairsBlockInternal(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top) {
ModelFile stairs = models().stairs(baseName, side, bottom, top);
ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top);
@@ -395,6 +470,13 @@ public abstract class BlockStateProvider implements DataProvider {
stairsBlock(block, stairs, stairsInner, stairsOuter);
}
private void stairsBlockInternalWithRenderTypeAndFast(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
ModelFile stairs = models().stairs(baseName, side, bottom, top).renderType(renderType, renderTypeFast);
ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top).renderType(renderType, renderTypeFast);
ModelFile stairsOuter = models().stairsOuter(baseName + "_outer", side, bottom, top).renderType(renderType, renderTypeFast);
stairsBlock(block, stairs, stairsInner, stairsOuter);
}
public void stairsBlock(StairBlock block, ModelFile stairs, ModelFile stairsInner, ModelFile stairsOuter) {
getVariantBuilder(block)
.forAllStatesExcept(state -> {
@@ -532,6 +614,32 @@ public abstract class BlockStateProvider implements DataProvider {
models().fenceSide(name + "_fence_side", texture).renderType(renderType));
}
public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
String baseName = key(block).toString();
fourWayBlock(block,
models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast));
}
public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
fourWayBlock(block,
models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast),
models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast));
}
public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
String baseName = key(block).toString();
fourWayBlock(block,
models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast));
}
public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
fourWayBlock(block,
models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast),
models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast));
}
public void fenceGateBlock(FenceGateBlock block, ResourceLocation texture) {
fenceGateBlockInternal(block, key(block).toString(), texture);
}
@@ -556,6 +664,22 @@ public abstract class BlockStateProvider implements DataProvider {
fenceGateBlockInternalWithRenderType(block, name + "_fence_gate", texture, renderType);
}
public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast);
}
public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, renderType, renderTypeFast);
}
private void fenceGateBlockInternal(FenceGateBlock block, String baseName, ResourceLocation texture) {
ModelFile gate = models().fenceGate(baseName, texture);
ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture);
@@ -572,6 +696,14 @@ public abstract class BlockStateProvider implements DataProvider {
fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen);
}
private void fenceGateBlockInternalWithRenderTypeAndFast(FenceGateBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
ModelFile gate = models().fenceGate(baseName, texture).renderType(renderType, renderTypeFast);
ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast);
ModelFile gateWall = models().fenceGateWall(baseName + "_wall", texture).renderType(renderType, renderTypeFast);
ModelFile gateWallOpen = models().fenceGateWallOpen(baseName + "_wall_open", texture).renderType(renderType, renderTypeFast);
fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen);
}
public void fenceGateBlock(FenceGateBlock block, ModelFile gate, ModelFile gateOpen, ModelFile gateWall, ModelFile gateWallOpen) {
getVariantBuilder(block).forAllStatesExcept(state -> {
ModelFile model = gate;
@@ -613,6 +745,22 @@ public abstract class BlockStateProvider implements DataProvider {
wallBlockInternalWithRenderType(block, name + "_wall", texture, renderType);
}
public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, String renderType, String renderTypeFast) {
wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) {
wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast);
}
public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, renderType, renderTypeFast);
}
private void wallBlockInternal(WallBlock block, String baseName, ResourceLocation texture) {
wallBlock(block, models().wallPost(baseName + "_post", texture),
models().wallSide(baseName + "_side", texture),
@@ -625,6 +773,12 @@ public abstract class BlockStateProvider implements DataProvider {
models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType));
}
private void wallBlockInternalWithRenderTypeAndFast(WallBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) {
wallBlock(block, models().wallPost(baseName + "_post", texture).renderType(renderType, renderTypeFast),
models().wallSide(baseName + "_side", texture).renderType(renderType, renderTypeFast),
models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType, renderTypeFast));
}
public static final ImmutableMap<Direction, Property<WallSide>> WALL_PROPS = ImmutableMap.<Direction, Property<WallSide>>builder()
.put(Direction.EAST, BlockStateProperties.EAST_WALL)
.put(Direction.NORTH, BlockStateProperties.NORTH_WALL)
@@ -677,6 +831,22 @@ public abstract class BlockStateProvider implements DataProvider {
paneBlockInternalWithRenderType(block, name + "_pane", pane, edge, renderType);
}
public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) {
paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) {
paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, renderType, renderTypeFast);
}
public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, renderType, renderTypeFast);
}
private void paneBlockInternal(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge) {
ModelFile post = models().panePost(baseName + "_post", pane, edge);
ModelFile side = models().paneSide(baseName + "_side", pane, edge);
@@ -695,6 +865,15 @@ public abstract class BlockStateProvider implements DataProvider {
paneBlock(block, post, side, sideAlt, noSide, noSideAlt);
}
private void paneBlockInternalWithRenderTypeAndFast(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) {
ModelFile post = models().panePost(baseName + "_post", pane, edge).renderType(renderType, renderTypeFast);
ModelFile side = models().paneSide(baseName + "_side", pane, edge).renderType(renderType, renderTypeFast);
ModelFile sideAlt = models().paneSideAlt(baseName + "_side_alt", pane, edge).renderType(renderType, renderTypeFast);
ModelFile noSide = models().paneNoSide(baseName + "_noside", pane).renderType(renderType, renderTypeFast);
ModelFile noSideAlt = models().paneNoSideAlt(baseName + "_noside_alt", pane).renderType(renderType, renderTypeFast);
paneBlock(block, post, side, sideAlt, noSide, noSideAlt);
}
public void paneBlock(IronBarsBlock block, ModelFile post, ModelFile side, ModelFile sideAlt, ModelFile noSide, ModelFile noSideAlt) {
MultiPartBlockStateBuilder builder = getMultipartBuilder(block)
.part().modelFile(post).addModel().end();
@@ -734,6 +913,22 @@ public abstract class BlockStateProvider implements DataProvider {
doorBlockInternalWithRenderType(block, name + "_door", bottom, top, renderType);
}
public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) {
doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, renderType, renderTypeFast);
}
public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, renderType, renderTypeFast);
}
private void doorBlockInternal(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top) {
ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top);
ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top);
@@ -758,6 +953,18 @@ public abstract class BlockStateProvider implements DataProvider {
doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen);
}
private void doorBlockInternalWithRenderTypeAndFast(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) {
ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top).renderType(renderType, renderTypeFast);
ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top).renderType(renderType, renderTypeFast);
ModelFile bottomRight = models().doorBottomRight(baseName + "_bottom_right", bottom, top).renderType(renderType, renderTypeFast);
ModelFile bottomRightOpen = models().doorBottomRightOpen(baseName + "_bottom_right_open", bottom, top).renderType(renderType, renderTypeFast);
ModelFile topLeft = models().doorTopLeft(baseName + "_top_left", bottom, top).renderType(renderType, renderTypeFast);
ModelFile topLeftOpen = models().doorTopLeftOpen(baseName + "_top_left_open", bottom, top).renderType(renderType, renderTypeFast);
ModelFile topRight = models().doorTopRight(baseName + "_top_right", bottom, top).renderType(renderType, renderTypeFast);
ModelFile topRightOpen = models().doorTopRightOpen(baseName + "_top_right_open", bottom, top).renderType(renderType, renderTypeFast);
doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen);
}
public void doorBlock(DoorBlock block, ModelFile bottomLeft, ModelFile bottomLeftOpen, ModelFile bottomRight, ModelFile bottomRightOpen, ModelFile topLeft, ModelFile topLeftOpen, ModelFile topRight, ModelFile topRightOpen) {
getVariantBuilder(block).forAllStatesExcept(state -> {
int yRot = ((int) state.getValue(DoorBlock.FACING).toYRot()) + 90;
@@ -824,6 +1031,22 @@ public abstract class BlockStateProvider implements DataProvider {
trapdoorBlockInternalWithRenderType(block, name + "_trapdoor", texture, orientable, renderType);
}
public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) {
trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) {
trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast));
}
public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, renderType, renderTypeFast);
}
public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, renderType, renderTypeFast);
}
private void trapdoorBlockInternal(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable) {
ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture) : models().trapdoorBottom(baseName + "_bottom", texture);
ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture) : models().trapdoorTop(baseName + "_top", texture);
@@ -838,6 +1061,13 @@ public abstract class BlockStateProvider implements DataProvider {
trapdoorBlock(block, bottom, top, open, orientable);
}
private void trapdoorBlockInternalWithRenderTypeAndFast(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) {
ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast) : models().trapdoorBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast);
ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture).renderType(renderType, renderTypeFast) : models().trapdoorTop(baseName + "_top", texture).renderType(renderType, renderTypeFast);
ModelFile open = orientable ? models().trapdoorOrientableOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast) : models().trapdoorOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast);
trapdoorBlock(block, bottom, top, open, orientable);
}
public void trapdoorBlock(TrapDoorBlock block, ModelFile bottom, ModelFile top, ModelFile open, boolean orientable) {
getVariantBuilder(block).forAllStatesExcept(state -> {
int xRot = 0;
@@ -28,7 +28,12 @@ import org.jetbrains.annotations.Nullable;
* Can be manually constructed, created by static factory such as
* {@link #allYRotations(ModelFile, int, boolean)}, or created by builder via
* {@link #builder()}.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public final class ConfiguredModel {
/**
@@ -13,6 +13,16 @@ import net.minecraftforge.common.data.ExistingFileHelper;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
*
* This is the only class that doesn't seem to have a vanilla alternative however, it should be a simple helper
* function to replace this functionality for your custom models
*
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class CustomLoaderBuilder<T extends ModelBuilder<T>>
{
protected final ResourceLocation loaderId;
@@ -8,6 +8,12 @@ package net.minecraftforge.client.model.generators;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.VisibleForTesting;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
@VisibleForTesting
public interface IGeneratedBlockState
{
@@ -20,7 +20,12 @@ import net.minecraftforge.common.data.ExistingFileHelper;
/**
* Builder for item models, adds the ability to build overrides via
* {@link #override()}.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public class ItemModelBuilder extends ModelBuilder<ItemModelBuilder> {
protected List<OverrideBuilder> overrides = new ArrayList<>();
@@ -37,7 +42,7 @@ public class ItemModelBuilder extends ModelBuilder<ItemModelBuilder> {
/**
* Get an existing override builder
*
*
* @param index the index of the existing override builder
* @return the override builder
* @throws IndexOutOfBoundsException if {@code} index is out of bounds
@@ -17,7 +17,12 @@ import java.util.Objects;
/**
* Stub class to extend for item model data providers, eliminates some
* boilerplate constructor parameters.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class ItemModelProvider extends ModelProvider<ItemModelBuilder> {
public ItemModelProvider(PackOutput output, String modid, ExistingFileHelper existingFileHelper) {
@@ -50,7 +50,12 @@ import org.joml.Vector3f;
* @see ItemModelBuilder
*
* @param <T> Self type, for simpler chaining of methods.
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
@Nullable
@@ -60,6 +65,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
protected final ExistingFileHelper existingFileHelper;
protected String renderType = null;
protected String renderTypeFast = null;
protected boolean ambientOcclusion = true;
protected GuiLight guiLight = null;
@@ -149,12 +155,17 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
}
/**
* Set the render type for this model.
* Set the render type for this model. Any render types to be used must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
* <p>
* Consider using {@linkplain #renderType(String, String)} if you need to set a render type for
* {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
*
* @param renderType the render type. Must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent}
* @param renderType the render type
* @return this builder
* @throws NullPointerException if {@code renderType} is {@code null}
*
* @throws NullPointerException if {@code renderType} is {@code null}
* @see #renderType(String, String)
*/
public T renderType(String renderType) {
Preconditions.checkNotNull(renderType, "Render type must not be null");
@@ -162,16 +173,55 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
}
/**
* Set the render type for this model.
* Set the render types for this model. Any render types to be used must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
*
* @param renderType the render type. Must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent}
* @param renderType the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics}
* @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}
* @return this builder
* @throws NullPointerException if {@code renderType} is {@code null}
*
* @throws NullPointerException if {@code renderType} is {@code null}
*/
public T renderType(String renderType, String renderTypeFast) {
Preconditions.checkNotNull(renderType, "Render type must not be null");
return renderType(ResourceLocation.parse(renderType), ResourceLocation.parse(renderTypeFast));
}
/**
* Set the render type for this model. Any render types to be used must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
* <p>
* Consider using {@linkplain #renderType(ResourceLocation, ResourceLocation)} if you need to set a render type for
* {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}.
*
* @param renderType the render type
* @return this builder
*
* @throws NullPointerException if {@code renderType} is {@code null}
* @see #renderType(ResourceLocation, ResourceLocation)
*/
public T renderType(ResourceLocation renderType) {
Preconditions.checkNotNull(renderType, "Render type must not be null");
this.renderType = renderType.toString();
this.renderTypeFast = null;
return self();
}
/**
* Set the render types for this model. Any render types to be used must be registered via
* {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}.
*
* @param renderType the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics}
* @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}
* @return this builder
*
* @throws NullPointerException if {@code renderType} is {@code null}
*/
public T renderType(ResourceLocation renderType, ResourceLocation renderTypeFast) {
Preconditions.checkNotNull(renderType, "Render type must not be null");
Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
this.renderType = renderType.toString();
this.renderTypeFast = renderType.toString();
return self();
}
@@ -10,6 +10,12 @@ import com.google.common.base.Preconditions;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.data.ExistingFileHelper;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class ModelFile {
protected ResourceLocation location;
@@ -21,6 +21,12 @@ import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.ExistingFileHelper.ResourceType;
import org.jetbrains.annotations.VisibleForTesting;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public abstract class ModelProvider<T extends ModelBuilder<T>> implements DataProvider {
public static final String BLOCK_FOLDER = "block";
@@ -366,7 +372,8 @@ public abstract class ModelProvider<T extends ModelBuilder<T>> implements DataPr
}
public T leaves(String name, ResourceLocation texture) {
return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture);
return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture)
.renderType("cutout_mipped", "solid");
}
/**
@@ -21,6 +21,12 @@ import com.google.gson.JsonObject;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.Property;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public final class MultiPartBlockStateBuilder implements IGeneratedBlockState {
private final List<PartBuilder> parts = new ArrayList<>();
private final Block owner;
@@ -50,7 +50,12 @@ import org.jetbrains.annotations.Nullable;
* values.
*
* @see BlockStateProvider
*
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
@Deprecated(since = "1.21.4", forRemoval = true)
public class VariantBlockStateBuilder implements IGeneratedBlockState
{
@@ -284,6 +289,7 @@ public class VariantBlockStateBuilder implements IGeneratedBlockState
return true;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public String toString() {
StringBuilder ret = new StringBuilder();
@@ -15,6 +15,11 @@ import net.minecraftforge.common.data.ExistingFileHelper;
import java.util.*;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
public class CompositeModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
{
private static final ResourceLocation NAME = ResourceLocation.fromNamespaceAndPath("forge", "composite");
@@ -14,6 +14,11 @@ import net.minecraftforge.client.model.generators.ModelBuilder;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.registries.ForgeRegistries;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
public class DynamicFluidContainerModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
{
private static final ResourceLocation NAME = ResourceLocation.fromNamespaceAndPath("forge", "fluid_container");
@@ -24,6 +24,11 @@ import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
import net.minecraftforge.client.model.generators.ModelBuilder;
import net.minecraftforge.common.data.ExistingFileHelper;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
{
private static final ResourceLocation NAME = ResourceLocation.fromNamespaceAndPath("forge", "item_layers");
@@ -34,6 +39,7 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
private final Int2ObjectMap<ForgeFaceData> faceData = new Int2ObjectOpenHashMap<>();
private final Map<ResourceLocation, IntSet> renderTypes = new LinkedHashMap<>();
private final Map<ResourceLocation, IntSet> renderTypesFast = new LinkedHashMap<>();
private final IntSet layersWithRenderTypes = new IntOpenHashSet();
protected ItemLayerModelBuilder(T parent, ExistingFileHelper existingFileHelper)
@@ -116,6 +122,23 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
return renderType(asLoc, layers);
}
public ItemLayerModelBuilder<T> renderType(String renderType, String renderTypeFast, int... layers)
{
Preconditions.checkNotNull(renderType, "Render type must not be null");
Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
ResourceLocation asLoc;
if (renderType.contains(":"))
asLoc = ResourceLocation.parse(renderType);
else
asLoc = parent.getLocation().withPath(renderType);
ResourceLocation asLocFast;
if (renderTypeFast.contains(":"))
asLocFast = ResourceLocation.parse(renderTypeFast);
else
asLocFast = parent.getLocation().withPath(renderTypeFast);
return renderType(asLoc, asLocFast, layers);
}
/**
* Set the render type for a set of layers.
*
@@ -145,6 +168,25 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
return this;
}
public ItemLayerModelBuilder<T> renderType(ResourceLocation renderType, ResourceLocation renderTypeFast, int... layers)
{
Preconditions.checkNotNull(renderType, "Render type must not be null");
Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null");
Preconditions.checkNotNull(layers, "Layers must not be null");
Preconditions.checkArgument(layers.length > 0, "At least one layer must be specified");
Preconditions.checkArgument(Arrays.stream(layers).allMatch(i -> i >= 0), "All layers must be >= 0");
var alreadyAssigned = Arrays.stream(layers).filter(layersWithRenderTypes::contains).toArray();
Preconditions.checkArgument(alreadyAssigned.length == 0, "Attempted to re-assign layer render types: " + Arrays.toString(alreadyAssigned));
var renderTypeLayers = renderTypes.computeIfAbsent(renderType, $ -> new IntOpenHashSet());
var renderTypeFastLayers = renderTypesFast.computeIfAbsent(renderType, $ -> new IntOpenHashSet());
Arrays.stream(layers).forEach(layer -> {
renderTypeLayers.add(layer);
renderTypeFastLayers.add(layer);
layersWithRenderTypes.add(layer);
});
return this;
}
@Override
public JsonObject toJson(JsonObject json)
{
@@ -171,6 +213,14 @@ public class ItemLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoad
});
json.add("render_types", renderTypes);
JsonObject renderTypesFast = new JsonObject();
this.renderTypesFast.forEach((renderTypeFast, layers) -> {
JsonArray array = new JsonArray();
layers.intStream().sorted().forEach(array::add);
renderTypesFast.add(renderTypeFast.toString(), array);
});
json.add("render_types_fast", renderTypesFast);
return json;
}
}
@@ -13,6 +13,11 @@ import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
import net.minecraftforge.client.model.generators.ModelBuilder;
import net.minecraftforge.common.data.ExistingFileHelper;
/**
* In 1.21.4 Mojang exposed their data generators for their models. So it should be feasible to just use theirs.
* If you find something lacking feel free to open a PR so that we can extend it.
* @deprecated Use Vanilla's providers {@link net.minecraft.client.data.models.ModelProvider}
*/
public class ObjModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
{
private static final ResourceLocation NAME = ResourceLocation.fromNamespaceAndPath("forge", "obj");
Loaded 100 of 158 files, more files were not shown because too many files have changed in this diff. Show more