Re-enabled the encoded pattern rendering hack that shows the crafting/processing output's item model when the player is holding shift (but only in the GUI).

This commit is contained in:
Sebastian Hartte
2020-06-16 17:39:53 +02:00
parent d9f039e1f4
commit d1622afa38
9 changed files with 231 additions and 77 deletions
@@ -0,0 +1,149 @@
package appeng.client.render.crafting;
import appeng.client.render.DelegateBakedModel;
import appeng.items.misc.ItemEncodedPattern;
import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.renderer.TransformationMatrix;
import net.minecraft.client.renderer.model.BakedQuad;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ItemCameraTransforms;
import net.minecraft.client.renderer.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.world.World;
import net.minecraftforge.client.model.PerspectiveMapWrapper;
import net.minecraftforge.client.model.data.IDynamicBakedModel;
import net.minecraftforge.client.model.data.IModelData;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Random;
/**
* This model is used to substitute the crafting result's item model for our encoded pattern model if these
* two conditions are met:
* - The player is holding shift
* - The itemstack is being rendered in the UI (not on the ground, etc.)
*
* We do this by abusing a custom {@link ItemOverrideList} since it will be called each frame with the itemstack
* that is about to be rendered. We return a custom IBakedModel ({@link ShiftHoldingModelWrapper} if the player
* is holding down shift from the override list.
* This custom baked model implements {@link #doesHandlePerspectives()} and returns the crafting result model
* if the model for {@link ItemCameraTransforms.TransformType#GUI} is requested.
*/
public class EncodedPatternBakedModel extends DelegateBakedModel {
private final CustomOverrideList overrides;
EncodedPatternBakedModel(IBakedModel baseModel)
{
super(baseModel);
this.overrides = new CustomOverrideList();
}
@Override
public ItemOverrideList getOverrides()
{
return this.overrides;
}
/**
* Since the ItemOverrideList handling comes before handling the perspective awareness (which is the first place
* where we
* know how we are being rendered) we need to remember the model of the crafting output, and make the decision on
* which to render later on.
* Sadly, Forge is pretty inconsistent when it will call the handlePerspective method, so some methods are called
* even on this interim-model.
* Usually those methods only matter for rendering on the ground and other cases, where we wouldn't render the
* crafting output model anyway,
* so in those cases we delegate to the model of the encoded pattern.
*/
private static class ShiftHoldingModelWrapper extends DelegateBakedModel
{
private final IBakedModel outputModel;
private ShiftHoldingModelWrapper( IBakedModel patternModel, IBakedModel outputModel )
{
super(patternModel);
this.outputModel = outputModel;
}
@Override
public boolean doesHandlePerspectives() {
return true;
}
@Override
public IBakedModel handlePerspective( ItemCameraTransforms.TransformType cameraTransformType, MatrixStack mat )
{
// No need to re-check for shift being held since this model is only handed out in that case
if( cameraTransformType == ItemCameraTransforms.TransformType.GUI )
{
ImmutableMap<ItemCameraTransforms.TransformType, TransformationMatrix> transforms = PerspectiveMapWrapper.getTransforms(outputModel.getItemCameraTransforms());
return PerspectiveMapWrapper.handlePerspective( this.outputModel, transforms, cameraTransformType, mat );
}
else
{
return getBaseModel().handlePerspective(cameraTransformType, mat);
}
}
// This determines diffuse lighting in the UI, and since we want to render
// the outputModel in the UI, we need to use it's setting here
@Override
public boolean func_230044_c_() {
return outputModel.func_230044_c_();
}
}
@Override
public boolean doesHandlePerspectives() {
return true;
}
@Override
public IBakedModel handlePerspective( ItemCameraTransforms.TransformType cameraTransformType, MatrixStack mat )
{
return getBaseModel().handlePerspective(cameraTransformType, mat);
}
/**
* Item Override Lists are the only point during item rendering where we can access the item stack that is being
* rendered.
* So this is the point where we actually check if shift is being held, and if so, determine the crafting output
* model.
*/
private class CustomOverrideList extends ItemOverrideList
{
@Nullable
@Override
public IBakedModel getModelWithOverrides(IBakedModel originalModel, ItemStack stack, @Nullable World world, @Nullable LivingEntity entity) {
boolean shiftHeld = Screen.hasShiftDown();
if( shiftHeld )
{
ItemEncodedPattern iep = (ItemEncodedPattern) stack.getItem();
ItemStack output = iep.getOutput( stack );
if( !output.isEmpty() )
{
IBakedModel realModel = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getItemModel( output );
// Give the item model a chance to handle the overrides as well
realModel = realModel.getOverrides().getModelWithOverrides( realModel, output, world, entity );
return new ShiftHoldingModelWrapper(getBaseModel(), realModel);
}
}
return getBaseModel().getOverrides().getModelWithOverrides( originalModel, stack, world, entity );
}
}
}
@@ -0,0 +1,36 @@
package appeng.client.render.crafting;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.renderer.model.*;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModelConfiguration;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;
/**
* This model is used to provide the {@link EncodedPatternBakedModel}.
*/
public class EncodedPatternModel implements IModelGeometry<EncodedPatternModel> {
private final ResourceLocation baseModel;
public EncodedPatternModel(ResourceLocation baseModel) {
this.baseModel = baseModel;
}
@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, IUnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
return modelGetter.apply(baseModel).getTextures(modelGetter, missingTextureErrors);
}
@Override
public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) {
IBakedModel baseModel = bakery.getBakedModel(this.baseModel, modelTransform, spriteGetter);
return new EncodedPatternBakedModel( baseModel);
}
}
@@ -0,0 +1,28 @@
package appeng.client.render.crafting;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModelLoader;
/**
* Provides our custom {@link EncodedPatternBakedModel encoded pattern item model}.
*/
public class EncodedPatternModelLoader implements IModelLoader<EncodedPatternModel> {
public static final EncodedPatternModelLoader INSTANCE = new EncodedPatternModelLoader();
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
}
@Override
public EncodedPatternModel read(JsonDeserializationContext deserializationContext, JsonObject modelContents) {
modelContents.remove("loader"); // Avoid recursion
ResourceLocation baseModel = new ResourceLocation(JSONUtils.getString(modelContents, "baseModel"));
return new EncodedPatternModel(baseModel);
}
}
@@ -1,25 +0,0 @@
package appeng.client.render.crafting;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.ItemStackTileEntityRenderer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
/**
* This special model handles switching between rendering the crafting output of an encoded pattern (when shift is being
* held), and showing the encoded pattern itself. Matters are further complicated by only wanting to show the crafting output when
* the pattern is being rendered in the GUI, and not anywhere else.
*/
@OnlyIn(Dist.CLIENT)
public class EncodedPatternRenderer extends ItemStackTileEntityRenderer {
@Override
public void render(ItemStack is, MatrixStack ms, IRenderTypeBuffer buffers, int combinedLight, int combinedOverlay) {
}
}
@@ -1,27 +0,0 @@
package appeng.client.render.crafting;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import appeng.bootstrap.IItemRendering;
import appeng.bootstrap.ItemRenderingCustomizer;
import appeng.core.AppEng;
public class ItemEncodedPatternRendering extends ItemRenderingCustomizer
{
private static final ResourceLocation MODEL = new ResourceLocation( AppEng.MOD_ID, "builtin/encoded_pattern" );
@Override
@OnlyIn( Dist.CLIENT )
public void customize( IItemRendering rendering )
{
// FIXME rendering.builtInModel( "models/item/builtin/encoded_pattern", new ItemEncodedPatternModel() );
// FIXME rendering.model( new ModelResourceLocation( MODEL, "inventory" ) ).variants( MODEL );
}
}