Added item models for facades.
This commit is contained in:
parent
77cb3d8b92
commit
5313d61490
9 changed files with 373 additions and 19 deletions
|
@ -0,0 +1,99 @@
|
|||
package appeng.client.render;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.items.parts.ItemFacade;
|
||||
|
||||
|
||||
/**
|
||||
* This baked model class is used as a dispatcher to redirect the renderer to the *real* model that should be used based on the item stack.
|
||||
* A custom Item Override List is used to accomplish this.
|
||||
*/
|
||||
public class FacadeDispatcherBakedModel implements IBakedModel
|
||||
{
|
||||
|
||||
private final IBakedModel baseModel;
|
||||
|
||||
public FacadeDispatcherBakedModel( IBakedModel baseModel )
|
||||
{
|
||||
this.baseModel = baseModel;
|
||||
}
|
||||
|
||||
// This is never used. See the item override list below.
|
||||
@Override
|
||||
public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand )
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return baseModel.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return baseModel.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return baseModel.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms()
|
||||
{
|
||||
return baseModel.getItemCameraTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return new ItemOverrideList( Collections.emptyList() )
|
||||
{
|
||||
@Override
|
||||
public IBakedModel handleItemState( IBakedModel originalModel, ItemStack stack, World world, EntityLivingBase entity )
|
||||
{
|
||||
if( !( stack.getItem() instanceof ItemFacade ) )
|
||||
{
|
||||
return originalModel;
|
||||
}
|
||||
|
||||
ItemFacade itemFacade = (ItemFacade) stack.getItem();
|
||||
|
||||
Block block = itemFacade.getBlock( stack );
|
||||
int meta = itemFacade.getMeta( stack );
|
||||
|
||||
// This is kinda fascinating, how do we get the meta from the itemblock
|
||||
IBlockState state = block.getStateFromMeta( meta );
|
||||
|
||||
return new FacadeWithBlockBakedModel( baseModel, state );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
66
src/main/java/appeng/client/render/FacadeItemModel.java
Normal file
66
src/main/java/appeng/client/render/FacadeItemModel.java
Normal file
|
@ -0,0 +1,66 @@
|
|||
package appeng.client.render;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.IModel;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.common.model.IModelState;
|
||||
import net.minecraftforge.common.model.TRSRTransformation;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
|
||||
|
||||
/**
|
||||
* The model class for facades. Since facades wrap existing models, they don't declare any dependencies here other
|
||||
* than the cable anchor.
|
||||
*/
|
||||
public class FacadeItemModel implements IModel
|
||||
{
|
||||
|
||||
// We use this to get the default item transforms and make our lives easier
|
||||
private static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "item/facade_base" );
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getDependencies()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake( IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter )
|
||||
{
|
||||
IModel baseModel;
|
||||
try
|
||||
{
|
||||
baseModel = ModelLoaderRegistry.getModel( MODEL_BASE );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
|
||||
IBakedModel bakedBaseModel = baseModel.bake( state, format, bakedTextureGetter );
|
||||
|
||||
return new FacadeDispatcherBakedModel( bakedBaseModel );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelState getDefaultState()
|
||||
{
|
||||
return TRSRTransformation.identity();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package appeng.client.render;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
|
||||
/**
|
||||
* This is the actual baked model that will combine the north face of a given block state
|
||||
* with the base facade item model to achieve what is then actually rendered on screen.
|
||||
*/
|
||||
public class FacadeWithBlockBakedModel implements IBakedModel
|
||||
{
|
||||
|
||||
private final IBakedModel baseModel;
|
||||
|
||||
private final IBlockState blockState;
|
||||
|
||||
private final IBakedModel textureModel;
|
||||
|
||||
public FacadeWithBlockBakedModel( IBakedModel baseModel, IBlockState blockState )
|
||||
{
|
||||
this.baseModel = baseModel;
|
||||
this.blockState = blockState;
|
||||
this.textureModel = Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState( blockState );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand )
|
||||
{
|
||||
// Only the north side is actually read from the base model for item models
|
||||
if( side == EnumFacing.NORTH )
|
||||
{
|
||||
return textureModel.getQuads( blockState, side, rand );
|
||||
}
|
||||
else
|
||||
{
|
||||
return baseModel.getQuads( state, side, rand );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion()
|
||||
{
|
||||
return baseModel.isAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d()
|
||||
{
|
||||
return baseModel.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleTexture()
|
||||
{
|
||||
return baseModel.getParticleTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms()
|
||||
{
|
||||
return baseModel.getItemCameraTransforms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemOverrideList getOverrides()
|
||||
{
|
||||
return ItemOverrideList.NONE;
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@ import appeng.core.localization.PlayerMessages;
|
|||
import appeng.core.stats.PlayerStatsRegistration;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.items.materials.ItemMultiItem;
|
||||
import appeng.items.parts.ItemFacade;
|
||||
import appeng.loot.ChestLoot;
|
||||
import appeng.me.cache.CraftingGridCache;
|
||||
import appeng.me.cache.EnergyGridCache;
|
||||
|
@ -315,8 +316,10 @@ public final class Registration
|
|||
|
||||
if( AEConfig.instance.isFeatureEnabled( AEFeature.EnableFacadeCrafting ) )
|
||||
{
|
||||
GameRegistry.addRecipe( new FacadeRecipe() );
|
||||
RecipeSorter.register( "appliedenergistics2:facade", FacadeRecipe.class, Category.SHAPED, "after:minecraft:shaped" );
|
||||
definitions.items().facade().maybeItem().ifPresent( facadeItem -> {
|
||||
GameRegistry.addRecipe( new FacadeRecipe( (ItemFacade) facadeItem ) );
|
||||
RecipeSorter.register( "appliedenergistics2:facade", FacadeRecipe.class, Category.SHAPED, "after:minecraft:shaped" );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import appeng.items.misc.ItemCrystalSeedRendering;
|
|||
import appeng.items.misc.ItemEncodedPattern;
|
||||
import appeng.items.misc.ItemPaintBall;
|
||||
import appeng.items.misc.ItemPaintBallRendering;
|
||||
import appeng.items.parts.FacadeRendering;
|
||||
import appeng.items.parts.ItemFacade;
|
||||
import appeng.items.storage.ItemBasicStorageCell;
|
||||
import appeng.items.storage.ItemCreativeStorageCell;
|
||||
|
@ -177,6 +178,7 @@ public final class ApiItems implements IItems
|
|||
this.facade = registry.item( "facade", ItemFacade::new )
|
||||
.features( AEFeature.Facades )
|
||||
.creativeTab( CreativeTabFacade.instance )
|
||||
.rendering( new FacadeRendering() )
|
||||
.build();
|
||||
this.crystalSeed = registry.item( "crystal_seed", ItemCrystalSeed::new )
|
||||
.rendering( new ItemCrystalSeedRendering() )
|
||||
|
|
21
src/main/java/appeng/items/parts/FacadeRendering.java
Normal file
21
src/main/java/appeng/items/parts/FacadeRendering.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
package appeng.items.parts;
|
||||
|
||||
|
||||
import appeng.bootstrap.IItemRendering;
|
||||
import appeng.bootstrap.ItemRenderingCustomizer;
|
||||
import appeng.client.render.FacadeItemModel;
|
||||
|
||||
|
||||
/**
|
||||
* Handles rendering customization for facade items. Please note that this works very differently
|
||||
* from actually rendering a Facade in a cable bus.
|
||||
*/
|
||||
public class FacadeRendering extends ItemRenderingCustomizer
|
||||
{
|
||||
@Override
|
||||
public void customize( IItemRendering rendering )
|
||||
{
|
||||
// This actually just uses the path it will look for by default, no custom model redirection needed
|
||||
rendering.builtInModel( "models/item/facade", new FacadeItemModel() );
|
||||
}
|
||||
}
|
|
@ -25,6 +25,10 @@ import java.util.List;
|
|||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockGlass;
|
||||
import net.minecraft.block.BlockStainedGlass;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
@ -34,6 +38,7 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
@ -45,7 +50,9 @@ import appeng.api.AEApi;
|
|||
import appeng.api.exceptions.MissingDefinition;
|
||||
import appeng.api.parts.IAlphaPassItem;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.FacadeConfig;
|
||||
import appeng.decorative.solid.BlockQuartzOre;
|
||||
import appeng.facade.FacadePart;
|
||||
import appeng.facade.IFacadeItem;
|
||||
import appeng.items.AEBaseItem;
|
||||
|
@ -129,6 +136,35 @@ public class ItemFacade extends AEBaseItem implements IFacadeItem, IAlphaPassIte
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean hasSimpleModel( Block b, IBlockState blockState )
|
||||
{
|
||||
if( b.getRenderType( blockState ) != EnumBlockRenderType.MODEL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IBakedModel model = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes().getModelForState( blockState );
|
||||
|
||||
for( EnumFacing facing : EnumFacing.values() )
|
||||
{
|
||||
List<BakedQuad> quads = model.getQuads( blockState, facing, 0 );
|
||||
if( quads.size() != 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BakedQuad q = quads.get( 0 );
|
||||
if( q.getFace() != facing )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO We could also check that the quad is fully encompassing the side
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ItemStack createFacadeForItem( final ItemStack l, final boolean returnItem )
|
||||
{
|
||||
if( l == null )
|
||||
|
@ -144,8 +180,24 @@ public class ItemFacade extends AEBaseItem implements IFacadeItem, IAlphaPassIte
|
|||
|
||||
final int metadata = l.getItem().getMetadata( l.getItemDamage() );
|
||||
|
||||
// TODO 1.10.2-R - XD
|
||||
final boolean defaultValue = true || b instanceof BlockGlass || b instanceof BlockStainedGlass;
|
||||
final boolean hasTile = b.hasTileEntity( b.getDefaultState() );
|
||||
final boolean enableGlass = b instanceof BlockGlass || b instanceof BlockStainedGlass;
|
||||
final boolean disableOre = b instanceof BlockQuartzOre;
|
||||
|
||||
// Try to get the block state based on the item stack's meta. If this fails, don't consider it for a facade
|
||||
// This for example fails for Pistons because they hardcoded an invalid meta value in vanilla
|
||||
IBlockState blockState;
|
||||
try
|
||||
{
|
||||
blockState = b.getStateFromMeta( metadata );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
AELog.debug( e, "Cannot create a facade for " + b.getRegistryName() );
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean defaultValue = ( b.isFullyOpaque( blockState ) && hasSimpleModel( b, blockState ) && !b.getTickRandomly() && !hasTile && !disableOre ) || enableGlass;
|
||||
if( FacadeConfig.instance.checkEnabled( b, metadata, defaultValue ) )
|
||||
{
|
||||
if( returnItem )
|
||||
|
|
|
@ -19,12 +19,10 @@
|
|||
package appeng.recipes.game;
|
||||
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryCrafting;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -39,13 +37,13 @@ import appeng.items.parts.ItemFacade;
|
|||
public final class FacadeRecipe implements IRecipe
|
||||
{
|
||||
private final IComparableDefinition anchor;
|
||||
private final Optional<Item> maybeFacade;
|
||||
private final ItemFacade facade;
|
||||
|
||||
public FacadeRecipe()
|
||||
public FacadeRecipe( ItemFacade facade )
|
||||
{
|
||||
this.facade = facade;
|
||||
final IDefinitions definitions = AEApi.instance().definitions();
|
||||
|
||||
this.maybeFacade = definitions.items().facade().maybeItem();
|
||||
this.anchor = definitions.parts().cableAnchor();
|
||||
}
|
||||
|
||||
|
@ -62,17 +60,12 @@ public final class FacadeRecipe implements IRecipe
|
|||
{
|
||||
if( this.anchor.isSameAs( inv.getStackInSlot( 1 ) ) && this.anchor.isSameAs( inv.getStackInSlot( 3 ) ) && this.anchor.isSameAs( inv.getStackInSlot( 5 ) ) && this.anchor.isSameAs( inv.getStackInSlot( 7 ) ) )
|
||||
{
|
||||
return this.maybeFacade.map( facadeItemDefinition ->
|
||||
final ItemStack facades = facade.createFacadeForItem( inv.getStackInSlot( 4 ), !createFacade );
|
||||
if( facades != null && createFacade )
|
||||
{
|
||||
final ItemFacade facade = (ItemFacade) facadeItemDefinition;
|
||||
|
||||
final ItemStack facades = facade.createFacadeForItem( inv.getStackInSlot( 4 ), !createFacade );
|
||||
if( facades != null && createFacade )
|
||||
{
|
||||
facades.stackSize = 4;
|
||||
}
|
||||
return facades;
|
||||
} ).orElse( null );
|
||||
facades.stackSize = 4;
|
||||
}
|
||||
return facades;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"anchor": "appliedenergistics2:parts/cable_anchor",
|
||||
"particle": "appliedenergistics2:parts/cable_anchor"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [ 7.0, 7.0, 2.0 ],
|
||||
"to": [ 9.0, 9.0, 10.0 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#anchor" },
|
||||
"east": { "texture": "#anchor" },
|
||||
"south": { "texture": "#anchor" },
|
||||
"west": { "texture": "#anchor" },
|
||||
"up": { "texture": "#anchor" },
|
||||
"down": { "texture": "#anchor" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [ 0, 0, 0 ],
|
||||
"to": [ 16, 16, 2 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#anchor" },
|
||||
"south": { "texture": "#anchor" },
|
||||
"west": { "texture": "#anchor" },
|
||||
"up": { "texture": "#anchor" },
|
||||
"down": { "texture": "#anchor" }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue