Fix #1273 (Make MultipartBakedModel and WeightedBackedModel implement FabricBakedModel properly) (#1301)

* fix #1273

* Expand testmod to test multipart and weighted models with FRAPI submodels

Co-authored-by: Technici4n <13494793+Technici4n@users.noreply.github.com>
This commit is contained in:
Cool_Mineman 2021-06-10 04:34:01 -05:00 committed by Player
parent be9da31056
commit 8a5c621a87
15 changed files with 261 additions and 20 deletions

4
.gitignore vendored
View file

@ -1,6 +1,10 @@
# Gradle
.gradle
# VSCode
.settings/
.vscode/
# Eclipse
.checkstyle
.classpath

View file

@ -20,10 +20,10 @@ def ENV = System.getenv()
class Globals {
static def baseVersion = "0.34.9"
static def mcVersion = "1.17-rc1"
static def yarnVersion = "+build.5"
static def mcVersion = "1.17"
static def yarnVersion = "+build.6"
static def loaderVersion = "0.11.3"
static def preRelease = true
static def preRelease = false
}
version = Globals.baseVersion + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()

View file

@ -10,5 +10,9 @@ dependencies {
testmodImplementation project(path: ':fabric-models-v0', configuration: 'dev')
testmodImplementation project(path: ':fabric-networking-blockentity-v0', configuration: 'dev')
testmodImplementation project(path: ':fabric-object-builder-api-v1', configuration: 'dev')
testmodImplementation project(path: ':fabric-renderer-indigo', configuration: 'dev')
testmodImplementation project(path: ':fabric-rendering-data-attachment-v1', configuration: 'dev')
testmodImplementation project(path: ':fabric-resource-loader-v0', configuration: 'dev')
testmodImplementation project(path: ':fabric-tag-extensions-v0', configuration: 'dev')
testmodImplementation project(path: ':fabric-tool-attribute-api-v1', configuration: 'dev')
}

View file

