From b26a1312f52575f28f2d4e8842a641a64b910880 Mon Sep 17 00:00:00 2001 From: CSX8600 Date: Wed, 31 Jul 2019 20:39:04 -0500 Subject: [PATCH] Add Wig-Wag Signals (Taiga #39) --- build.gradle | 2 +- .../trafficcontrol/ModBlocks.java | 4 + .../trafficcontrol/blocks/BlockWigWag.java | 115 +++++++++++ .../item/ItemCrossingRelayTuner.java | 13 ++ .../trafficcontrol/proxy/CommonProxy.java | 5 + .../tileentity/RelayTileEntity.java | 102 +++++++--- .../tileentity/WigWagTileEntity.java | 105 ++++++++++ .../tileentity/render/RenderBoxHelper.java | 188 ++++++++++++++++++ .../render/RendererCrossingGateGate.java | 188 +----------------- .../tileentity/render/RendererWigWag.java | 117 +++++++++++ .../trafficcontrol/blockstates/wig_wag.json | 91 +++++++++ .../assets/trafficcontrol/lang/en_us.lang | 1 + .../trafficcontrol/models/block/wig_wag.json | 90 +++++++++ 13 files changed, 807 insertions(+), 214 deletions(-) create mode 100644 src/main/java/com/clussmanproductions/trafficcontrol/blocks/BlockWigWag.java create mode 100644 src/main/java/com/clussmanproductions/trafficcontrol/tileentity/WigWagTileEntity.java create mode 100644 src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RenderBoxHelper.java create mode 100644 src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererWigWag.java create mode 100644 src/main/resources/assets/trafficcontrol/blockstates/wig_wag.json create mode 100644 src/main/resources/assets/trafficcontrol/models/block/wig_wag.json diff --git a/build.gradle b/build.gradle index f2007924..64f49d7b 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge' //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -version = "0.0.5" +version = "0.0.6a" group = "com.clussmanproductions.trafficcontrol" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "trafficcontrol" diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/ModBlocks.java b/src/main/java/com/clussmanproductions/trafficcontrol/ModBlocks.java index 4114a4d6..282f3ed0 100644 --- a/src/main/java/com/clussmanproductions/trafficcontrol/ModBlocks.java +++ b/src/main/java/com/clussmanproductions/trafficcontrol/ModBlocks.java @@ -26,6 +26,7 @@ import com.clussmanproductions.trafficcontrol.blocks.BlockSign; import com.clussmanproductions.trafficcontrol.blocks.BlockStreetLightDouble; import com.clussmanproductions.trafficcontrol.blocks.BlockStreetLightSingle; +import com.clussmanproductions.trafficcontrol.blocks.BlockWigWag; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder; @@ -86,6 +87,8 @@ public class ModBlocks { public static BlockLightSource light_source; @ObjectHolder("street_light_double") public static BlockStreetLightDouble street_light_double; + @ObjectHolder("wig_wag") + public static BlockWigWag wig_wag; @SideOnly(Side.CLIENT) public static void initModels(ModelRegistryEvent e) @@ -107,5 +110,6 @@ public static void initModels(ModelRegistryEvent e) drum.initModel(); street_light_single.initModel(); street_light_double.initModel(); + wig_wag.initModel(); } } diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/blocks/BlockWigWag.java b/src/main/java/com/clussmanproductions/trafficcontrol/blocks/BlockWigWag.java new file mode 100644 index 00000000..ec967804 --- /dev/null +++ b/src/main/java/com/clussmanproductions/trafficcontrol/blocks/BlockWigWag.java @@ -0,0 +1,115 @@ +package com.clussmanproductions.trafficcontrol.blocks; + +import com.clussmanproductions.trafficcontrol.ModBlocks; +import com.clussmanproductions.trafficcontrol.ModTrafficControl; +import com.clussmanproductions.trafficcontrol.tileentity.WigWagTileEntity; +import com.clussmanproductions.trafficcontrol.tileentity.render.RendererWigWag; + +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.Material; +import net.minecraft.block.properties.PropertyBool; +import net.minecraft.block.properties.PropertyDirection; +import net.minecraft.block.state.BlockStateContainer; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.Item; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +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.client.model.ModelLoader; +import net.minecraftforge.fml.client.registry.ClientRegistry; + +public class BlockWigWag extends Block implements ITileEntityProvider { + public static PropertyDirection FACING = PropertyDirection.create("facing", EnumFacing.Plane.HORIZONTAL); + public static PropertyBool ACTIVE = PropertyBool.create("active"); + public BlockWigWag() + { + super(Material.IRON); + setRegistryName("wig_wag"); + setUnlocalizedName(ModTrafficControl.MODID + ".wig_wag"); + setHardness(2f); + setCreativeTab(ModTrafficControl.CREATIVE_TAB); + } + + public void initModel() + { + ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(this), 0, new ModelResourceLocation(getRegistryName(), "inventory")); + + ClientRegistry.bindTileEntitySpecialRenderer(WigWagTileEntity.class, new RendererWigWag()); + } + + @Override + public int getMetaFromState(IBlockState state) { + int modifier = 0; + if (state.getValue(ACTIVE)) + { + modifier = 4; + } + return state.getValue(FACING).getHorizontalIndex() + modifier; + } + + @Override + public IBlockState getStateFromMeta(int meta) { + boolean active = meta >= 4; + meta = active ? meta - 4 : meta; + return getDefaultState().withProperty(FACING, EnumFacing.getHorizontal(meta)).withProperty(ACTIVE, active); + } + + @Override + protected BlockStateContainer createBlockState() { + return new BlockStateContainer(this, FACING, ACTIVE); + } + + @Override + public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { + if (state.getBlock() != ModBlocks.wig_wag) + { + return FULL_BLOCK_AABB; + } + + switch(state.getValue(FACING)) + { + case WEST: + return new AxisAlignedBB(0.375,0,0.375,0.625,1.25,1.3125); + case EAST: + return new AxisAlignedBB(0.375,0,0.5625,0.625,1.25,-0.375); + case NORTH: + return new AxisAlignedBB(-0.375,0,0.625,0.5625,1.25,0.375); + case SOUTH: + return new AxisAlignedBB(0.4375,0,0.625,1.375,1.25,0.375); + } + return super.getBoundingBox(state, source, pos); + } + + @Override + public int getLightValue(IBlockState state) { + return state.getValue(ACTIVE) ? 15 : 0; + } + + @Override + public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, + float hitZ, int meta, EntityLivingBase placer, EnumHand hand) { + return getDefaultState().withProperty(FACING, placer.getHorizontalFacing()).withProperty(ACTIVE, false); + } + + @Override + public boolean isOpaqueCube(IBlockState state) { + return false; + } + + @Override + public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + public TileEntity createNewTileEntity(World worldIn, int meta) { + return new WigWagTileEntity(); + } +} diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/item/ItemCrossingRelayTuner.java b/src/main/java/com/clussmanproductions/trafficcontrol/item/ItemCrossingRelayTuner.java index d82a5e88..59fe5952 100644 --- a/src/main/java/com/clussmanproductions/trafficcontrol/item/ItemCrossingRelayTuner.java +++ b/src/main/java/com/clussmanproductions/trafficcontrol/item/ItemCrossingRelayTuner.java @@ -5,6 +5,7 @@ import com.clussmanproductions.trafficcontrol.tileentity.BellBaseTileEntity; import com.clussmanproductions.trafficcontrol.tileentity.CrossingGateGateTileEntity; import com.clussmanproductions.trafficcontrol.tileentity.RelayTileEntity; +import com.clussmanproductions.trafficcontrol.tileentity.WigWagTileEntity; import net.minecraft.block.state.IBlockState; import net.minecraft.client.renderer.block.model.ModelResourceLocation; @@ -197,5 +198,17 @@ private void checkUseOnTileEntity(World world, TileEntity te, RelayTileEntity re player.sendMessage(new TextComponentString("Unpaired Bell from Relay Box")); } } + + if (te instanceof WigWagTileEntity) + { + if (relay.addOrRemoveWigWag(te.getPos())) + { + player.sendMessage(new TextComponentString("Paired Wig Wag to Relay Box")); + } + else + { + player.sendMessage(new TextComponentString("Unpaired Wig Wag from Relay Box")); + } + } } } diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/proxy/CommonProxy.java b/src/main/java/com/clussmanproductions/trafficcontrol/proxy/CommonProxy.java index ed622a73..363c00a0 100644 --- a/src/main/java/com/clussmanproductions/trafficcontrol/proxy/CommonProxy.java +++ b/src/main/java/com/clussmanproductions/trafficcontrol/proxy/CommonProxy.java @@ -29,6 +29,7 @@ import com.clussmanproductions.trafficcontrol.blocks.BlockSign; import com.clussmanproductions.trafficcontrol.blocks.BlockStreetLightDouble; import com.clussmanproductions.trafficcontrol.blocks.BlockStreetLightSingle; +import com.clussmanproductions.trafficcontrol.blocks.BlockWigWag; import com.clussmanproductions.trafficcontrol.gui.GuiProxy; import com.clussmanproductions.trafficcontrol.item.ItemCrossingRelayBox; import com.clussmanproductions.trafficcontrol.item.ItemCrossingRelayTuner; @@ -40,6 +41,7 @@ import com.clussmanproductions.trafficcontrol.tileentity.SignTileEntity; import com.clussmanproductions.trafficcontrol.tileentity.StreetLightDoubleTileEntity; import com.clussmanproductions.trafficcontrol.tileentity.StreetLightSingleTileEntity; +import com.clussmanproductions.trafficcontrol.tileentity.WigWagTileEntity; import net.minecraft.block.Block; import net.minecraft.item.Item; @@ -85,6 +87,7 @@ public static void registerBlocks(RegistryEvent.Register e) e.getRegistry().register(new BlockStreetLightSingle()); e.getRegistry().register(new BlockLightSource()); e.getRegistry().register(new BlockStreetLightDouble()); + e.getRegistry().register(new BlockWigWag()); GameRegistry.registerTileEntity(CrossingGateGateTileEntity.class, ModTrafficControl.MODID + "_crossinggategate"); GameRegistry.registerTileEntity(SafetranType3TileEntity.class, ModTrafficControl.MODID + "_safetrantyp3"); @@ -93,6 +96,7 @@ public static void registerBlocks(RegistryEvent.Register e) GameRegistry.registerTileEntity(SignTileEntity.class, ModTrafficControl.MODID + "_sign"); GameRegistry.registerTileEntity(StreetLightSingleTileEntity.class, ModTrafficControl.MODID + "_streetsignsingle"); GameRegistry.registerTileEntity(StreetLightDoubleTileEntity.class, ModTrafficControl.MODID + "_streetlightdouble"); + GameRegistry.registerTileEntity(WigWagTileEntity.class, ModTrafficControl.MODID + "_wigwag"); } @SubscribeEvent @@ -118,6 +122,7 @@ public static void registerItems(RegistryEvent.Register e) e.getRegistry().register(new ItemBlock(ModBlocks.drum).setRegistryName(ModBlocks.drum.getRegistryName())); e.getRegistry().register(new ItemBlock(ModBlocks.street_light_single).setRegistryName(ModBlocks.street_light_single.getRegistryName())); e.getRegistry().register(new ItemBlock(ModBlocks.street_light_double).setRegistryName(ModBlocks.street_light_double.getRegistryName())); + e.getRegistry().register(new ItemBlock(ModBlocks.wig_wag).setRegistryName(ModBlocks.wig_wag.getRegistryName())); } public static void registerSounds(RegistryEvent.Register e) diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/RelayTileEntity.java b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/RelayTileEntity.java index 86482042..3a33ad83 100644 --- a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/RelayTileEntity.java +++ b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/RelayTileEntity.java @@ -6,6 +6,7 @@ import com.clussmanproductions.trafficcontrol.blocks.BlockCrossingGateLamps; import com.clussmanproductions.trafficcontrol.blocks.BlockLampBase; import com.clussmanproductions.trafficcontrol.blocks.BlockLampBase.EnumState; +import com.clussmanproductions.trafficcontrol.blocks.BlockWigWag; import com.clussmanproductions.trafficcontrol.tileentity.CrossingGateGateTileEntity.EnumStatuses; import com.clussmanproductions.trafficcontrol.util.AnyStatement; @@ -34,9 +35,13 @@ public class RelayTileEntity extends TileEntity implements ITickable { // Bell information private boolean alreadyNotifiedBells; + // Wig Wag information + private boolean alreadyNotifiedWigWags; + private ArrayList crossingLampLocations = new ArrayList(); private ArrayList crossingGateLocations = new ArrayList(); private ArrayList bellLocations = new ArrayList(); + private ArrayList wigWagLocations = new ArrayList(); private ArrayList crossingGates = new ArrayList(); private ArrayList bells = new ArrayList(); @@ -65,41 +70,23 @@ public void readFromNBT(NBTTagCompound compound) { // Bell information alreadyNotifiedBells = compound.getBoolean("alreadynotifiedbells"); + fillArrayListFromNBT("lamps", bellLocations, compound); + fillArrayListFromNBT("gate", bellLocations, compound); + fillArrayListFromNBT("bell", bellLocations, compound); + fillArrayListFromNBT("wigwags", wigWagLocations, compound); + } + + private void fillArrayListFromNBT(String key, ArrayList list, NBTTagCompound tag) + { int i = 0; while (true) { - if (!compound.hasKey("lamps" + i)) { + if (!tag.hasKey(key + i)) { break; } - int[] blockPos = compound.getIntArray("lamps" + i); - BlockPos lampPos = new BlockPos(blockPos[0], blockPos[1], blockPos[2]); - crossingLampLocations.add(lampPos); - - i++; - } - - i = 0; - while (true) { - if (!compound.hasKey("gate" + i)) { - break; - } - - int[] blockPos = compound.getIntArray("gate" + i); - BlockPos gatePos = new BlockPos(blockPos[0], blockPos[1], blockPos[2]); - crossingGateLocations.add(gatePos); - - i++; - } - - i = 0; - while (true) { - if (!compound.hasKey("bell" + i)) { - break; - } - - int[] blockPos = compound.getIntArray("bell" + i); - BlockPos bellPos = new BlockPos(blockPos[0], blockPos[1], blockPos[2]); - bellLocations.add(bellPos); + int[] blockPos = tag.getIntArray(key + i); + BlockPos pos = new BlockPos(blockPos[0], blockPos[1], blockPos[2]); + list.add(pos); i++; } @@ -124,6 +111,9 @@ public NBTTagCompound writeToNBT(NBTTagCompound compound) { // Bell information nbt.setBoolean("alreadynotifiedbells", alreadyNotifiedBells); + + // Wig Wag information + nbt.setBoolean("alreadynotifiedwigwags", alreadyNotifiedWigWags); for (int i = 0; i < crossingLampLocations.size(); i++) { BlockPos lamps = crossingLampLocations.get(i); @@ -145,6 +135,13 @@ public NBTTagCompound writeToNBT(NBTTagCompound compound) { int[] bellPos = new int[] { bell.getPos().getX(), bell.getPos().getY(), bell.getPos().getZ() }; nbt.setIntArray("bell" + i, bellPos); } + + for (int i = 0; i < wigWagLocations.size(); i++) { + BlockPos wigWag = wigWagLocations.get(i); + + int[] wigWagPos = new int[] { wigWag.getX(), wigWag.getY(), wigWag.getZ() }; + nbt.setIntArray("wigwags" + i, wigWagPos); + } return nbt; } @@ -160,6 +157,7 @@ public void update() { notifyGates(); updateLamps(); updateBells(); + notifyWigWags(); } private void verifyLocations() @@ -323,6 +321,35 @@ private void updateBells() } } + private void notifyWigWags() + { + if (!alreadyNotifiedWigWags) + { + ArrayList positionsToRemove = new ArrayList(); + for(BlockPos pos : wigWagLocations) + { + try + { + IBlockState currentState = world.getBlockState(pos); + world.setBlockState(pos, currentState.withProperty(BlockWigWag.ACTIVE, isPowered)); + } + catch (Exception ex) + { + positionsToRemove.add(pos); + } + } + + for(BlockPos pos : positionsToRemove) + { + wigWagLocations.remove(pos); + + ModTrafficControl.logger.error("Wig Wag at " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ() + " has been unpaired due to an error"); + } + + alreadyNotifiedWigWags = true; + } + } + public void setMaster() { isMaster = true; markDirty(); @@ -417,11 +444,26 @@ public boolean addOrRemoveBell(BellBaseTileEntity bell) { return true; } + public boolean addOrRemoveWigWag(BlockPos wigWagPos) + { + if (wigWagLocations.contains(wigWagPos)) + { + wigWagLocations.remove(wigWagPos); + return false; + } + else + { + wigWagLocations.add(wigWagPos); + return true; + } + } + public void setPowered(boolean isPowered) { this.isPowered = isPowered; alreadyNotifiedGates = false; alreadyNotifiedBells = false; + alreadyNotifiedWigWags = false; markDirty(); } diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/WigWagTileEntity.java b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/WigWagTileEntity.java new file mode 100644 index 00000000..fa425cb4 --- /dev/null +++ b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/WigWagTileEntity.java @@ -0,0 +1,105 @@ +package com.clussmanproductions.trafficcontrol.tileentity; + +import com.clussmanproductions.trafficcontrol.ModBlocks; +import com.clussmanproductions.trafficcontrol.blocks.BlockWigWag; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ITickable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class WigWagTileEntity extends TileEntity implements ITickable { + private int rotation = 0; + private AnimationMode mode = AnimationMode.SwingPositive; + @Override + public void readFromNBT(NBTTagCompound compound) { + // TODO Auto-generated method stub + super.readFromNBT(compound); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound compound) { + // TODO Auto-generated method stub + return super.writeToNBT(compound); + } + + @Override + public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) { + if (newSate.getBlock() == ModBlocks.wig_wag) + { + return false; + } + + return true; + } + + @Override + public void update() { + if (!world.isRemote) + { + return; + } + + IBlockState state = world.getBlockState(getPos()); + if (state.getBlock() != ModBlocks.wig_wag) + { + return; + } + + boolean active = state.getValue(BlockWigWag.ACTIVE); + + if (!active && rotation != 0) + { + if (rotation < 0 && mode != AnimationMode.SwingPositive) + { + mode = AnimationMode.SwingPositive; + } + + if (rotation > 0 && mode != AnimationMode.SwingNegative) + { + mode = AnimationMode.SwingNegative; + } + } + + if (!active && rotation == 0) + { + return; + } + + if (active) + { + if (rotation > 45) + { + mode = AnimationMode.SwingNegative; + } + + if (rotation < -45) + { + mode = AnimationMode.SwingPositive; + } + } + + switch(mode) + { + case SwingNegative: + rotation -= 3; + break; + case SwingPositive: + rotation += 3; + break; + } + } + + private enum AnimationMode + { + SwingNegative, + SwingPositive + } + + public int getRotation() + { + return rotation; + } +} diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RenderBoxHelper.java b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RenderBoxHelper.java new file mode 100644 index 00000000..52da5422 --- /dev/null +++ b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RenderBoxHelper.java @@ -0,0 +1,188 @@ +package com.clussmanproductions.trafficcontrol.tileentity.render; + +import java.util.function.Consumer; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.ResourceLocation; + +public class RenderBoxHelper { + public static class Box + { + private double x; + private double y; + private double z; + private double width; + private double height; + private double depth; + private TextureInfoCollection textureInfoCollection; + + public Box(double x, double y, double z, double width, double height, double depth, TextureInfoCollection textureInfoCollection) + { + this.x = x; + this.y = y; + this.z = z; + this.width = width; + this.height = height; + this.depth = depth; + this.textureInfoCollection = textureInfoCollection; + } + + public void render(BufferBuilder builder, Consumer bindTexture) + { + double[][] vertexPoints = getVertexPoints(); + + int index = 0; + int count = 0; + ResourceLocation lastResourceLocation = null; + for(double[] vertexPoint : vertexPoints) + { + TextureInfo info = getTextureInfo(index); + if (info.texture != lastResourceLocation) + { + lastResourceLocation = info.texture; + bindTexture.accept(lastResourceLocation); + } + + double uvX = 0; + double uvY = 0; + + switch(count) + { + case 0: + uvX = info.getConvertedEndX(); + uvY = info.getConvertedEndY(); + break; + case 1: + uvX = info.getConvertedEndX(); + uvY = info.getConvertedStartY(); + break; + case 2: + uvX = info.getConvertedStartX(); + uvY = info.getConvertedStartY(); + break; + case 3: + uvX = info.getConvertedStartX(); + uvY = info.getConvertedEndY(); + break; + } + + builder.pos(vertexPoint[0], vertexPoint[1], vertexPoint[2]).tex(uvX, uvY).endVertex(); + count++; + + if (count >= 4) + { + index++; + count = 0; + } + } + } + + private TextureInfo getTextureInfo(int count) + { + switch(count) + { + case 0: + return textureInfoCollection.northFace; + case 1: + return textureInfoCollection.upFace; + case 2: + return textureInfoCollection.southFace; + case 3: + return textureInfoCollection.downFace; + case 4: + return textureInfoCollection.eastFace; + case 5: + return textureInfoCollection.westFace; + default: + return null; + } + } + + private double[][] getVertexPoints() + { + double convertedX = x / 16; + double convertedY = y / 16; + double convertedZ = z / 16; + double convertedWidth = width / 16; + double convertedHeight = height / 16; + double convertedDepth = depth / 16; + return new double[][] { + {convertedX + convertedWidth, convertedY, convertedZ}, + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, + {convertedX, convertedY + convertedHeight, convertedZ}, + {convertedX, convertedY, convertedZ}, // Front + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX, convertedY + convertedHeight, convertedZ}, // Up + {convertedX, convertedY, convertedZ + convertedDepth}, + {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, // Back + {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, + {convertedX + convertedWidth, convertedY, convertedZ}, + {convertedX, convertedY, convertedZ}, + {convertedX, convertedY, convertedZ + convertedDepth}, // Down + {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, + {convertedX + convertedWidth, convertedY, convertedZ}, // Right + {convertedX, convertedY, convertedZ}, + {convertedX, convertedY + convertedHeight, convertedZ}, + {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, + {convertedX, convertedY, convertedZ + convertedDepth} // Left + }; + } + } + + public static class TextureInfoCollection + { + TextureInfo southFace; + TextureInfo upFace; + TextureInfo northFace; + TextureInfo downFace; + TextureInfo eastFace; + TextureInfo westFace; + + public TextureInfoCollection(TextureInfo southFace, TextureInfo upFace, TextureInfo northFace, TextureInfo downFace, TextureInfo eastFace, TextureInfo westFace) + { + this.southFace = southFace; + this.upFace = upFace; + this.northFace = northFace; + this.downFace = downFace; + this.eastFace = eastFace; + this.westFace = westFace; + } + + public TextureInfo getSouthFace() { return southFace; } + public TextureInfo getUpFace() { return upFace; } + public TextureInfo getNorthFace() { return northFace; } + public TextureInfo getDownFace() { return downFace; } + public TextureInfo getEastFace() { return eastFace; } + public TextureInfo getWestFace() { return westFace; } + } + + public static class TextureInfo + { + ResourceLocation texture; + double startX; + double startY; + double endX; + double endY; + + public TextureInfo(ResourceLocation texture, double startX, double startY, double endX, double endY) + { + this.texture = texture; + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + public double getConvertedStartX() { return startX / 16; } + public double getConvertedStartY() { return startY / 16; } + public double getConvertedEndX() { return endX / 16; } + public double getConvertedEndY() { return endY / 16; } + } + +} diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererCrossingGateGate.java b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererCrossingGateGate.java index 3da7b64c..862cd9cf 100644 --- a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererCrossingGateGate.java +++ b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererCrossingGateGate.java @@ -4,11 +4,12 @@ import com.clussmanproductions.trafficcontrol.ModTrafficControl; import com.clussmanproductions.trafficcontrol.tileentity.CrossingGateGateTileEntity; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.Box; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.TextureInfo; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.TextureInfoCollection; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -52,7 +53,7 @@ private void renderWeightVerticies(BufferBuilder builder) new TextureInfo(generic, 0, 0, 1, 4), new TextureInfo(generic, 0, 0, 1, 4)); Box weightBox = new Box(-4, -2, 4, 12, 4, -1, collection); - weightBox.render(builder); + weightBox.render(builder, (rl) -> bindTexture(rl)); } private void renderGateVerticies(BufferBuilder builder) @@ -66,185 +67,6 @@ private void renderGateVerticies(BufferBuilder builder) new TextureInfo(gate, 0, 2, 3, 4), new TextureInfo(gate, 0, 2, 3, 4)); Box gateBox = new Box(-76, -1, 4, 72, 2, -1, collection); - gateBox.render(builder); - } - - private class Box - { - private double x; - private double y; - private double z; - private double width; - private double height; - private double depth; - private TextureInfoCollection textureInfoCollection; - - public Box(double x, double y, double z, double width, double height, double depth, TextureInfoCollection textureInfoCollection) - { - this.x = x; - this.y = y; - this.z = z; - this.width = width; - this.height = height; - this.depth = depth; - this.textureInfoCollection = textureInfoCollection; - } - - public void render(BufferBuilder builder) - { - double[][] vertexPoints = getVertexPoints(); - - int index = 0; - int count = 0; - ResourceLocation lastResourceLocation = null; - for(double[] vertexPoint : vertexPoints) - { - TextureInfo info = getTextureInfo(index); - if (info.texture != lastResourceLocation) - { - lastResourceLocation = info.texture; - bindTexture(lastResourceLocation); - } - - double uvX = 0; - double uvY = 0; - - switch(count) - { - case 0: - uvX = info.getConvertedEndX(); - uvY = info.getConvertedEndY(); - break; - case 1: - uvX = info.getConvertedEndX(); - uvY = info.getConvertedStartY(); - break; - case 2: - uvX = info.getConvertedStartX(); - uvY = info.getConvertedStartY(); - break; - case 3: - uvX = info.getConvertedStartX(); - uvY = info.getConvertedEndY(); - break; - } - - builder.pos(vertexPoint[0], vertexPoint[1], vertexPoint[2]).tex(uvX, uvY).endVertex(); - count++; - - if (count >= 4) - { - index++; - count = 0; - } - } - } - - private TextureInfo getTextureInfo(int count) - { - switch(count) - { - case 0: - return textureInfoCollection.northFace; - case 1: - return textureInfoCollection.upFace; - case 2: - return textureInfoCollection.southFace; - case 3: - return textureInfoCollection.downFace; - case 4: - return textureInfoCollection.eastFace; - case 5: - return textureInfoCollection.westFace; - default: - return null; - } - } - - private double[][] getVertexPoints() - { - double convertedX = x / 16; - double convertedY = y / 16; - double convertedZ = z / 16; - double convertedWidth = width / 16; - double convertedHeight = height / 16; - double convertedDepth = depth / 16; - return new double[][] { - {convertedX + convertedWidth, convertedY, convertedZ}, - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, - {convertedX, convertedY + convertedHeight, convertedZ}, - {convertedX, convertedY, convertedZ}, // Front - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX, convertedY + convertedHeight, convertedZ}, // Up - {convertedX, convertedY, convertedZ + convertedDepth}, - {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, // Back - {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, - {convertedX + convertedWidth, convertedY, convertedZ}, - {convertedX, convertedY, convertedZ}, - {convertedX, convertedY, convertedZ + convertedDepth}, // Down - {convertedX + convertedWidth, convertedY, convertedZ + convertedDepth}, - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX + convertedWidth, convertedY + convertedHeight, convertedZ}, - {convertedX + convertedWidth, convertedY, convertedZ}, // Right - {convertedX, convertedY, convertedZ}, - {convertedX, convertedY + convertedHeight, convertedZ}, - {convertedX, convertedY + convertedHeight, convertedZ + convertedDepth}, - {convertedX, convertedY, convertedZ + convertedDepth} // Left - }; - } - } - - private class TextureInfoCollection - { - TextureInfo southFace; - TextureInfo upFace; - TextureInfo northFace; - TextureInfo downFace; - TextureInfo eastFace; - TextureInfo westFace; - - public TextureInfoCollection(TextureInfo southFace, TextureInfo upFace, TextureInfo northFace, TextureInfo downFace, TextureInfo eastFace, TextureInfo westFace) - { - this.southFace = southFace; - this.upFace = upFace; - this.northFace = northFace; - this.downFace = downFace; - this.eastFace = eastFace; - this.westFace = westFace; - } - - public TextureInfo getSouthFace() { return southFace; } - public TextureInfo getUpFace() { return upFace; } - public TextureInfo getNorthFace() { return northFace; } - public TextureInfo getDownFace() { return downFace; } - public TextureInfo getEastFace() { return eastFace; } - public TextureInfo getWestFace() { return westFace; } - } - - private class TextureInfo - { - ResourceLocation texture; - double startX; - double startY; - double endX; - double endY; - - public TextureInfo(ResourceLocation texture, double startX, double startY, double endX, double endY) - { - this.texture = texture; - this.startX = startX; - this.startY = startY; - this.endX = endX; - this.endY = endY; - } - - public double getConvertedStartX() { return startX / 16; } - public double getConvertedStartY() { return startY / 16; } - public double getConvertedEndX() { return endX / 16; } - public double getConvertedEndY() { return endY / 16; } + gateBox.render(builder, (rl) -> bindTexture(rl)); } } diff --git a/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererWigWag.java b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererWigWag.java new file mode 100644 index 00000000..ba2f75ae --- /dev/null +++ b/src/main/java/com/clussmanproductions/trafficcontrol/tileentity/render/RendererWigWag.java @@ -0,0 +1,117 @@ +package com.clussmanproductions.trafficcontrol.tileentity.render; + +import org.lwjgl.opengl.GL11; + +import com.clussmanproductions.trafficcontrol.ModBlocks; +import com.clussmanproductions.trafficcontrol.ModTrafficControl; +import com.clussmanproductions.trafficcontrol.blocks.BlockWigWag; +import com.clussmanproductions.trafficcontrol.tileentity.WigWagTileEntity; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.Box; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.TextureInfo; +import com.clussmanproductions.trafficcontrol.tileentity.render.RenderBoxHelper.TextureInfoCollection; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; + +public class RendererWigWag extends TileEntitySpecialRenderer { + + ResourceLocation genericTexture = new ResourceLocation(ModTrafficControl.MODID + ":textures/blocks/generic.png"); + ResourceLocation blackTexture = new ResourceLocation(ModTrafficControl.MODID + ":textures/blocks/black.png"); + ResourceLocation redTexture = new ResourceLocation(ModTrafficControl.MODID + ":textures/blocks/red.png"); + @Override + public void render(WigWagTileEntity te, double x, double y, double z, float partialTicks, int destroyStage, + float alpha) { + IBlockState state = te.getWorld().getBlockState(te.getPos()); + + if (state.getBlock() != ModBlocks.wig_wag) + { + return; + } + + GlStateManager.pushMatrix(); + GlStateManager.translate(x + 0.5, y, z + 0.5); + int facingIndex = state.getValue(BlockWigWag.FACING).getHorizontalIndex() + 2; + if (facingIndex > 3) + facingIndex -= 4; + + int yRotationAmount = facingIndex * 90 * -1; + GlStateManager.rotate(yRotationAmount, 0, 1, 0); + GlStateManager.translate(-0.5, 0, -0.5); + + GlStateManager.translate(bcwc(-3.5), bcwc(16.5), bcwc(7.5)); + GlStateManager.rotate(te.getRotation(), 0, 0, 1); + GlStateManager.translate(bcwc(3.5), bcwc(-16.5), bcwc(-7.5)); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder builder = tessellator.getBuffer(); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + + int bright = te.getWorld().getCombinedLight(te.getPos(), 0); + int brightX = bright % 65536; + int brightY = bright / 65536; + + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightX, brightY); + + renderSuspendedPole(builder); + tessellator.draw(); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + renderBacking(builder); + tessellator.draw(); + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); + renderLamp(builder, state.getValue(BlockWigWag.ACTIVE)); + tessellator.draw(); + + GlStateManager.popMatrix(); + } + + private void renderSuspendedPole(BufferBuilder builder) + { + GlStateManager.translate(bcwc(-3.5), bcwc(10.5), bcwc(7.5)); + Box box = new Box(0, 0, 1, 1, 6.5, -1, new TextureInfoCollection(new TextureInfo(genericTexture, 0, 0, 1, 6), + new TextureInfo(genericTexture, 0, 0, 1, 1), + new TextureInfo(genericTexture, 0, 0, 1, 6), + new TextureInfo(genericTexture, 0, 0, 1, 1), + new TextureInfo(genericTexture, 0, 0, 1, 6), + new TextureInfo(genericTexture, 0, 0, 1, 6))); + + box.render(builder, (rl) -> bindTexture(rl)); + } + + private void renderBacking(BufferBuilder builder) + { + GlStateManager.translate(bcwc(-2.5), bcwc(-6), 0); + Box box = new Box(0, 0, 1, 6, 6, -1, new TextureInfoCollection(new TextureInfo(blackTexture, 0, 0, 6, 6), + new TextureInfo(blackTexture, 0, 0, 6, 1), + new TextureInfo(blackTexture, 0, 0, 6, 6), + new TextureInfo(blackTexture, 0, 0, 6, 1), + new TextureInfo(blackTexture, 0, 0, 1, 6), + new TextureInfo(blackTexture, 0, 0, 1, 6))); + + box.render(builder, (rl) -> bindTexture(rl)); + } + + private void renderLamp(BufferBuilder builder, boolean active) + { + GlStateManager.translate(bcwc(1.5), bcwc(1.5), bcwc(1)); + Box box = new Box(0, 0, 1, 3, 3, -1, new TextureInfoCollection(new TextureInfo(active ? redTexture : blackTexture, 0, 0, 6, 6), + new TextureInfo(active ? redTexture : blackTexture, 0, 0, 6, 1), + new TextureInfo(active ? redTexture : blackTexture, 0, 0, 6, 6), + new TextureInfo(active ? redTexture : blackTexture, 0, 0, 6, 1), + new TextureInfo(active ? redTexture : blackTexture, 0, 0, 1, 6), + new TextureInfo(active ? redTexture : blackTexture, 0, 0, 1, 6))); + + box.render(builder, (rl) -> bindTexture(rl)); + } + + // Block Coordinate -> World Coordinate + private double bcwc(double blockCoord) + { + return blockCoord / 16; + } +} diff --git a/src/main/resources/assets/trafficcontrol/blockstates/wig_wag.json b/src/main/resources/assets/trafficcontrol/blockstates/wig_wag.json new file mode 100644 index 00000000..ee9ec080 --- /dev/null +++ b/src/main/resources/assets/trafficcontrol/blockstates/wig_wag.json @@ -0,0 +1,91 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "trafficcontrol:wig_wag" + }, + "variants": { + "active=false,facing=north": + [{ + "textures": + { + "lamp": "trafficcontrol:blocks/black" + } + }], + "active=false,facing=west": + { + "y": 270, + "textures": + { + "lamp": "trafficcontrol:blocks/black" + } + }, + "active=false,facing=south": + { + "y": 180, + "textures": + { + "lamp": "trafficcontrol:blocks/black" + } + }, + "active=false,facing=east": + { + "y": 90, + "textures": + { + "lamp": "trafficcontrol:blocks/black" + } + }, + "active=true,facing=north": + [{ + "textures": + { + "lamp": "trafficcontrol:blocks/red" + } + }], + "active=true,facing=west": + { + "y": 270, + "textures": + { + "lamp": "trafficcontrol:blocks/red" + } + }, + "active=true,facing=south": + { + "y": 180, + "textures": + { + "lamp": "trafficcontrol:blocks/red" + } + }, + "active=true,facing=east": + { + "y": 90, + "textures": + { + "lamp": "trafficcontrol:blocks/red" + } + }, + "inventory": + { + "model": "trafficcontrol:wig_wag", + "transform": + { + "firstperson": + { + "scale": 0.5 + }, + "firstperson_lefthand": + { + "scale": 0.5 + }, + "gui": + { + "scale": [0.75, 0.8, 1], + "translation": [0.25, -0.1, 0] + } + } + }, + "normal": [{}] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/trafficcontrol/lang/en_us.lang b/src/main/resources/assets/trafficcontrol/lang/en_us.lang index e5fd9516..81c82bdf 100644 --- a/src/main/resources/assets/trafficcontrol/lang/en_us.lang +++ b/src/main/resources/assets/trafficcontrol/lang/en_us.lang @@ -16,6 +16,7 @@ tile.trafficcontrol.channelizer.name=Channelizer tile.trafficcontrol.drum.name=Drum tile.trafficcontrol.street_light_single.name=Street Light (Single) tile.trafficcontrol.street_light_double.name=Street Light (Double) +tile.trafficcontrol.wig_wag.name=Wig Wag #items item.trafficcontrol.crossing_relay_box.name=Crossing Gate Relay item.trafficcontrol.crossing_relay_tuner.name=Crossing Gate Tuner diff --git a/src/main/resources/assets/trafficcontrol/models/block/wig_wag.json b/src/main/resources/assets/trafficcontrol/models/block/wig_wag.json new file mode 100644 index 00000000..ebc5674b --- /dev/null +++ b/src/main/resources/assets/trafficcontrol/models/block/wig_wag.json @@ -0,0 +1,90 @@ +{ + "__comment": "Model generated using MrCrayfish's Model Creator (http://mrcrayfish.com/modelcreator/)", + "textures": { + "0": "trafficcontrol:blocks/generic", + "1": "trafficcontrol:blocks/bell", + "particle": "trafficcontrol:blocks/generic" + }, + "elements": [ + { + "name": "Pole", + "from": [ 7.0, 0.0, 7.0 ], + "to": [ 9.0, 16.0, 9.0 ], + "faces": { + "north": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 16.0 ] }, + "east": { "texture": "#0", "uv": [ 2.0, 0.0, 4.0, 16.0 ] }, + "south": { "texture": "#0", "uv": [ 4.0, 0.0, 6.0, 16.0 ] }, + "west": { "texture": "#0", "uv": [ 6.0, 0.0, 8.0, 16.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 2.0, 2.0 ] } + } + }, + { + "name": "N Support", + "from": [ 7.0, 8.0, 6.100000001490116 ], + "to": [ 8.0, 19.0, 7.0 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "z", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 11.0 ] }, + "east": { "texture": "#0", "uv": [ 0.0, 0.0, 0.8999999985098839, 11.0 ] }, + "south": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 11.0 ] }, + "west": { "texture": "#0", "uv": [ 0.0, 0.0, 0.8999999985098839, 11.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 0.8999999985098839 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 0.8999999985098839 ] } + } + }, + { + "name": "S Support", + "from": [ 7.0, 8.0, 8.899999998509884 ], + "to": [ 8.0, 19.0, 9.799999997019768 ], + "rotation": { "origin": [ 8.0, 8.0, 8.0 ], "axis": "z", "angle": 45.0 }, + "faces": { + "north": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 11.0 ] }, + "east": { "texture": "#0", "uv": [ 0.0, 0.0, 0.8999999985098839, 11.0 ] }, + "south": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 11.0 ] }, + "west": { "texture": "#0", "uv": [ 0.0, 0.0, 0.8999999985098839, 11.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 0.8999999985098839 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 0.8999999985098839 ] } + } + }, + { + "name": "N Upper Support", + "from": [ -5.0, 15.0, 6.0 ], + "to": [ 9.0, 16.0, 7.0 ], + "faces": { + "north": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "east": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "south": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "west": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] } + } + }, + { + "name": "S Upper Support", + "from": [ -5.0, 15.0, 9.0 ], + "to": [ 9.0, 16.0, 10.0 ], + "faces": { + "north": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "east": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "south": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "west": { "texture": "#0", "uv": [ 0.0, 0.0, 1.0, 1.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 14.0, 1.0 ] } + } + }, + { + "name": "Motor", + "from": [ -5.0, 16.0, 6.0 ], + "to": [ -1.0, 20.0, 10.0 ], + "faces": { + "north": { "texture": "#1", "uv": [ 0.0, 0.0, 8.0, 8.0 ] }, + "east": { "texture": "#0", "uv": [ 0.0, 0.0, 4.0, 4.0 ] }, + "south": { "texture": "#1", "uv": [ 0.0, 0.0, 8.0, 8.0 ] }, + "west": { "texture": "#0", "uv": [ 0.0, 0.0, 4.0, 4.0 ] }, + "up": { "texture": "#0", "uv": [ 0.0, 0.0, 4.0, 4.0 ] }, + "down": { "texture": "#0", "uv": [ 0.0, 0.0, 4.0, 4.0 ] } + } + } + ] +} \ No newline at end of file