From 5b6ed0cfd09b3f052a10beb66b1145ba6e6878e9 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Mon, 12 Sep 2016 01:11:38 +0200 Subject: [PATCH] First pass of implementing rendering for crafting cubes (#7) --- .../block/crafting/BlockCraftingMonitor.java | 41 +++ .../block/crafting/BlockCraftingUnit.java | 48 ++- .../block/networking/BlockCableBus.java | 4 +- .../CableBusContainerUnlistedProperty.java | 34 -- .../CableBusRenderStateProperty.java | 37 --- .../java/appeng/block/storage/BlockDrive.java | 3 +- .../storage/DriveSlotsStateProperty.java | 50 --- .../components/StateMapperComponent.java | 4 +- .../java/appeng/client/UnlistedProperty.java | 48 +++ .../client/render/cablebus/CubeBuilder.java | 16 +- .../crafting/CraftingCubeBakedModel.java | 294 ++++++++++++++++++ .../render/crafting/CraftingCubeModel.java | 137 ++++++++ .../crafting/CraftingCubeRendering.java | 73 +++++ .../render/crafting/CraftingCubeState.java | 27 ++ .../render/crafting/LightBakedModel.java | 42 +++ .../render/crafting/MonitorBakedModel.java | 116 +++++++ .../render/crafting/UnitBakedModel.java | 32 ++ .../core/api/definitions/ApiBlocks.java | 8 + .../implementations/CraftingCPUCluster.java | 4 + .../tile/crafting/TileCraftingTile.java | 13 +- .../blockstates/crafting_accelerator.json | 5 + .../blockstates/crafting_monitor.json | 5 + .../blockstates/crafting_storage_16k.json | 5 + .../blockstates/crafting_storage_1k.json | 5 + .../blockstates/crafting_storage_4k.json | 5 + .../blockstates/crafting_storage_64k.json | 5 + .../blockstates/crafting_unit.json | 5 + .../models/block/crafting/accelerator.json | 6 + .../models/block/crafting/monitor.json | 11 + .../models/block/crafting/storage_16k.json | 6 + .../models/block/crafting/storage_1k.json | 6 + .../models/block/crafting/storage_4k.json | 6 + .../models/block/crafting/storage_64k.json | 6 + .../models/block/crafting/unit.json | 6 + .../models/item/crafting_accelerator.json | 5 +- .../models/item/crafting_monitor.json | 10 +- .../models/item/crafting_storage_16k.json | 5 +- .../models/item/crafting_storage_1k.json | 5 +- .../models/item/crafting_storage_4k.json | 5 +- .../models/item/crafting_storage_64k.json | 5 +- .../models/item/crafting_unit.json | 5 +- ...elerator_fit.png => accelerator_light.png} | Bin .../{fit_solid.png => light_base.png} | Bin .../{monitor_outer.png => monitor_base.png} | Bin ...fit_light.png => monitor_light_bright.png} | Bin ...or_fit_dark.png => monitor_light_dark.png} | Bin ...it_medium.png => monitor_light_medium.png} | Bin .../{unit_ring.png => ring_corner.png} | Bin .../blocks/crafting/ring_side_hor.png | Bin 0 -> 2867 bytes .../blocks/crafting/ring_side_ver.png | Bin 0 -> 2867 bytes ...rage_16k_fit.png => storage_16k_light.png} | Bin ...torage_1k_fit.png => storage_1k_light.png} | Bin ...torage_4k_fit.png => storage_4k_light.png} | Bin ...rage_64k_fit.png => storage_64k_light.png} | Bin .../crafting/{unit_fit.png => unit_base.png} | Bin .../blocks/crafting/unit_ring_long.png | Bin 243 -> 0 bytes .../crafting/unit_ring_long_rotated.png | Bin 217 -> 0 bytes 57 files changed, 980 insertions(+), 173 deletions(-) delete mode 100644 src/main/java/appeng/block/networking/CableBusContainerUnlistedProperty.java delete mode 100644 src/main/java/appeng/block/networking/CableBusRenderStateProperty.java delete mode 100644 src/main/java/appeng/block/storage/DriveSlotsStateProperty.java create mode 100644 src/main/java/appeng/client/UnlistedProperty.java create mode 100644 src/main/java/appeng/client/render/crafting/CraftingCubeBakedModel.java create mode 100644 src/main/java/appeng/client/render/crafting/CraftingCubeModel.java create mode 100644 src/main/java/appeng/client/render/crafting/CraftingCubeRendering.java create mode 100644 src/main/java/appeng/client/render/crafting/CraftingCubeState.java create mode 100644 src/main/java/appeng/client/render/crafting/LightBakedModel.java create mode 100644 src/main/java/appeng/client/render/crafting/MonitorBakedModel.java create mode 100644 src/main/java/appeng/client/render/crafting/UnitBakedModel.java create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_accelerator.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_monitor.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_16k.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_1k.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_4k.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_64k.json create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/crafting_unit.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/accelerator.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/monitor.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_16k.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_1k.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_4k.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_64k.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/block/crafting/unit.json rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{accelerator_fit.png => accelerator_light.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{fit_solid.png => light_base.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{monitor_outer.png => monitor_base.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{monitor_fit_light.png => monitor_light_bright.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{monitor_fit_dark.png => monitor_light_dark.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{monitor_fit_medium.png => monitor_light_medium.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{unit_ring.png => ring_corner.png} (100%) create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_hor.png create mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_ver.png rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{storage_16k_fit.png => storage_16k_light.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{storage_1k_fit.png => storage_1k_light.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{storage_4k_fit.png => storage_4k_light.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{storage_64k_fit.png => storage_64k_light.png} (100%) rename src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/{unit_fit.png => unit_base.png} (100%) delete mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/unit_ring_long.png delete mode 100644 src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/unit_ring_long_rotated.png diff --git a/src/main/java/appeng/block/crafting/BlockCraftingMonitor.java b/src/main/java/appeng/block/crafting/BlockCraftingMonitor.java index a05654129..6273cf7ef 100644 --- a/src/main/java/appeng/block/crafting/BlockCraftingMonitor.java +++ b/src/main/java/appeng/block/crafting/BlockCraftingMonitor.java @@ -21,23 +21,64 @@ package appeng.block.crafting; import java.util.List; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.property.ExtendedBlockState; +import net.minecraftforge.common.property.IExtendedBlockState; +import net.minecraftforge.common.property.IUnlistedProperty; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import appeng.api.util.AEColor; +import appeng.client.UnlistedProperty; import appeng.tile.crafting.TileCraftingMonitorTile; public class BlockCraftingMonitor extends BlockCraftingUnit { + + public static final UnlistedProperty COLOR = new UnlistedProperty<>( "color", AEColor.class ); + + public static final UnlistedProperty FORWARD = new UnlistedProperty<>( "forward", EnumFacing.class ); + public BlockCraftingMonitor() { super( CraftingUnitType.MONITOR ); this.setTileEntity( TileCraftingMonitorTile.class ); } + @Override + protected BlockStateContainer createBlockState() + { + return new ExtendedBlockState( this, getAEStates(), new IUnlistedProperty[] { + STATE, + COLOR, + FORWARD + } ); + } + + @Override + public IExtendedBlockState getExtendedState( IBlockState state, IBlockAccess world, BlockPos pos ) + { + AEColor color = AEColor.Transparent; + EnumFacing forward = EnumFacing.NORTH; + + TileCraftingMonitorTile te = getTileEntity( world, pos ); + if( te != null ) + { + color = te.getColor(); + forward = te.getForward(); + } + + return super.getExtendedState( state, world, pos ).withProperty( COLOR, color ).withProperty( FORWARD, forward ); + } + @Override @SideOnly( Side.CLIENT ) public void getCheckedSubBlocks( final Item item, final CreativeTabs tabs, final List itemStacks ) diff --git a/src/main/java/appeng/block/crafting/BlockCraftingUnit.java b/src/main/java/appeng/block/crafting/BlockCraftingUnit.java index b198b0c4e..d9bfc70f2 100644 --- a/src/main/java/appeng/block/crafting/BlockCraftingUnit.java +++ b/src/main/java/appeng/block/crafting/BlockCraftingUnit.java @@ -19,12 +19,14 @@ package appeng.block.crafting; +import java.util.EnumSet; import javax.annotation.Nullable; 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.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -32,10 +34,16 @@ import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; 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.api.util.AEPartLocation; import appeng.block.AEBaseTileBlock; +import appeng.client.UnlistedProperty; +import appeng.client.render.crafting.CraftingCubeState; import appeng.core.sync.GuiBridge; import appeng.tile.crafting.TileCraftingTile; import appeng.util.Platform; @@ -43,8 +51,9 @@ import appeng.util.Platform; public class BlockCraftingUnit extends AEBaseTileBlock { - public static final PropertyBool POWERED = PropertyBool.create( "powered" ); public static final PropertyBool FORMED = PropertyBool.create( "formed" ); + public static final PropertyBool POWERED = PropertyBool.create( "powered" ); + public static final UnlistedProperty STATE = new UnlistedProperty<>( "state", CraftingCubeState.class ); public final CraftingUnitType type; @@ -61,7 +70,38 @@ public class BlockCraftingUnit extends AEBaseTileBlock { return new IProperty[] { POWERED, FORMED }; } - + + @Override + public IExtendedBlockState getExtendedState( IBlockState state, IBlockAccess world, BlockPos pos ) + { + + EnumSet connections = EnumSet.noneOf( EnumFacing.class ); + + for( EnumFacing facing : EnumFacing.values() ) + { + if( isConnected( world, pos, facing ) ) + { + connections.add( facing ); + } + } + + IExtendedBlockState extState = (IExtendedBlockState) state; + + return extState.withProperty( STATE, new CraftingCubeState( connections ) ); + } + + private boolean isConnected( IBlockAccess world, BlockPos pos, EnumFacing side ) + { + BlockPos adjacentPos = pos.offset( side ); + return world.getBlockState( adjacentPos ).getBlock() instanceof BlockCraftingUnit; + } + + @Override + protected BlockStateContainer createBlockState() + { + return new ExtendedBlockState( this, getAEStates(), new IUnlistedProperty[] { STATE } ); + } + @Override public IBlockState getStateFromMeta( final int meta ) { @@ -71,8 +111,8 @@ public class BlockCraftingUnit extends AEBaseTileBlock @Override public int getMetaFromState( final IBlockState state ) { - final boolean p = (boolean) state.getValue( POWERED ); - final boolean f = (boolean) state.getValue( FORMED ); + boolean p = state.getValue( POWERED ); + boolean f = state.getValue( FORMED ); return ( p ? 1 : 0 ) | ( f ? 2 : 0 ); } diff --git a/src/main/java/appeng/block/networking/BlockCableBus.java b/src/main/java/appeng/block/networking/BlockCableBus.java index 57d4b7dc6..f1e4ab566 100644 --- a/src/main/java/appeng/block/networking/BlockCableBus.java +++ b/src/main/java/appeng/block/networking/BlockCableBus.java @@ -61,6 +61,7 @@ import appeng.api.parts.PartItemStack; import appeng.api.parts.SelectedPart; import appeng.api.util.AEColor; import appeng.block.AEBaseTileBlock; +import appeng.client.UnlistedProperty; import appeng.client.render.cablebus.CableBusBakedModel; import appeng.client.render.cablebus.CableBusRenderState; import appeng.core.AEConfig; @@ -81,7 +82,8 @@ import appeng.util.Platform; public class BlockCableBus extends AEBaseTileBlock { - public static final CableBusRenderStateProperty RENDER_STATE_PROPERTY = new CableBusRenderStateProperty(); + public static final UnlistedProperty RENDER_STATE_PROPERTY = + new UnlistedProperty<>( "cable_bus_render_state", CableBusRenderState.class ); private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer(); diff --git a/src/main/java/appeng/block/networking/CableBusContainerUnlistedProperty.java b/src/main/java/appeng/block/networking/CableBusContainerUnlistedProperty.java deleted file mode 100644 index e9b454a48..000000000 --- a/src/main/java/appeng/block/networking/CableBusContainerUnlistedProperty.java +++ /dev/null @@ -1,34 +0,0 @@ -package appeng.block.networking; - -import net.minecraftforge.common.property.IUnlistedProperty; - -import appeng.parts.CableBusContainer; - -public class CableBusContainerUnlistedProperty implements IUnlistedProperty -{ - - @Override - public String getName() - { - return "bus"; - } - - @Override - public boolean isValid( CableBusContainer value ) - { - return true; - } - - @Override - public Class getType() - { - return CableBusContainer.class; - } - - @Override - public String valueToString( CableBusContainer value ) - { - return null; - } - -} diff --git a/src/main/java/appeng/block/networking/CableBusRenderStateProperty.java b/src/main/java/appeng/block/networking/CableBusRenderStateProperty.java deleted file mode 100644 index 2ad8ac2a1..000000000 --- a/src/main/java/appeng/block/networking/CableBusRenderStateProperty.java +++ /dev/null @@ -1,37 +0,0 @@ -package appeng.block.networking; - - -import net.minecraftforge.common.property.IUnlistedProperty; - -import appeng.client.render.cablebus.CableBusRenderState; - - -/** - * An unlisted property for the cable bus block's render state. - */ -public class CableBusRenderStateProperty implements IUnlistedProperty -{ - @Override - public String getName() - { - return "cable_bus_render_state"; - } - - @Override - public boolean isValid( CableBusRenderState value ) - { - return value != null; - } - - @Override - public Class getType() - { - return CableBusRenderState.class; - } - - @Override - public String valueToString( CableBusRenderState value ) - { - return value.toString(); - } -} diff --git a/src/main/java/appeng/block/storage/BlockDrive.java b/src/main/java/appeng/block/storage/BlockDrive.java index ffe6f9d4d..a5bf11888 100644 --- a/src/main/java/appeng/block/storage/BlockDrive.java +++ b/src/main/java/appeng/block/storage/BlockDrive.java @@ -38,6 +38,7 @@ import net.minecraftforge.common.property.IUnlistedProperty; import appeng.api.util.AEPartLocation; import appeng.block.AEBaseTileBlock; +import appeng.client.UnlistedProperty; import appeng.core.sync.GuiBridge; import appeng.tile.storage.TileDrive; import appeng.util.Platform; @@ -46,7 +47,7 @@ import appeng.util.Platform; public class BlockDrive extends AEBaseTileBlock { - public static final DriveSlotsStateProperty SLOTS_STATE = new DriveSlotsStateProperty(); + public static final UnlistedProperty SLOTS_STATE = new UnlistedProperty<>("drive_slots_state", DriveSlotsState.class); public BlockDrive() { diff --git a/src/main/java/appeng/block/storage/DriveSlotsStateProperty.java b/src/main/java/appeng/block/storage/DriveSlotsStateProperty.java deleted file mode 100644 index 9a5497ec1..000000000 --- a/src/main/java/appeng/block/storage/DriveSlotsStateProperty.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of Applied Energistics 2. - * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. - * - * Applied Energistics 2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Applied Energistics 2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Applied Energistics 2. If not, see . - */ - -package appeng.block.storage; - - -import net.minecraftforge.common.property.IUnlistedProperty; - - -public class DriveSlotsStateProperty implements IUnlistedProperty -{ - @Override - public String getName() - { - return "drive_slots_state"; - } - - @Override - public boolean isValid( DriveSlotsState value ) - { - return value != null; - } - - @Override - public Class getType() - { - return DriveSlotsState.class; - } - - @Override - public String valueToString( DriveSlotsState value ) - { - return value.toString(); - } -} diff --git a/src/main/java/appeng/bootstrap/components/StateMapperComponent.java b/src/main/java/appeng/bootstrap/components/StateMapperComponent.java index d33e5e064..be0c98cb9 100644 --- a/src/main/java/appeng/bootstrap/components/StateMapperComponent.java +++ b/src/main/java/appeng/bootstrap/components/StateMapperComponent.java @@ -13,7 +13,7 @@ import net.minecraftforge.fml.relauncher.Side; /** * Registers a custom state mapper for a given block. */ -public class StateMapperComponent implements InitComponent +public class StateMapperComponent implements PreInitComponent { private final Block block; @@ -27,7 +27,7 @@ public class StateMapperComponent implements InitComponent } @Override - public void initialize( Side side ) + public void preInitialize( Side side ) { ModelLoader.setCustomStateMapper( block, stateMapper ); if( stateMapper instanceof IResourceManagerReloadListener ) diff --git a/src/main/java/appeng/client/UnlistedProperty.java b/src/main/java/appeng/client/UnlistedProperty.java new file mode 100644 index 000000000..a98f2d92e --- /dev/null +++ b/src/main/java/appeng/client/UnlistedProperty.java @@ -0,0 +1,48 @@ +package appeng.client; + + +import net.minecraftforge.common.property.IUnlistedProperty; + + +/** + * A generic implementation for {@link IUnlistedProperty}. + * @param + */ +public class UnlistedProperty implements IUnlistedProperty +{ + + private final String name; + + private final Class clazz; + + public UnlistedProperty( String name, Class clazz ) + { + this.name = name; + this.clazz = clazz; + } + + @Override + public String getName() + { + return name; + } + + @Override + public boolean isValid( T value ) + { + return value != null; + } + + @Override + public Class getType() + { + return clazz; + } + + @Override + public String valueToString( T value ) + { + return value.toString(); + } + +} diff --git a/src/main/java/appeng/client/render/cablebus/CubeBuilder.java b/src/main/java/appeng/client/render/cablebus/CubeBuilder.java index ee4d7e9a7..2f3312ba5 100644 --- a/src/main/java/appeng/client/render/cablebus/CubeBuilder.java +++ b/src/main/java/appeng/client/render/cablebus/CubeBuilder.java @@ -136,10 +136,10 @@ public class CubeBuilder { v2 = texture.getInterpolatedV( 16 - y2 * 16 ); } - putVertex(builder, face, x2, y2, z1, u1, v2); - putVertex(builder, face, x2, y1, z1, u1, v1); - putVertex(builder, face, x1, y1, z1, u2, v1); - putVertex(builder, face, x1, y2, z1, u2, v2); + putVertex(builder, face, x2, y2, z1, u2, v2); + putVertex(builder, face, x2, y1, z1, u2, v1); + putVertex(builder, face, x1, y1, z1, u1, v1); + putVertex(builder, face, x1, y2, z1, u1, v2); break; case SOUTH: if (customUv == null) @@ -178,10 +178,10 @@ public class CubeBuilder { v2 = texture.getInterpolatedV( 16 - y2 * 16 ); } - putVertex(builder, face, x2, y2, z1, u1, v2); - putVertex(builder, face, x2, y2, z2, u2, v2); - putVertex(builder, face, x2, y1, z2, u2, v1); - putVertex(builder, face, x2, y1, z1, u1, v1); + putVertex(builder, face, x2, y2, z1, u2, v2); + putVertex(builder, face, x2, y2, z2, u1, v2); + putVertex(builder, face, x2, y1, z2, u1, v1); + putVertex(builder, face, x2, y1, z1, u2, v1); break; } diff --git a/src/main/java/appeng/client/render/crafting/CraftingCubeBakedModel.java b/src/main/java/appeng/client/render/crafting/CraftingCubeBakedModel.java new file mode 100644 index 000000000..32b144d06 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/CraftingCubeBakedModel.java @@ -0,0 +1,294 @@ +package appeng.client.render.crafting; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import javax.annotation.Nullable; + +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.minecraftforge.common.property.IExtendedBlockState; + +import appeng.block.crafting.BlockCraftingUnit; +import appeng.client.render.cablebus.CubeBuilder; + + +/** + * The base model for baked models used by components of the crafting cube multi-block in it's formed state. + * Primarily this base class handles adding the "ring" that frames the multi-block structure and delegates + * rendering of the "inner" part of each block to the subclasses of this class. + */ +abstract class CraftingCubeBakedModel implements IBakedModel +{ + + private final VertexFormat format; + + private final TextureAtlasSprite ringCorner; + + private final TextureAtlasSprite ringHor; + + private final TextureAtlasSprite ringVer; + + CraftingCubeBakedModel( VertexFormat format, TextureAtlasSprite ringCorner, TextureAtlasSprite ringHor, TextureAtlasSprite ringVer ) + { + this.format = format; + this.ringCorner = ringCorner; + this.ringHor = ringHor; + this.ringVer = ringVer; + } + + @Override + public List getQuads( @Nullable IBlockState state, @Nullable EnumFacing side, long rand ) + { + + if( side == null ) + { + return Collections.emptyList(); // No generic quads for this model + } + + EnumSet connections = getConnections( state ); + + List quads = new ArrayList<>(); + CubeBuilder builder = new CubeBuilder( format, quads ); + + builder.setDrawFaces( EnumSet.of( side ) ); + + // Add the quads for the ring that frames the entire multi-block structure + addRing( builder, side, connections ); + + // Calculate the bounds of the "inner" block that is framed by the border drawn above + float x2 = connections.contains( EnumFacing.EAST ) ? 16 : 13.01f; + float x1 = connections.contains( EnumFacing.WEST ) ? 0 : 2.99f; + + float y2 = connections.contains( EnumFacing.UP ) ? 16 : 13.01f; + float y1 = connections.contains( EnumFacing.DOWN ) ? 0 : 2.99f; + + float z2 = connections.contains( EnumFacing.SOUTH ) ? 16 : 13.01f; + float z1 = connections.contains( EnumFacing.NORTH ) ? 0 : 2.99f; + + // On the axis of the side that we're currently drawing, extend the dimensions + // out to the outer face of the block + switch( side ) + { + case DOWN: + case UP: + y1 = 0; + y2 = 16; + break; + case NORTH: + case SOUTH: + z1 = 0; + z2 = 16; + break; + case WEST: + case EAST: + x1 = 0; + x2 = 16; + break; + } + + addInnerCube( side, state, builder, x1, y1, z1, x2, y2, z2 ); + + return quads; + } + + private void addRing( CubeBuilder builder, @Nullable EnumFacing side, EnumSet connections ) + { + // Fill in the corners + builder.setTexture( ringCorner ); + addCornerCap( builder, connections, side, EnumFacing.UP, EnumFacing.EAST, EnumFacing.NORTH ); + addCornerCap( builder, connections, side, EnumFacing.UP, EnumFacing.EAST, EnumFacing.SOUTH ); + addCornerCap( builder, connections, side, EnumFacing.UP, EnumFacing.WEST, EnumFacing.NORTH ); + addCornerCap( builder, connections, side, EnumFacing.UP, EnumFacing.WEST, EnumFacing.SOUTH ); + addCornerCap( builder, connections, side, EnumFacing.DOWN, EnumFacing.EAST, EnumFacing.NORTH ); + addCornerCap( builder, connections, side, EnumFacing.DOWN, EnumFacing.EAST, EnumFacing.SOUTH ); + addCornerCap( builder, connections, side, EnumFacing.DOWN, EnumFacing.WEST, EnumFacing.NORTH ); + addCornerCap( builder, connections, side, EnumFacing.DOWN, EnumFacing.WEST, EnumFacing.SOUTH ); + + // Fill in the remaining stripes of the face + for( EnumFacing a : EnumFacing.values() ) + { + if( a == side || a == side.getOpposite() ) + { + continue; + } + + // Select the horizontal or vertical ring texture depending on which side we're filling in + if( ( side.getAxis() != EnumFacing.Axis.Y ) && ( a == EnumFacing.NORTH || a == EnumFacing.EAST || a == EnumFacing.WEST || a == EnumFacing.SOUTH ) ) + { + builder.setTexture( ringVer ); + } + else if( side.getAxis() == EnumFacing.Axis.Y && ( a == EnumFacing.EAST || a == EnumFacing.WEST ) ) + { + builder.setTexture( ringVer ); + } + else + { + builder.setTexture( ringHor ); + } + + // If there's an adjacent crafting cube block on side a, then the core of the block already extends + // fully to this side. So only bother drawing the stripe, if there's no connection. + if( !connections.contains( a ) ) + { + // Note that since we're drawing something that "looks" 2-dimensional, + // two of the following will always be 0 and 16. + float x1 = 0, y1 = 0, z1 = 0, x2 = 16, y2 = 16, z2 = 16; + + switch( a ) + { + case DOWN: + y1 = 0; + y2 = 3; + break; + case UP: + y1 = 13.0f; + y2 = 16; + break; + case WEST: + x1 = 0; + x2 = 3; + break; + case EAST: + x1 = 13; + x2 = 16; + break; + case NORTH: + z1 = 0; + z2 = 3; + break; + case SOUTH: + z1 = 13; + z2 = 16; + break; + } + + // Constraint the stripe in the two directions perpendicular to a in case there has been a corner + // drawn in those directions. Since a corner is drawn if the three touching faces dont have adjacent + // crafting cube blocks, we'd have to check for a, side, and the perpendicular direction. But in this + // block, we've already checked for side (due to face culling) and a (see above). + EnumFacing perpendicular = a.rotateAround( side.getAxis() ); + for ( EnumFacing cornerCandidate: EnumSet.of(perpendicular, perpendicular.getOpposite())) + { + if( !connections.contains( cornerCandidate ) ) + { + // There's a cap in this direction + switch( cornerCandidate ) + { + case DOWN: + y1 = 3; + break; + case UP: + y2 = 13; + break; + case NORTH: + z1 = 3; + break; + case SOUTH: + z2 = 13; + break; + case WEST: + x1 = 3; + break; + case EAST: + x2 = 13; + break; + } + } + } + + builder.addCube( x1, y1, z1, x2, y2, z2 ); + } + } + } + + /** + * Adds a 3x3x3 corner cap to the cube builder if there are no adjacent crafting cubes on that corner. + */ + private void addCornerCap( CubeBuilder builder, EnumSet connections, EnumFacing side, EnumFacing down, EnumFacing west, EnumFacing north ) + { + if( connections.contains( down ) || connections.contains( west ) || connections.contains( north ) ) + { + return; + } + + // Only add faces for sides that can actually be seen (the outside of the cube) + if( side != down && side != west && side != north ) + { + return; + } + + float x1 = (west == EnumFacing.WEST ? 0 : 13); + float y1 = (down == EnumFacing.DOWN ? 0 : 13); + float z1 = (north == EnumFacing.NORTH ? 0 : 13); + float x2 = (west == EnumFacing.WEST ? 3 : 16); + float y2 = (down == EnumFacing.DOWN ? 3 : 16); + float z2 = (north == EnumFacing.NORTH ? 3 : 16); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + } + + // Retrieve the cube connection state from the block state + // If none is present, just assume there are no adjacent crafting cube blocks + private static EnumSet getConnections( @Nullable IBlockState state ) + { + if( !( state instanceof IExtendedBlockState ) ) + { + return EnumSet.noneOf( EnumFacing.class ); + } + + IExtendedBlockState extState = (IExtendedBlockState) state; + CraftingCubeState cubeState = extState.getValue( BlockCraftingUnit.STATE ); + if( cubeState == null ) + { + return EnumSet.noneOf( EnumFacing.class ); + } + + return cubeState.getConnections(); + } + + protected abstract void addInnerCube( EnumFacing facing, IBlockState state, CubeBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2 ); + + @Override + public boolean isAmbientOcclusion() + { + return false; + } + + @Override + public boolean isGui3d() + { + return false; + } + + @Override + public boolean isBuiltInRenderer() + { + return false; + } + + @Override + public TextureAtlasSprite getParticleTexture() + { + return null; + } + + @Override + public ItemCameraTransforms getItemCameraTransforms() + { + return ItemCameraTransforms.DEFAULT; + } + + @Override + public ItemOverrideList getOverrides() + { + return ItemOverrideList.NONE; + } +} diff --git a/src/main/java/appeng/client/render/crafting/CraftingCubeModel.java b/src/main/java/appeng/client/render/crafting/CraftingCubeModel.java new file mode 100644 index 000000000..1a52ec0e9 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/CraftingCubeModel.java @@ -0,0 +1,137 @@ +package appeng.client.render.crafting; + + +import java.util.Collection; +import java.util.Collections; + +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.common.model.IModelState; +import net.minecraftforge.common.model.TRSRTransformation; + +import appeng.block.crafting.BlockCraftingUnit; +import appeng.core.AppEng; + + +/** + * The built-in model for the connected texture crafting cube. + */ +class CraftingCubeModel implements IModel +{ + + private final static ResourceLocation RING_CORNER = texture( "ring_corner" ); + private final static ResourceLocation RING_SIDE_HOR = texture( "ring_side_hor" ); + private final static ResourceLocation RING_SIDE_VER = texture( "ring_side_ver" ); + private final static ResourceLocation UNIT_BASE = texture( "unit_base" ); + private final static ResourceLocation LIGHT_BASE = texture( "light_base" ); + private final static ResourceLocation ACCELERATOR_LIGHT = texture( "accelerator_light" ); + private final static ResourceLocation STORAGE_1K_LIGHT = texture( "storage_1k_light" ); + private final static ResourceLocation STORAGE_4K_LIGHT = texture( "storage_4k_light" ); + private final static ResourceLocation STORAGE_16K_LIGHT = texture( "storage_16k_light" ); + private final static ResourceLocation STORAGE_64K_LIGHT = texture( "storage_64k_light" ); + private final static ResourceLocation MONITOR_BASE = texture( "monitor_base" ); + private final static ResourceLocation MONITOR_LIGHT_DARK = texture( "monitor_light_dark" ); + private final static ResourceLocation MONITOR_LIGHT_MEDIUM = texture( "monitor_light_medium" ); + private final static ResourceLocation MONITOR_LIGHT_BRIGHT = texture( "monitor_light_bright" ); + + private final BlockCraftingUnit.CraftingUnitType type; + + CraftingCubeModel( BlockCraftingUnit.CraftingUnitType type ) + { + this.type = type; + } + + @Override + public Collection getDependencies() + { + return Collections.emptyList(); + } + + @Override + public Collection getTextures() + { + return ImmutableList.of( + RING_CORNER, + RING_SIDE_HOR, + RING_SIDE_VER, + UNIT_BASE, + LIGHT_BASE, + ACCELERATOR_LIGHT, + STORAGE_1K_LIGHT, + STORAGE_4K_LIGHT, + STORAGE_16K_LIGHT, + STORAGE_64K_LIGHT, + MONITOR_BASE, + MONITOR_LIGHT_DARK, + MONITOR_LIGHT_MEDIUM, + MONITOR_LIGHT_BRIGHT + ); + } + + @Override + public IBakedModel bake( IModelState state, VertexFormat format, Function bakedTextureGetter ) + { + // Retrieve our textures and pass them on to the baked model + TextureAtlasSprite ringCorner = bakedTextureGetter.apply( RING_CORNER ); + TextureAtlasSprite ringSideHor = bakedTextureGetter.apply( RING_SIDE_HOR ); + TextureAtlasSprite ringSideVer = bakedTextureGetter.apply( RING_SIDE_VER ); + + switch( type ) + { + case UNIT: + return new UnitBakedModel( format, ringCorner, ringSideHor, ringSideVer, bakedTextureGetter.apply( UNIT_BASE ) ); + case ACCELERATOR: + case STORAGE_1K: + case STORAGE_4K: + case STORAGE_16K: + case STORAGE_64K: + return new LightBakedModel( format, ringCorner, ringSideHor, ringSideVer, bakedTextureGetter.apply( LIGHT_BASE ), getLightTexture( bakedTextureGetter, type ) ); + case MONITOR: + return new MonitorBakedModel( format, ringCorner, ringSideHor, ringSideVer, + bakedTextureGetter.apply( UNIT_BASE ), + bakedTextureGetter.apply( MONITOR_BASE ), + bakedTextureGetter.apply( MONITOR_LIGHT_DARK ), + bakedTextureGetter.apply( MONITOR_LIGHT_MEDIUM ), + bakedTextureGetter.apply( MONITOR_LIGHT_BRIGHT ) + ); + default: + throw new IllegalArgumentException( "Unsupported crafting unit type: " + type ); + } + } + + private static TextureAtlasSprite getLightTexture( Function textureGetter, BlockCraftingUnit.CraftingUnitType type ) + { + switch( type ) + { + case ACCELERATOR: + return textureGetter.apply( ACCELERATOR_LIGHT ); + case STORAGE_1K: + return textureGetter.apply( STORAGE_1K_LIGHT ); + case STORAGE_4K: + return textureGetter.apply( STORAGE_4K_LIGHT ); + case STORAGE_16K: + return textureGetter.apply( STORAGE_16K_LIGHT ); + case STORAGE_64K: + return textureGetter.apply( STORAGE_64K_LIGHT ); + default: + throw new IllegalArgumentException( "Crafting unit type " + type + " does not use a light texture." ); + } + } + + @Override + public IModelState getDefaultState() + { + return TRSRTransformation.identity(); + } + + private static ResourceLocation texture( String name ) + { + return new ResourceLocation( AppEng.MOD_ID, "blocks/crafting/" + name ); + } +} diff --git a/src/main/java/appeng/client/render/crafting/CraftingCubeRendering.java b/src/main/java/appeng/client/render/crafting/CraftingCubeRendering.java new file mode 100644 index 000000000..242ec2871 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/CraftingCubeRendering.java @@ -0,0 +1,73 @@ +package appeng.client.render.crafting; + + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.util.ResourceLocation; + +import appeng.block.crafting.BlockCraftingUnit; +import appeng.bootstrap.BlockRenderingCustomizer; +import appeng.bootstrap.IBlockRendering; +import appeng.bootstrap.IItemRendering; +import appeng.core.AppEng; + + +/** + * Rendering customization for the crafting cube. + */ +public class CraftingCubeRendering extends BlockRenderingCustomizer +{ + + private final String registryName; + + private final BlockCraftingUnit.CraftingUnitType type; + + public CraftingCubeRendering( String registryName, BlockCraftingUnit.CraftingUnitType type ) + { + this.registryName = registryName; + this.type = type; + } + + @Override + public void customize( IBlockRendering rendering, IItemRendering itemRendering ) + { + ResourceLocation baseName = new ResourceLocation( AppEng.MOD_ID, registryName ); + + // Disable auto-rotation + rendering.modelCustomizer( ( loc, model ) -> model ); + + // This is the standard blockstate model + ModelResourceLocation defaultModel = new ModelResourceLocation( baseName, "normal" ); + + // This is the built-in model + String builtInName = "models/block/crafting/" + registryName + "/builtin"; + ModelResourceLocation builtInModelName = new ModelResourceLocation( new ResourceLocation( AppEng.MOD_ID, builtInName ), "normal" ); + + rendering.builtInModel( builtInName, new CraftingCubeModel( type ) ); + + rendering.stateMapper( block -> mapState( block, defaultModel, builtInModelName ) ); + } + + private Map mapState( Block block, ModelResourceLocation defaultModel, ModelResourceLocation formedModel ) + { + Map result = new HashMap<>(); + for( IBlockState state : block.getBlockState().getValidStates() ) + { + if( state.getValue( BlockCraftingUnit.FORMED ) ) + { + // Always use the builtin model if the multiblock is formed + result.put( state, formedModel ); + } + else + { + // Use the default model + result.put( state, defaultModel ); + } + } + return result; + } +} diff --git a/src/main/java/appeng/client/render/crafting/CraftingCubeState.java b/src/main/java/appeng/client/render/crafting/CraftingCubeState.java new file mode 100644 index 000000000..d468ab3b4 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/CraftingCubeState.java @@ -0,0 +1,27 @@ +package appeng.client.render.crafting; + + +import java.util.EnumSet; + +import net.minecraft.util.EnumFacing; + + +/** + * Transports the rendering state for a block of a crafting cube. + */ +public final class CraftingCubeState +{ + + // Contains information on which sides of the block are connected to other parts of a formed crafting cube + private final EnumSet connections; + + public CraftingCubeState( EnumSet connections ) + { + this.connections = connections; + } + + public EnumSet getConnections() + { + return connections; + } +} diff --git a/src/main/java/appeng/client/render/crafting/LightBakedModel.java b/src/main/java/appeng/client/render/crafting/LightBakedModel.java new file mode 100644 index 000000000..1cdbcfb3b --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/LightBakedModel.java @@ -0,0 +1,42 @@ +package appeng.client.render.crafting; + + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; + +import appeng.block.crafting.BlockCraftingUnit; +import appeng.client.render.cablebus.CubeBuilder; + + +/** + * Crafting cube baked model that adds a full-bright light texture on top of a normal base texture onto the inner cube. + * The light texture is only drawn fullbright if the multiblock is currently powered. + */ +class LightBakedModel extends CraftingCubeBakedModel +{ + + private final TextureAtlasSprite baseTexture; + + private final TextureAtlasSprite lightTexture; + + LightBakedModel( VertexFormat format, TextureAtlasSprite ringCorner, TextureAtlasSprite ringHor, TextureAtlasSprite ringVer, TextureAtlasSprite baseTexture, TextureAtlasSprite lightTexture ) + { + super( format, ringCorner, ringHor, ringVer ); + this.baseTexture = baseTexture; + this.lightTexture = lightTexture; + } + + @Override + protected void addInnerCube( EnumFacing facing, IBlockState state, CubeBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2 ) + { + builder.setTexture( baseTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + + boolean powered = state.getValue( BlockCraftingUnit.POWERED ); + builder.setRenderFullBright( powered ); + builder.setTexture( lightTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + } +} diff --git a/src/main/java/appeng/client/render/crafting/MonitorBakedModel.java b/src/main/java/appeng/client/render/crafting/MonitorBakedModel.java new file mode 100644 index 000000000..966de895e --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/MonitorBakedModel.java @@ -0,0 +1,116 @@ +package appeng.client.render.crafting; + + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.property.IExtendedBlockState; + +import appeng.api.util.AEColor; +import appeng.block.crafting.BlockCraftingMonitor; +import appeng.client.render.cablebus.CubeBuilder; + + +/** + * The baked model for the crafting monitor. Please note that this model doesn't handle the item being displayed. That is handled by a TESR. + * Instead, this model adds 3 layered light textures using the [dark|medium|bright] color variants of the attached bus color. The textures + * are full-bright if the cube is powered. + */ +class MonitorBakedModel extends CraftingCubeBakedModel +{ + + private final TextureAtlasSprite chassisTexture; + + private final TextureAtlasSprite baseTexture; + + private final TextureAtlasSprite lightDarkTexture; + + private final TextureAtlasSprite lightMediumTexture; + + private final TextureAtlasSprite lightBrightTexture; + + MonitorBakedModel( VertexFormat format, + TextureAtlasSprite ringCorner, + TextureAtlasSprite ringHor, + TextureAtlasSprite ringVer, + TextureAtlasSprite chassisTexture, + TextureAtlasSprite baseTexture, + TextureAtlasSprite lightDarkTexture, + TextureAtlasSprite lightMediumTexture, + TextureAtlasSprite lightBrightTexture ) + { + super( format, ringCorner, ringHor, ringVer ); + this.chassisTexture = chassisTexture; + this.baseTexture = baseTexture; + this.lightDarkTexture = lightDarkTexture; + this.lightMediumTexture = lightMediumTexture; + this.lightBrightTexture = lightBrightTexture; + } + + @Override + protected void addInnerCube( EnumFacing side, IBlockState state, CubeBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2 ) + { + EnumFacing forward = getForward( state ); + + // For sides other than the front, use the chassis texture + if( side != forward ) + { + builder.setTexture( chassisTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + return; + } + + builder.setTexture( baseTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + + // Now add the three layered light textures + AEColor color = getColor( state ); + boolean powered = state.getValue( BlockCraftingMonitor.POWERED ); + + builder.setRenderFullBright( powered ); + + builder.setColorRGB( color.whiteVariant ); + builder.setTexture( lightBrightTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + + builder.setColorRGB( color.mediumVariant ); + builder.setTexture( lightMediumTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + + builder.setColorRGB( color.blackVariant ); + builder.setTexture( lightDarkTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + + } + + private static AEColor getColor( IBlockState state ) + { + if( state instanceof IExtendedBlockState ) + { + IExtendedBlockState extState = (IExtendedBlockState) state; + AEColor color = extState.getValue( BlockCraftingMonitor.COLOR ); + if( color != null ) + { + return color; + } + } + + return AEColor.Transparent; + } + + private static EnumFacing getForward( IBlockState state ) + { + if( state instanceof IExtendedBlockState ) + { + IExtendedBlockState extState = (IExtendedBlockState) state; + EnumFacing forward = extState.getValue( BlockCraftingMonitor.FORWARD ); + if( forward != null ) + { + return forward; + } + } + + return EnumFacing.NORTH; + } +} diff --git a/src/main/java/appeng/client/render/crafting/UnitBakedModel.java b/src/main/java/appeng/client/render/crafting/UnitBakedModel.java new file mode 100644 index 000000000..7778412d9 --- /dev/null +++ b/src/main/java/appeng/client/render/crafting/UnitBakedModel.java @@ -0,0 +1,32 @@ +package appeng.client.render.crafting; + + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.util.EnumFacing; + +import appeng.client.render.cablebus.CubeBuilder; + + +/** + * A simple crafting unit model that uses an un-lit texture for the inner block. + */ +class UnitBakedModel extends CraftingCubeBakedModel +{ + + private final TextureAtlasSprite unitTexture; + + UnitBakedModel( VertexFormat format, TextureAtlasSprite ringCorner, TextureAtlasSprite ringHor, TextureAtlasSprite ringVer, TextureAtlasSprite unitTexture ) + { + super( format, ringCorner, ringHor, ringVer ); + this.unitTexture = unitTexture; + } + + @Override + protected void addInnerCube( EnumFacing facing, IBlockState state, CubeBuilder builder, float x1, float y1, float z1, float x2, float y2, float z2 ) + { + builder.setTexture( unitTexture ); + builder.addCube( x1, y1, z1, x2, y2, z2 ); + } +} diff --git a/src/main/java/appeng/core/api/definitions/ApiBlocks.java b/src/main/java/appeng/core/api/definitions/ApiBlocks.java index 61891bd5b..20fd2b32f 100644 --- a/src/main/java/appeng/core/api/definitions/ApiBlocks.java +++ b/src/main/java/appeng/core/api/definitions/ApiBlocks.java @@ -83,6 +83,7 @@ import appeng.bootstrap.BlockRenderingCustomizer; import appeng.bootstrap.FeatureFactory; import appeng.bootstrap.IBlockRendering; import appeng.bootstrap.IItemRendering; +import appeng.client.render.crafting.CraftingCubeRendering; import appeng.client.render.model.GlassModel; import appeng.core.AppEng; import appeng.core.features.AEFeature; @@ -321,28 +322,35 @@ public final class ApiBlocks implements IBlocks FeatureFactory crafting = registry.features( AEFeature.CraftingCPU ); this.craftingUnit = crafting.block( "crafting_unit", () -> new BlockCraftingUnit( CraftingUnitType.UNIT ) ) + .rendering( new CraftingCubeRendering( "crafting_unit", CraftingUnitType.UNIT ) ) .useCustomItemModel() .build(); this.craftingAccelerator = crafting.block( "crafting_accelerator", () -> new BlockCraftingUnit( CraftingUnitType.ACCELERATOR ) ) + .rendering( new CraftingCubeRendering( "crafting_accelerator", CraftingUnitType.ACCELERATOR ) ) .useCustomItemModel() .build(); this.craftingStorage1k = crafting.block( "crafting_storage_1k", () -> new BlockCraftingStorage( CraftingUnitType.STORAGE_1K ) ) .item( ItemCraftingStorage::new ) + .rendering( new CraftingCubeRendering( "crafting_storage_1k", CraftingUnitType.STORAGE_1K ) ) .useCustomItemModel() .build(); this.craftingStorage4k = crafting.block( "crafting_storage_4k", () -> new BlockCraftingStorage( CraftingUnitType.STORAGE_4K ) ) .item( ItemCraftingStorage::new ) + .rendering( new CraftingCubeRendering( "crafting_storage_4k", CraftingUnitType.STORAGE_4K ) ) .useCustomItemModel() .build(); this.craftingStorage16k = crafting.block( "crafting_storage_16k", () -> new BlockCraftingStorage( CraftingUnitType.STORAGE_16K ) ) .item( ItemCraftingStorage::new ) + .rendering( new CraftingCubeRendering( "crafting_storage_16k", CraftingUnitType.STORAGE_16K ) ) .useCustomItemModel() .build(); this.craftingStorage64k = crafting.block( "crafting_storage_64k", () -> new BlockCraftingStorage( CraftingUnitType.STORAGE_64K ) ) .item( ItemCraftingStorage::new ) + .rendering( new CraftingCubeRendering( "crafting_storage_64k", CraftingUnitType.STORAGE_64K ) ) .useCustomItemModel() .build(); this.craftingMonitor = crafting.block( "crafting_monitor", BlockCraftingMonitor::new ) + .rendering( new CraftingCubeRendering( "crafting_monitor", CraftingUnitType.MONITOR ) ) .useCustomItemModel() .build(); diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java index 3e3740c76..cfae99af4 100644 --- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java @@ -465,6 +465,10 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU private TileCraftingTile getCore() { + if( this.machineSrc == null ) + { + return null; + } return (TileCraftingTile) this.machineSrc.via; } diff --git a/src/main/java/appeng/tile/crafting/TileCraftingTile.java b/src/main/java/appeng/tile/crafting/TileCraftingTile.java index dfb9967ec..8980b2119 100644 --- a/src/main/java/appeng/tile/crafting/TileCraftingTile.java +++ b/src/main/java/appeng/tile/crafting/TileCraftingTile.java @@ -158,11 +158,18 @@ public class TileCraftingTile extends AENetworkTile implements IAEMultiBlock, IP } final IBlockState current = this.worldObj.getBlockState( this.pos ); - final IBlockState newState = current.withProperty( BlockCraftingUnit.POWERED, power ).withProperty( BlockCraftingUnit.FORMED, formed ); - if( current != newState ) + // The tile might try to update while being destroyed + if( current.getBlock() instanceof BlockCraftingUnit ) { - this.worldObj.setBlockState( this.pos, newState ); + final IBlockState newState = current.withProperty( BlockCraftingUnit.POWERED, power ).withProperty( BlockCraftingUnit.FORMED, formed ); + + if( current != newState ) + { + // Not using flag 2 here (only send to clients, prevent block update) will cause infinite loops + // In case there is an inconsistency in the crafting clusters. + this.worldObj.setBlockState( this.pos, newState, 2 ); + } } if( updateFormed ) diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_accelerator.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_accelerator.json new file mode 100644 index 000000000..c2e2ba4a8 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_accelerator.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/accelerator" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_monitor.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_monitor.json new file mode 100644 index 000000000..4b3dbb132 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_monitor.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/monitor" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_16k.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_16k.json new file mode 100644 index 000000000..b824cb66e --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_16k.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/storage_16k" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_1k.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_1k.json new file mode 100644 index 000000000..7e0996192 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_1k.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/storage_1k" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_4k.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_4k.json new file mode 100644 index 000000000..781d0d5f6 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_4k.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/storage_4k" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_64k.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_64k.json new file mode 100644 index 000000000..110f3cec7 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_storage_64k.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/storage_64k" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/crafting_unit.json b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_unit.json new file mode 100644 index 000000000..1dd923901 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/crafting_unit.json @@ -0,0 +1,5 @@ +{ + "variants": { + "normal": { "model": "appliedenergistics2:crafting/unit" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/accelerator.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/accelerator.json new file mode 100644 index 000000000..7b29d5b5d --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/accelerator.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/accelerator" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/monitor.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/monitor.json new file mode 100644 index 000000000..eaf0429ee --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/monitor.json @@ -0,0 +1,11 @@ +{ + "parent": "block/cube", + "textures": { + "north": "appliedenergistics2:blocks/crafting/monitor", + "east": "appliedenergistics2:blocks/crafting/unit", + "west": "appliedenergistics2:blocks/crafting/unit", + "south": "appliedenergistics2:blocks/crafting/unit", + "up": "appliedenergistics2:blocks/crafting/unit", + "down": "appliedenergistics2:blocks/crafting/unit" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_16k.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_16k.json new file mode 100644 index 000000000..52ee88fb6 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_16k.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/storage_16k" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_1k.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_1k.json new file mode 100644 index 000000000..3d0d2beaa --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_1k.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/storage_1k" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_4k.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_4k.json new file mode 100644 index 000000000..fd48bae5e --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_4k.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/storage_4k" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_64k.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_64k.json new file mode 100644 index 000000000..1dafb740b --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/storage_64k.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/storage_64k" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/block/crafting/unit.json b/src/main/resources/assets/appliedenergistics2/models/block/crafting/unit.json new file mode 100644 index 000000000..417043459 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/block/crafting/unit.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "appliedenergistics2:blocks/crafting/unit" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_accelerator.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_accelerator.json index 7b29d5b5d..e45c6c48d 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_accelerator.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_accelerator.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/accelerator" - } + "parent": "appliedenergistics2:block/crafting/accelerator" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_monitor.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_monitor.json index eaf0429ee..7c1d3bdc3 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_monitor.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_monitor.json @@ -1,11 +1,3 @@ { - "parent": "block/cube", - "textures": { - "north": "appliedenergistics2:blocks/crafting/monitor", - "east": "appliedenergistics2:blocks/crafting/unit", - "west": "appliedenergistics2:blocks/crafting/unit", - "south": "appliedenergistics2:blocks/crafting/unit", - "up": "appliedenergistics2:blocks/crafting/unit", - "down": "appliedenergistics2:blocks/crafting/unit" - } + "parent": "appliedenergistics2:block/crafting/monitor" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_16k.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_16k.json index 52ee88fb6..8e7b2150d 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_16k.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_16k.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/storage_16k" - } + "parent": "appliedenergistics2:block/crafting/storage_16k" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_1k.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_1k.json index 3d0d2beaa..99b074011 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_1k.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_1k.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/storage_1k" - } + "parent": "appliedenergistics2:block/crafting/storage_1k" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_4k.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_4k.json index fd48bae5e..9144d3942 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_4k.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_4k.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/storage_4k" - } + "parent": "appliedenergistics2:block/crafting/storage_4k" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_64k.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_64k.json index 1dafb740b..b8e7495b0 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_64k.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_storage_64k.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/storage_64k" - } + "parent": "appliedenergistics2:block/crafting/storage_64k" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/models/item/crafting_unit.json b/src/main/resources/assets/appliedenergistics2/models/item/crafting_unit.json index 417043459..4ced365c1 100644 --- a/src/main/resources/assets/appliedenergistics2/models/item/crafting_unit.json +++ b/src/main/resources/assets/appliedenergistics2/models/item/crafting_unit.json @@ -1,6 +1,3 @@ { - "parent": "block/cube_all", - "textures": { - "all": "appliedenergistics2:blocks/crafting/unit" - } + "parent": "appliedenergistics2:block/crafting/unit" } \ No newline at end of file diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/accelerator_fit.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/accelerator_light.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/accelerator_fit.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/accelerator_light.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/fit_solid.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/light_base.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/fit_solid.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/light_base.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_outer.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_base.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_outer.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_base.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_light.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_bright.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_light.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_bright.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_dark.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_dark.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_dark.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_dark.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_medium.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_medium.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_fit_medium.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/monitor_light_medium.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/unit_ring.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_corner.png similarity index 100% rename from src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/unit_ring.png rename to src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_corner.png diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_hor.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_hor.png new file mode 100644 index 0000000000000000000000000000000000000000..38153a448b0b398a9744513aba66072358b23a21 GIT binary patch literal 2867 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_ver.png b/src/main/resources/assets/appliedenergistics2/textures/blocks/crafting/ring_side_ver.png new file mode 100644 index 0000000000000000000000000000000000000000..50004ea26c596792c34cb77e0b7467dacea6f4de GIT binary patch literal 2867 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 P0|SGntDnm{r-UW|YNkf<