Fixes #2431: Implemented multi block rendering for quantum network bridge.

This commit is contained in:
Sebastian Hartte 2016-10-14 22:59:14 +02:00
parent 202dff3a96
commit 7761a37d59
14 changed files with 485 additions and 24 deletions

View file

@ -21,11 +21,18 @@ package appeng.block.qnb;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import appeng.block.AEBaseTileBlock;
import appeng.helpers.ICustomCollision;
@ -34,6 +41,10 @@ import appeng.tile.qnb.TileQuantumBridge;
public abstract class BlockQuantumBase extends AEBaseTileBlock implements ICustomCollision
{
public static final PropertyBool FORMED = PropertyBool.create( "formed" );
public static final QnbFormedStateProperty FORMED_STATE = new QnbFormedStateProperty();
public BlockQuantumBase( final Material mat )
{
super( mat );
@ -42,6 +53,45 @@ public abstract class BlockQuantumBase extends AEBaseTileBlock implements ICusto
this.boundingBox = new AxisAlignedBB( shave, shave, shave, 1.0f - shave, 1.0f - shave, 1.0f - shave );
this.setLightOpacity( 0 );
this.setFullSize( this.setOpaque( false ) );
this.setDefaultState( getDefaultState().withProperty( FORMED, false ) );
}
@Override
protected IProperty[] getAEStates()
{
return new IProperty[] { FORMED };
}
@Override
protected BlockStateContainer createBlockState()
{
return new ExtendedBlockState( this, getAEStates(), new IUnlistedProperty[] { FORMED_STATE } );
}
@Override
public IBlockState getExtendedState( IBlockState state, IBlockAccess world, BlockPos pos )
{
IExtendedBlockState extState = (IExtendedBlockState) state;
TileQuantumBridge bridge = getTileEntity( world, pos );
if( bridge != null )
{
QnbFormedState formedState = new QnbFormedState( bridge.getConnections(), bridge.isCorner(), bridge.isPowered() );
extState = extState.withProperty( FORMED_STATE, formedState );
}
return extState;
}
@Override
public IBlockState getActualState( IBlockState state, IBlockAccess worldIn, BlockPos pos )
{
TileQuantumBridge bridge = getTileEntity( worldIn, pos );
if( bridge != null )
{
state = state.withProperty( FORMED, bridge.isFormed() );
}
return state;
}
@Override
@ -72,4 +122,9 @@ public abstract class BlockQuantumBase extends AEBaseTileBlock implements ICusto
super.breakBlock( w, pos, state );
}
@Override
public boolean isFullCube( IBlockState state )
{
return false;
}
}

View file

@ -0,0 +1,241 @@
package appeng.block.qnb;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
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.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.property.IExtendedBlockState;
import appeng.api.AEApi;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.core.AppEng;
class QnbFormedBakedModel implements IBakedModel
{
private static final ResourceLocation TEXTURE_LINK = new ResourceLocation( AppEng.MOD_ID, "blocks/quantum_link" );
private static final ResourceLocation TEXTURE_RING = new ResourceLocation( AppEng.MOD_ID, "blocks/quantum_ring" );
private static final ResourceLocation TEXTURE_RING_LIGHT = new ResourceLocation( AppEng.MOD_ID, "blocks/quantum_ring_light" );
private static final ResourceLocation TEXTURE_RING_LIGHT_CORNER = new ResourceLocation( AppEng.MOD_ID, "blocks/quantum_ring_light_corner" );
private static final ResourceLocation TEXTURE_CABLE_GLASS = new ResourceLocation( AppEng.MOD_ID, "parts/cable/glass/transparent" );
private static final ResourceLocation TEXTURE_COVERED_CABLE = new ResourceLocation( AppEng.MOD_ID, "parts/cable/covered/transparent" );
private static final float DEFAULT_RENDER_MIN = 2.0f;
private static final float DEFAULT_RENDER_MAX = 14.0f;
private static final float CORNER_POWERED_RENDER_MIN = 3.9f;
private static final float CORNER_POWERED_RENDER_MAX = 12.1f;
private static final float CENTER_POWERED_RENDER_MIN = -0.01f;
private static final float CENTER_POWERED_RENDER_MAX = 16.01f;
private final VertexFormat vertexFormat;
private final IBakedModel baseModel;
private final Block linkBlock;
private final TextureAtlasSprite linkTexture;
private final TextureAtlasSprite ringTexture;
private final TextureAtlasSprite glassCableTexture;
private final TextureAtlasSprite coveredCableTexture;
private final TextureAtlasSprite lightTexture;
private final TextureAtlasSprite lightCornerTexture;
public QnbFormedBakedModel( VertexFormat vertexFormat, IBakedModel baseModel, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter )
{
this.vertexFormat = vertexFormat;
this.baseModel = baseModel;
this.linkTexture = bakedTextureGetter.apply( TEXTURE_LINK );
this.ringTexture = bakedTextureGetter.apply( TEXTURE_RING );
this.glassCableTexture = bakedTextureGetter.apply( TEXTURE_CABLE_GLASS );
this.coveredCableTexture = bakedTextureGetter.apply( TEXTURE_COVERED_CABLE );
this.lightTexture = bakedTextureGetter.apply( TEXTURE_RING_LIGHT );
this.lightCornerTexture = bakedTextureGetter.apply( TEXTURE_RING_LIGHT_CORNER );
this.linkBlock = AEApi.instance().definitions().blocks().quantumLink().maybeBlock().orElse( null );
}
@Override
public List<BakedQuad> getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand )
{
// Get the correct base model
if( !( state instanceof IExtendedBlockState ) )
{
return baseModel.getQuads( state, side, rand );
}
IExtendedBlockState extendedBlockState = (IExtendedBlockState) state;
QnbFormedState formedState = extendedBlockState.getValue( BlockQuantumBase.FORMED_STATE );
return getQuads( formedState, state, side, rand );
}
private List<BakedQuad> getQuads( QnbFormedState formedState, IBlockState state, EnumFacing side, long rand )
{
CubeBuilder builder = new CubeBuilder( vertexFormat );
if( state.getBlock() == linkBlock )
{
Set<EnumFacing> sides = formedState.getConnections();
this.renderCableAt( builder, 0.11f * 16, glassCableTexture, 0.141f * 16, sides );
this.renderCableAt( builder, 0.188f * 16, coveredCableTexture, 0.1875f * 16, sides );
builder.setTexture( linkTexture );
builder.addCube( DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX );
}
else
{
if( formedState.isCorner() )
{
this.renderCableAt( builder, 0.188f * 16, coveredCableTexture, 0.05f * 16, formedState.getConnections() );
builder.setTexture( ringTexture );
builder.addCube( DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX );
if( formedState.isPowered() )
{
builder.setTexture( lightCornerTexture );
builder.setRenderFullBright( true );
for( EnumFacing facing : EnumFacing.values() )
{
float xOffset = Math.abs( facing.getFrontOffsetX() * 0.01f );
float yOffset = Math.abs( facing.getFrontOffsetY() * 0.01f );
float zOffset = Math.abs( facing.getFrontOffsetZ() * 0.01f );
builder.setDrawFaces( EnumSet.of( facing ) );
builder.addCube(
DEFAULT_RENDER_MIN - xOffset, DEFAULT_RENDER_MIN - yOffset, DEFAULT_RENDER_MIN - zOffset,
DEFAULT_RENDER_MAX + xOffset, DEFAULT_RENDER_MAX + yOffset, DEFAULT_RENDER_MAX + zOffset
);
}
}
}
else
{
builder.setTexture( ringTexture );
builder.addCube( 0, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, 16, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX );
builder.addCube( DEFAULT_RENDER_MIN, 0, DEFAULT_RENDER_MIN, DEFAULT_RENDER_MAX, 16, DEFAULT_RENDER_MAX );
builder.addCube( DEFAULT_RENDER_MIN, DEFAULT_RENDER_MIN, 0, DEFAULT_RENDER_MAX, DEFAULT_RENDER_MAX, 16 );
if( formedState.isPowered() )
{
builder.setTexture( lightTexture );
builder.setRenderFullBright( true );
for( EnumFacing facing : EnumFacing.values() )
{
float xOffset = Math.abs( facing.getFrontOffsetX() * 0.01f );
float yOffset = Math.abs( facing.getFrontOffsetY() * 0.01f );
float zOffset = Math.abs( facing.getFrontOffsetZ() * 0.01f );
builder.setDrawFaces( EnumSet.of( facing ) );
builder.addCube(
-xOffset, -yOffset, -zOffset,
16 + xOffset, 16 + yOffset, 16 + zOffset
);
}
}
}
}
return builder.getOutput();
}
private void renderCableAt( CubeBuilder builder, float thickness, TextureAtlasSprite texture, float pull, Set<EnumFacing> connections )
{
builder.setTexture( texture );
if( connections.contains( EnumFacing.WEST ) )
{
builder.addCube( 0, 8 - thickness, 8 - thickness, 8 - thickness - pull, 8 + thickness, 8 + thickness );
}
if( connections.contains( EnumFacing.EAST ) )
{
builder.addCube( 8 + thickness + pull, 8 - thickness, 8 - thickness, 16, 8 + thickness, 8 + thickness );
}
if( connections.contains( EnumFacing.NORTH ) )
{
builder.addCube( 8 - thickness, 8 - thickness, 0, 8 + thickness, 8 + thickness, 8 - thickness - pull );
}
if( connections.contains( EnumFacing.SOUTH ) )
{
builder.addCube( 8 - thickness, 8 - thickness, 8 + thickness + pull, 8 + thickness, 8 + thickness, 16 );
}
if( connections.contains( EnumFacing.DOWN ) )
{
builder.addCube( 8 - thickness, 0, 8 - thickness, 8 + thickness, 8 - thickness - pull, 8 + thickness );
}
if( connections.contains( EnumFacing.UP ) )
{
builder.addCube( 8 - thickness, 8 + thickness + pull, 8 - thickness, 8 + thickness, 16, 8 + thickness );
}
}
@Override
public boolean isAmbientOcclusion()
{
return baseModel.isAmbientOcclusion();
}
@Override
public boolean isGui3d()
{
return true;
}
@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 baseModel.getOverrides();
}
public static List<ResourceLocation> getRequiredTextures()
{
return ImmutableList.of(
TEXTURE_LINK, TEXTURE_RING, TEXTURE_CABLE_GLASS, TEXTURE_COVERED_CABLE, TEXTURE_RING_LIGHT, TEXTURE_RING_LIGHT_CORNER
);
}
}

View file

@ -0,0 +1,63 @@
package appeng.block.qnb;
import java.util.Collection;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
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;
public class QnbFormedModel implements IModel
{
private static final ResourceLocation MODEL_RING = new ResourceLocation( AppEng.MOD_ID, "block/qnb/ring" );
@Override
public Collection<ResourceLocation> getDependencies()
{
return ImmutableList.of( MODEL_RING );
}
@Override
public Collection<ResourceLocation> getTextures()
{
return QnbFormedBakedModel.getRequiredTextures();
}
@Override
public IBakedModel bake( IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter )
{
IBakedModel ringModel = getBaseModel( MODEL_RING, state, format, bakedTextureGetter );
return new QnbFormedBakedModel( format, ringModel, bakedTextureGetter );
}
@Override
public IModelState getDefaultState()
{
return TRSRTransformation.identity();
}
private IBakedModel getBaseModel( ResourceLocation model, IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter )
{
// Load the base model
try
{
return ModelLoaderRegistry.getModel( model ).bake( state, format, bakedTextureGetter );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
}

View file

@ -0,0 +1,40 @@
package appeng.block.qnb;
import java.util.Set;
import net.minecraft.util.EnumFacing;
public class QnbFormedState
{
private final Set<EnumFacing> connections;
private final boolean corner;
private final boolean powered;
public QnbFormedState( Set<EnumFacing> connections, boolean corner, boolean powered )
{
this.connections = connections;
this.corner = corner;
this.powered = powered;
}
public Set<EnumFacing> getConnections()
{
return connections;
}
public boolean isCorner()
{
return corner;
}
public boolean isPowered()
{
return powered;
}
}

View file

@ -0,0 +1,33 @@
package appeng.block.qnb;
import net.minecraftforge.common.property.IUnlistedProperty;
public class QnbFormedStateProperty implements IUnlistedProperty<QnbFormedState>
{
@Override
public String getName()
{
return "qnb_formed";
}
@Override
public boolean isValid( QnbFormedState value )
{
return value != null;
}
@Override
public Class<QnbFormedState> getType()
{
return QnbFormedState.class;
}
@Override
public String valueToString( QnbFormedState value )
{
return null;
}
}

View file

@ -0,0 +1,23 @@
package appeng.block.qnb;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.bootstrap.BlockRenderingCustomizer;
import appeng.bootstrap.IBlockRendering;
import appeng.bootstrap.IItemRendering;
public class QuantumBridgeRendering extends BlockRenderingCustomizer
{
@Override
@SideOnly( Side.CLIENT )
public void customize( IBlockRendering rendering, IItemRendering itemRendering )
{
rendering.builtInModel( "models/block/qnb/qnb_formed", new QnbFormedModel() );
// Disable auto rotation
rendering.modelCustomizer( (location, model) -> model );
}
}

View file

@ -47,9 +47,9 @@ public class EnergyFx extends ParticleBreaking
{
super( par1World, par2, par4, par6, par8Item );
this.particleGravity = 0;
this.particleBlue = 255;
this.particleGreen = 255;
this.particleRed = 255;
this.particleBlue = 1;
this.particleGreen = 1;
this.particleRed = 1;
this.particleAlpha = 1.4f;
this.particleScale = 3.5f;
this.particleTextureIndex = ParticleTextures.BlockEnergyParticle;
@ -66,7 +66,7 @@ public class EnergyFx extends ParticleBreaking
}
@Override
public void renderParticle( final VertexBuffer par1Tessellator, final Entity p_180434_2_, final float par2, final float par3, final float par4, final float par5, final float par6, final float par7 )
public void renderParticle( final VertexBuffer par1Tessellator, final Entity p_180434_2_, final float partialTicks, final float par3, final float par4, final float par5, final float par6, final float par7 )
{
final float f6 = this.particleTextureIndex.getMinU();
final float f7 = this.particleTextureIndex.getMaxU();
@ -74,9 +74,9 @@ public class EnergyFx extends ParticleBreaking
final float f9 = this.particleTextureIndex.getMaxV();
final float f10 = 0.1F * this.particleScale;
final float f11 = (float) ( this.prevPosX + ( this.posX - this.prevPosX ) * par2 - interpPosX );
final float f12 = (float) ( this.prevPosY + ( this.posY - this.prevPosY ) * par2 - interpPosY );
final float f13 = (float) ( this.prevPosZ + ( this.posZ - this.prevPosZ ) * par2 - interpPosZ );
final float f11 = (float) ( this.prevPosX + ( this.posX - this.prevPosX ) * partialTicks - interpPosX );
final float f12 = (float) ( this.prevPosY + ( this.posY - this.prevPosY ) * partialTicks - interpPosY );
final float f13 = (float) ( this.prevPosZ + ( this.posZ - this.prevPosZ ) * partialTicks - interpPosZ );
final int blkX = MathHelper.floor_double( this.posX );
final int blkY = MathHelper.floor_double( this.posY );
@ -84,7 +84,7 @@ public class EnergyFx extends ParticleBreaking
if( blkX == this.startBlkX && blkY == this.startBlkY && blkZ == this.startBlkZ )
{
int i = this.getBrightnessForRender(par2);
int i = this.getBrightnessForRender(partialTicks);
int j = i >> 16 & 65535;
int k = i & 65535;

View file

@ -39,9 +39,9 @@ public class MatterCannonFX extends ParticleBreaking
{
super( par1World, par2, par4, par6, par8Item );
this.particleGravity = 0;
this.particleBlue = 255;
this.particleGreen = 255;
this.particleRed = 255;
this.particleBlue = 1;
this.particleGreen = 1;
this.particleRed = 1;
this.particleAlpha = 1.4f;
this.particleScale = 1.1f;
this.motionX = 0.0f;

View file

@ -69,6 +69,7 @@ import appeng.block.networking.ControllerRendering;
import appeng.block.networking.WirelessRendering;
import appeng.block.qnb.BlockQuantumLinkChamber;
import appeng.block.qnb.BlockQuantumRing;
import appeng.block.qnb.QuantumBridgeRendering;
import appeng.block.spatial.BlockMatrixFrame;
import appeng.block.spatial.BlockSpatialIOPort;
import appeng.block.spatial.BlockSpatialPylon;
@ -284,8 +285,14 @@ public final class ApiBlocks implements IBlocks
.features( AEFeature.Security )
.rendering( new SecurityStationRendering() )
.build();
this.quantumRing = registry.block( "quantum_ring", BlockQuantumRing::new ).features( AEFeature.QuantumNetworkBridge ).build();
this.quantumLink = registry.block( "quantum_link", BlockQuantumLinkChamber::new ).features( AEFeature.QuantumNetworkBridge ).build();
this.quantumRing = registry.block( "quantum_ring", BlockQuantumRing::new )
.features( AEFeature.QuantumNetworkBridge )
.rendering( new QuantumBridgeRendering() )
.build();
this.quantumLink = registry.block( "quantum_link", BlockQuantumLinkChamber::new )
.features( AEFeature.QuantumNetworkBridge )
.rendering( new QuantumBridgeRendering() )
.build();
this.spatialPylon = registry.block( "spatial_pylon", BlockSpatialPylon::new )
.features( AEFeature.SpatialIO )
.useCustomItemModel()

View file

@ -234,12 +234,9 @@ public class TileQuantumBridge extends AENetworkInvTile implements IAEMultiBlock
if( this.isCorner() || this.isCenter() )
{
final EnumSet<EnumFacing> sides = EnumSet.noneOf( EnumFacing.class );
for( final AEPartLocation dir : this.getConnections() )
for( final EnumFacing dir : this.getConnections() )
{
if( dir != AEPartLocation.INTERNAL )
{
sides.add( dir.getFacing() );
}
sides.add( dir );
}
this.getProxy().setValidSides( sides );
@ -256,13 +253,13 @@ public class TileQuantumBridge extends AENetworkInvTile implements IAEMultiBlock
return ( this.constructed & this.getCorner() ) == this.getCorner() && this.constructed != -1;
}
public EnumSet<AEPartLocation> getConnections()
public EnumSet<EnumFacing> getConnections()
{
final EnumSet<AEPartLocation> set = EnumSet.noneOf( AEPartLocation.class );
final EnumSet<EnumFacing> set = EnumSet.noneOf( EnumFacing.class );
for( final AEPartLocation d : AEPartLocation.values() )
for( final EnumFacing d : EnumFacing.values() )
{
final TileEntity te = this.worldObj.getTileEntity( d == AEPartLocation.INTERNAL ? this.pos : this.pos.offset( d.getFacing() ) );
final TileEntity te = this.worldObj.getTileEntity( this.pos.offset( d ) );
if( te instanceof TileQuantumBridge )
{
set.add( d );

View file

@ -1,5 +1,6 @@
{
"variants": {
"normal": { "model": "appliedenergistics2:qnb/link" }
"formed=false": { "model": "appliedenergistics2:qnb/link" },
"formed=true": { "model": "appliedenergistics2:qnb/qnb_formed" }
}
}

View file

@ -1,5 +1,6 @@
{
"variants": {
"normal": { "model": "appliedenergistics2:qnb/ring" }
"formed=false": { "model": "appliedenergistics2:qnb/ring" },
"formed=true": { "model": "appliedenergistics2:qnb/qnb_formed" }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B