diff --git a/src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java b/src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java new file mode 100644 index 000000000..9c04b636a --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java @@ -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 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 ); + } + } + +} diff --git a/src/main/java/appeng/client/render/crafting/EncodedPatternModel.java b/src/main/java/appeng/client/render/crafting/EncodedPatternModel.java new file mode 100644 index 000000000..a1d9962d2 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/EncodedPatternModel.java @@ -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 { + + private final ResourceLocation baseModel; + + public EncodedPatternModel(ResourceLocation baseModel) { + this.baseModel = baseModel; + } + + @Override + public Collection getTextures(IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors) { + return modelGetter.apply(baseModel).getTextures(modelGetter, missingTextureErrors); + } + + @Override + public IBakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform modelTransform, ItemOverrideList overrides, ResourceLocation modelLocation) { + IBakedModel baseModel = bakery.getBakedModel(this.baseModel, modelTransform, spriteGetter); + return new EncodedPatternBakedModel( baseModel); + } + +} diff --git a/src/main/java/appeng/client/render/crafting/EncodedPatternModelLoader.java b/src/main/java/appeng/client/render/crafting/EncodedPatternModelLoader.java new file mode 100644 index 000000000..583c0fe8b --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/EncodedPatternModelLoader.java @@ -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 { + + 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); + } + +} diff --git a/src/main/java/appeng/client/render/crafting/EncodedPatternRenderer.java b/src/main/java/appeng/client/render/crafting/EncodedPatternRenderer.java deleted file mode 100644 index ee46b5a26..000000000 --- a/src/main/java/appeng/client/render/crafting/EncodedPatternRenderer.java +++ /dev/null @@ -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) { - } - -} diff --git a/src/main/java/appeng/client/render/crafting/ItemEncodedPatternRendering.java b/src/main/java/appeng/client/render/crafting/ItemEncodedPatternRendering.java deleted file mode 100644 index bbedf2c52..000000000 --- a/src/main/java/appeng/client/render/crafting/ItemEncodedPatternRendering.java +++ /dev/null @@ -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 ); - } - -} diff --git a/src/main/java/appeng/core/AppEng.java b/src/main/java/appeng/core/AppEng.java index 4d56aa6a4..2e4a63805 100644 --- a/src/main/java/appeng/core/AppEng.java +++ b/src/main/java/appeng/core/AppEng.java @@ -19,9 +19,6 @@ package appeng.core; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - import appeng.block.paint.PaintSplotchesModel; import appeng.block.qnb.QnbFormedModel; import appeng.bootstrap.components.IClientSetupComponent; @@ -34,8 +31,10 @@ import appeng.client.render.SimpleModelLoader; import appeng.client.render.cablebus.CableBusModelLoader; import appeng.client.render.cablebus.P2PTunnelFrequencyModel; import appeng.client.render.crafting.CraftingCubeModelLoader; +import appeng.client.render.crafting.EncodedPatternModelLoader; import appeng.client.render.model.*; import appeng.client.render.spatial.SpatialPylonModel; +import appeng.core.crash.ModCrashEnhancement; import appeng.core.features.registries.PartModels; import appeng.core.stats.AdvancementTriggers; import appeng.core.sync.network.NetworkHandler; @@ -54,40 +53,33 @@ import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.Item; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.particles.ParticleType; -import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraft.world.biome.Biome; -import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.gen.feature.Feature; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.gen.feature.Feature; -import net.minecraft.world.server.ServerWorld; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.client.model.geometry.IModelGeometry; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.ModDimension; -import net.minecraftforge.event.world.WorldEvent; -import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.CrashReportExtender; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Mod; - import net.minecraftforge.fml.config.ModConfig; - -import appeng.core.crash.ModCrashEnhancement; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.server.*; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; +import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; +import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import javax.annotation.Nonnull; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; @Mod(AppEng.MOD_ID) @@ -205,6 +197,7 @@ public final class AppEng addBuiltInModel("paint_splotches", PaintSplotchesModel::new); addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new); addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new); + ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "encoded_pattern"), EncodedPatternModelLoader.INSTANCE); ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "part_plane"), PlaneModelLoader.INSTANCE); ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "crafting_cube"), CraftingCubeModelLoader.INSTANCE); ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE); diff --git a/src/main/java/appeng/core/api/definitions/ApiItems.java b/src/main/java/appeng/core/api/definitions/ApiItems.java index 4c6ee7377..f95944d21 100644 --- a/src/main/java/appeng/core/api/definitions/ApiItems.java +++ b/src/main/java/appeng/core/api/definitions/ApiItems.java @@ -25,8 +25,6 @@ import appeng.api.util.AEColor; import appeng.api.util.AEColoredItemDefinition; import appeng.bootstrap.FeatureFactory; import appeng.api.features.AEFeature; -import appeng.client.render.crafting.EncodedPatternRenderer; -import appeng.client.render.crafting.ItemEncodedPatternRendering; import appeng.core.CreativeTabFacade; import appeng.core.features.ActivityState; import appeng.core.features.ColoredItemDefinition; @@ -288,10 +286,8 @@ public final class ApiItems implements IItems // rv1 this.encodedPattern = registry.item( "encoded_pattern", ItemEncodedPattern::new ) - .props(props -> props.maxStackSize(1) - .setISTER(() -> EncodedPatternRenderer::new)) + .props(props -> props.maxStackSize(1)) .features( AEFeature.PATTERNS ) - .rendering( new ItemEncodedPatternRendering() ) .build(); this.coloredPaintBall = createPaintBalls(registry, "_paint_ball", false); diff --git a/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern.json b/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern.json index ee3f69165..3e4453dd0 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern.json @@ -1,6 +1,4 @@ { - "parent": "item/generated", - "textures": { - "layer0": "appliedenergistics2:item/encoded_pattern" - } -} + "loader": "appliedenergistics2:encoded_pattern", + "baseModel": "appliedenergistics2:item/encoded_pattern_base" +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern_base.json b/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern_base.json new file mode 100644 index 000000000..ee3f69165 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/item/encoded_pattern_base.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "appliedenergistics2:item/encoded_pattern" + } +}