Add callback for registering custom BuiltInBlockModels (#5447)

* generate BuiltInBlockModels class tweaker entries

* add BuiltInBlockModelsCallback

* add simple test
This commit is contained in:
Fuzss 2026-07-01 14:35:42 +02:00 committed by GitHub
parent 9e7dc27f05
commit 67c84725b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 178 additions and 0 deletions

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.client.rendering.v1;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.renderer.block.BuiltInBlockModels;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
/**
* Called when custom {@link BlockModel.Unbaked BlockModels} are registered in
* {@link BuiltInBlockModels#createBlockModels(BlockColors)}.
*
* <p>This allows for overriding block models which eventually end up being used in
* {@link net.minecraft.client.renderer.block.BlockModelResolver}.
*/
public interface BuiltInBlockModelsCallback {
Event<BuiltInBlockModelsCallback> EVENT = EventFactory.createArrayBacked(
BuiltInBlockModelsCallback.class,
listeners -> builder -> {
for (BuiltInBlockModelsCallback listener : listeners) {
listener.createBlockModels(builder);
}
});
/**
* @param builder the block models builder instance
*/
void createBlockModels(BuiltInBlockModels.Builder builder);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.rendering;
import java.util.Map;
import com.llamalad7.mixinextras.sugar.Local;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.renderer.block.BuiltInBlockModels;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.world.level.block.state.BlockState;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltInBlockModelsCallback;
@Mixin(BuiltInBlockModels.class)
abstract class BuiltInBlockModelsMixin {
@Inject(method = "createBlockModels",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/renderer/block/BuiltInBlockModels$Builder;build()Ljava/util/Map;"))
private static void createBlockModels(CallbackInfoReturnable<Map<BlockState, BlockModel.Unbaked>> callback, @Local BuiltInBlockModels.Builder builder) {
BuiltInBlockModelsCallback.EVENT.invoker().createBlockModels(builder);
}
}

View file

@ -7,6 +7,7 @@
"AtlasManagerMixin",
"BlockColorsMixin",
"BlockEntityRenderersMixin",
"BuiltInBlockModelsMixin",
"CapeLayerMixin",
"ClientLevelMixin",
"ClientTooltipComponentMixin",

View file

@ -16,6 +16,7 @@
"net.fabricmc.fabric.test.rendering.client.AdvancementRenderingTests",
"net.fabricmc.fabric.test.rendering.client.AtlasTests",
"net.fabricmc.fabric.test.rendering.client.ArmorRenderingTests",
"net.fabricmc.fabric.test.rendering.client.BuiltInBlockModelsTest",
"net.fabricmc.fabric.test.rendering.client.CustomSpriteSourcesTest",
"net.fabricmc.fabric.test.rendering.client.CustomColorResolverTest",
"net.fabricmc.fabric.test.rendering.client.DebugOptionsTests",

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.test.rendering.client;
import net.minecraft.client.renderer.block.BuiltInBlockModels;
import net.minecraft.world.level.block.Blocks;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltInBlockModelsCallback;
public class BuiltInBlockModelsTest implements ClientModInitializer {
@Override
public void onInitializeClient() {
BuiltInBlockModelsCallback.EVENT.register(builder -> {
// Overrides the yellow shulker box built-in block model with an empty one.
// This can be tested in-game e.g., by checking out a minecart with that block.
// summon minecraft:minecart ~ ~ ~ {DisplayState:{Name:"minecraft:yellow_shulker_box"}}
BuiltInBlockModels.createAir(builder, Blocks.DYED_SHULKER_BOX.yellow());
});
}
}

View file

@ -49,6 +49,8 @@ tasks.register('generateClassTweaker') {
FileSystems.newFileSystem(URI.create("jar:${clientJar.toUri()}"), [create: false]).withCloseable { fs ->
generateRenderPipelinesFields(lines, fs)
lines.add("")
generateBuiltInBlockModelsMethods(lines, fs)
}
file('src/main/resources/fabric-transitive-access-wideners-v1.classtweaker').text = String.join('\n', lines) + '\n'
@ -191,12 +193,30 @@ def generateEnchantmentMethods(List<String> lines, FileSystem fs) {
}
}
}
lines.add('transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper$EnchantmentVisitor')
lines.add('transitive-accessible class net/minecraft/world/item/enchantment/EnchantmentHelper$EnchantmentInSlotVisitor')
lines.add('transitive-accessible class net/minecraft/world/item/enchantment/Enchantment$GenericAction')
lines.add('transitive-accessible class net/minecraft/world/item/enchantment/Enchantment$FloatAction')
}
def generateBuiltInBlockModelsMethods(List<String> lines, FileSystem fs) {
lines.add("# Private methods of BuiltInBlockModels and BuiltInBlockModels\$Builder")
for (def node : [ loadClass(fs.getPath("net/minecraft/client/renderer/block/BuiltInBlockModels.class")), loadClass(fs.getPath("net/minecraft/client/renderer/block/BuiltInBlockModels\$Builder.class")) ]) {
for (def method : node.methods) {
// Every method can be useful
if ((method.access & Opcodes.ACC_PRIVATE) != 0 && !method.name.startsWith("lambda\$")) {
lines.add("transitive-accessible method $node.name $method.name $method.desc")
}
}
}
lines.add('transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$Builder')
lines.add('transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$ModelFactory')
lines.add('transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory')
}
ClassNode loadClass(Path path) {
def node = new ClassNode()

View file

@ -413,3 +413,37 @@ transitive-accessible field net/minecraft/client/renderer/RenderPipelines GUI_TE
transitive-accessible field net/minecraft/client/renderer/RenderPipelines GUI_TEXT_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
transitive-accessible field net/minecraft/client/renderer/RenderPipelines OUTLINE_SNIPPET Lcom/mojang/blaze3d/pipeline/RenderPipeline$Snippet;
transitive-accessible method net/minecraft/client/renderer/RenderPipelines register (Lcom/mojang/blaze3d/pipeline/RenderPipeline;)Lcom/mojang/blaze3d/pipeline/RenderPipeline;
# Private methods of BuiltInBlockModels and BuiltInBlockModels$Builder
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels addDefaults (Lnet/minecraft/client/renderer/block/BuiltInBlockModels$Builder;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createAir (Lnet/minecraft/client/renderer/block/BuiltInBlockModels$Builder;Lnet/minecraft/world/level/block/Block;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels special (Lnet/minecraft/client/renderer/special/SpecialModelRenderer$Unbaked;)Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels special (Lnet/minecraft/client/renderer/special/SpecialModelRenderer$Unbaked;Lcom/mojang/math/Transformation;)Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createMobHead (Lnet/minecraft/world/level/block/SkullBlock$Types;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createMobWallHead (Lnet/minecraft/world/level/block/SkullBlock$Types;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createMobHeads (Lnet/minecraft/client/renderer/block/BuiltInBlockModels$Builder;Lnet/minecraft/world/level/block/SkullBlock$Types;Lnet/minecraft/world/level/block/Block;Lnet/minecraft/world/level/block/Block;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createPlayerHead ()Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createPlayerWallHead ()Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createBanner (Lnet/minecraft/world/item/DyeColor;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createWallBanner (Lnet/minecraft/world/item/DyeColor;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createShulkerBox ()Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createDyedShulkerBox (Lnet/minecraft/world/item/DyeColor;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createChest (Lnet/minecraft/resources/Identifier;Lnet/minecraft/world/level/block/state/properties/ChestType;Lnet/minecraft/core/Direction;)Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createSingletonChest (Lnet/minecraft/resources/Identifier;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createChest (Lnet/minecraft/client/renderer/MultiblockChestResources;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createXmasChest (Lnet/minecraft/client/renderer/MultiblockChestResources;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createCopperGolem (Lnet/minecraft/world/level/block/WeatheringCopper$WeatherState;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createDecoratedPot ()Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createBlockStateModelWrapper (Lnet/minecraft/client/color/block/BlockColors;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/block/model/BlockStateModelWrapper$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels combineSpecialAndBlockModels (Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;Lnet/minecraft/client/color/block/BlockColors;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/block/model/CompositeBlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createFlowerBedModel (Lnet/minecraft/client/color/block/BlockColors;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/block/SelectBlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels createEnchantingTable ()Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels specialModelWithPropertyDispatch (Lnet/minecraft/world/level/block/state/properties/Property;Ljava/util/function/Function;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels specialModelWithPropertyDispatch (Lnet/minecraft/world/level/block/state/properties/Property;Lnet/minecraft/world/level/block/state/properties/Property;Ljava/util/function/BiFunction;)Lnet/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory;
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels$Builder <init> (Lnet/minecraft/client/color/block/BlockColors;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels$Builder put (Lnet/minecraft/client/renderer/block/BuiltInBlockModels$ModelFactory;Lnet/minecraft/world/level/block/Block;Lnet/minecraft/world/level/block/Block;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels$Builder put (Lnet/minecraft/client/renderer/block/model/BlockModel$Unbaked;Lnet/minecraft/world/level/block/Block;)V
transitive-accessible method net/minecraft/client/renderer/block/BuiltInBlockModels$Builder put (Lnet/minecraft/client/renderer/block/BuiltInBlockModels$ModelFactory;Lnet/minecraft/world/level/block/Block;)V
transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$Builder
transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$ModelFactory
transitive-accessible class net/minecraft/client/renderer/block/BuiltInBlockModels$SpecialModelFactory