@ -0,0 +1,101 @@
/*
* 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.renderer.client;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.MultipartBakedModel;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
@Mixin(MultipartBakedModel.class)
public class MixinMultipartBakedModel implements FabricBakedModel {
@Shadow
@Final
private List<Pair<Predicate<BlockState>, BakedModel>> components;
@Shadow
@Final
private Map<BlockState, BitSet> stateCache;
@Unique
boolean isVanilla = true;
@Override
public boolean isVanillaAdapter() {
return isVanilla;
}
@Inject(at = @At("RETURN"), method = "<init>")
private void onInit(List<Pair<Predicate<BlockState>, BakedModel>> components, CallbackInfo cb) {
for (Pair<Predicate<BlockState>, BakedModel> component : components) {
if (!((FabricBakedModel) component.getRight()).isVanillaAdapter()) {
isVanilla = false;
break;
}
}
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
BitSet bitSet = this.stateCache.get(state);
if (bitSet == null) {
bitSet = new BitSet();
for (int i = 0; i < this.components.size(); i++) {
Pair<Predicate<BlockState>, BakedModel> pair = components.get(i);
if (pair.getLeft().test(state)) {
((FabricBakedModel) pair.getRight()).emitBlockQuads(blockView, state, pos, randomSupplier, context);
bitSet.set(i);
}
}
stateCache.put(state, bitSet);
} else {
for (int i = 0; i < this.components.size(); i++) {
if (bitSet.get(i)) ((FabricBakedModel) components.get(i).getRight()).emitBlockQuads(blockView, state, pos, randomSupplier, context);
}
}
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
// Vanilla doesn't use MultipartBakedModel for items.
}
}

View file

@ -0,0 +1,86 @@
/*
* 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.renderer.client;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.WeightedBakedModel;
import net.minecraft.item.ItemStack;
import net.minecraft.util.collection.Weighted;
import net.minecraft.util.collection.Weighting;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
@Mixin(WeightedBakedModel.class)
public class MixinWeightedBakedModel implements FabricBakedModel {
@Shadow
@Final
private int totalWeight;
@Shadow
@Final
private List<Weighted.Present<BakedModel>> models;
@Unique
boolean isVanilla = true;
@Inject(at = @At("RETURN"), method = "<init>")
private void onInit(List<Weighted.Present<BakedModel>> models, CallbackInfo cb) {
for (int i = 0; i < models.size(); i++) {
if (!((FabricBakedModel) models.get(i).getData()).isVanillaAdapter()) {
isVanilla = false;
break;
}
}
}
@Override
public boolean isVanillaAdapter() {
return isVanilla;
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
Weighted.Present<BakedModel> selected = Weighting.getAt(this.models, Math.abs((int) randomSupplier.get().nextLong()) % this.totalWeight).orElse(null);
if (selected != null) {
((FabricBakedModel) selected.getData()).emitBlockQuads(blockView, state, pos, randomSupplier, context);
}
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
Weighted.Present<BakedModel> selected = Weighting.getAt(this.models, Math.abs((int) randomSupplier.get().nextLong()) % this.totalWeight).orElse(null);
if (selected != null) {
((FabricBakedModel) selected.getData()).emitItemQuads(stack, randomSupplier, context);
}
}
}

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.renderer.client;
package net.fabricmc.fabric.mixin.renderer.client.debughud;
import java.util.List;

View file

@ -1,9 +1,9 @@
{
"required": false,
"package": "net.fabricmc.fabric.mixin.renderer",
"package": "net.fabricmc.fabric.mixin.renderer.client.debughud",
"compatibilityLevel": "JAVA_16",
"client": [
"client.MixinDebugHud"
"MixinDebugHud"
],
"injectors": {
"defaultRequire": 1

View file

@ -4,6 +4,8 @@
"compatibilityLevel": "JAVA_16",
"client": [
"client.MixinBakedModel",
"client.MixinMultipartBakedModel",
"client.MixinWeightedBakedModel",
"client.MixinSpriteAtlasTexture"
],
"injectors": {

View file

@ -27,13 +27,19 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
public final class FrameBlock extends Block implements BlockEntityProvider {
public FrameBlock(Settings settings) {
super(settings);
public final Identifier id;
public FrameBlock(Identifier id) {
super(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
this.id = id;
}
@Override

View file

@ -22,8 +22,8 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
@ -84,7 +84,7 @@ public final class FrameBlockEntity extends BlockEntity implements RenderAttachm
@Override
public void fromClientTag(NbtCompound tag) {
System.out.println("Recieved sync packet");
System.out.println("Received sync packet");
if (tag.contains("block", NbtType.STRING)) {
this.block = Registry.BLOCK.get(new Identifier(tag.getString("block")));

View file

@ -16,14 +16,14 @@
package net.fabricmc.fabric.test.renderer.simple;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
/**
@ -34,12 +34,24 @@ import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityT
* <p>There are no fancy shaders or glow that is provided by this renderer test.
*/
public final class RendererTest implements ModInitializer {
public static final Block FRAME = new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque());
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME).build(null);
public static final FrameBlock[] FRAMES = new FrameBlock[] {
new FrameBlock(id("frame")),
new FrameBlock(id("frame_multipart")),
new FrameBlock(id("frame_weighted")),
};
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAMES).build(null);
@Override
public void onInitialize() {
Registry.register(Registry.BLOCK, new Identifier("fabric-renderer-api-v1-testmod", "frame"), FRAME);
Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier("fabric-renderer-api-v1-testmod", "frame"), FRAME_BLOCK_ENTITY);
for (FrameBlock frameBlock : FRAMES) {
Registry.register(Registry.BLOCK, frameBlock.id, frameBlock);
Registry.register(Registry.ITEM, frameBlock.id, new BlockItem(frameBlock, new Item.Settings().group(ItemGroup.MISC)));
}
Registry.register(Registry.BLOCK_ENTITY_TYPE, id("frame"), FRAME_BLOCK_ENTITY);
}
public static Identifier id(String path) {
return new Identifier("fabric-renderer-api-v1-testmod", path);
}
}

View file

@ -22,7 +22,6 @@ import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.client.model.ModelProviderContext;
import net.fabricmc.fabric.api.client.model.ModelProviderException;
import net.fabricmc.fabric.api.client.model.ModelResourceProvider;
/**
@ -33,7 +32,7 @@ final class FrameModelResourceProvider implements ModelResourceProvider {
@Nullable
@Override
public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException {
public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) {
if (resourceId.equals(FRAME_MODEL_ID)) {
return new FrameUnbakedModel();
}

View file

@ -21,12 +21,16 @@ import net.minecraft.client.render.RenderLayer;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.test.renderer.simple.FrameBlock;
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
public final class RendererClientTest implements ClientModInitializer {
@Override
public void onInitializeClient() {
ModelLoadingRegistry.INSTANCE.registerResourceProvider(manager -> new FrameModelResourceProvider());
BlockRenderLayerMap.INSTANCE.putBlock(RendererTest.FRAME, RenderLayer.getCutoutMipped());
for (FrameBlock frameBlock : RendererTest.FRAMES) {
BlockRenderLayerMap.INSTANCE.putBlock(frameBlock, RenderLayer.getCutoutMipped());
}
}
}

View file

@ -0,0 +1,10 @@
{
"__comment": "We test that MultipartBakedModel works correctly.",
"multipart": [
{
"apply": {
"model": "fabric-renderer-api-v1-testmod:block/frame"
}
}
]
}

View file

@ -0,0 +1,13 @@
{
"__comment": "We test that WeightedBakedModel works correctly, hence the two variants.",
"variants": {
"": [
{
"model": "fabric-renderer-api-v1-testmod:block/frame"
},
{
"model": "fabric-renderer-api-v1-testmod:block/frame"
}
]
}
}