diff --git a/.gitignore b/.gitignore index f87430f3..2f8772de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,12 @@ /build/ /bin/ /download/ -/src/com/xcompwiz/ \ No newline at end of file +#Remove OS generated garbage +*/.DS_Store +.DS_Store +.DS_Store? +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db \ No newline at end of file diff --git a/resources/assets/tinker/lang/en_US.lang b/resources/assets/tinker/lang/en_US.lang index 746bd3c3..46d37ef2 100644 --- a/resources/assets/tinker/lang/en_US.lang +++ b/resources/assets/tinker/lang/en_US.lang @@ -100,6 +100,9 @@ block.fancybrick.stone.name=Fancy Stone Brick tile.rail.wood.name=Wooden Rail +tile.signalbus.name=Signal Bus +tile.signalterminal.name=Signal Terminal + tile.cloth.white.slab.name=Wool Slab tile.cloth.orange.slab.name=Orange Wool Slab tile.cloth.magenta.slab.name=Magenta Wool Slab @@ -125,7 +128,10 @@ item.oreberry.aluminum.name=Aluminum Oreberry item.oreberry.essence.name=Concentrated Essence Berry item.goldenhead.name=Golden Head -item.tconstruct.titleicon.name=Spawn +item.tconstruct.titleicon.name=Spawn + +item.spoolwire.name=Spool of Wire +item.lengthwire.name=Length of Wire item.InfiTool.Pickaxe.name=Pickaxe item.InfiTool.Shovel.name=Shovel diff --git a/resources/assets/tinker/textures/blocks/signalbus.png b/resources/assets/tinker/textures/blocks/signalbus.png new file mode 100644 index 00000000..4d9403a8 Binary files /dev/null and b/resources/assets/tinker/textures/blocks/signalbus.png differ diff --git a/resources/assets/tinker/textures/items/logic/lengthwire.png b/resources/assets/tinker/textures/items/logic/lengthwire.png new file mode 100644 index 00000000..2dab64df Binary files /dev/null and b/resources/assets/tinker/textures/items/logic/lengthwire.png differ diff --git a/resources/assets/tinker/textures/items/logic/spoolwire.png b/resources/assets/tinker/textures/items/logic/spoolwire.png new file mode 100644 index 00000000..5b86b6cf Binary files /dev/null and b/resources/assets/tinker/textures/items/logic/spoolwire.png differ diff --git a/src/tconstruct/TConstruct.java b/src/tconstruct/TConstruct.java index ca5bf540..596ea236 100644 --- a/src/tconstruct/TConstruct.java +++ b/src/tconstruct/TConstruct.java @@ -13,10 +13,13 @@ import java.util.logging.Logger; import net.minecraft.crash.CallableMinecraftVersion; import net.minecraft.world.gen.structure.MapGenStructureIO; import net.minecraftforge.common.MinecraftForge; +import tconstruct.blocks.SignalBus; +import tconstruct.client.SignalTetherWorldOverlayRenderer; import tconstruct.client.event.EventCloakRender; import tconstruct.common.*; import tconstruct.library.TConstructRegistry; import tconstruct.library.crafting.*; +import tconstruct.library.multiblock.MultiblockEventHandler; import tconstruct.library.util.TabTools; import tconstruct.util.*; import tconstruct.util.config.*; @@ -95,6 +98,8 @@ public class TConstruct proxy.addNames(); proxy.readManuals(); proxy.registerKeys(); + + MinecraftForge.EVENT_BUS.register(new MultiblockEventHandler()); GameRegistry.registerWorldGenerator(new TBaseWorldGenerator()); MinecraftForge.TERRAIN_GEN_BUS.register(new TerrainGenEventHandler()); @@ -135,6 +140,8 @@ public class TConstruct if (event.getSide() == Side.CLIENT) { MinecraftForge.EVENT_BUS.register(new EventCloakRender()); + MinecraftForge.EVENT_BUS.register(TConstruct.instance.content.signalBus); + MinecraftForge.EVENT_BUS.register(new SignalTetherWorldOverlayRenderer()); } content.intermodCommunication(); diff --git a/src/tconstruct/blocks/SignalBus.java b/src/tconstruct/blocks/SignalBus.java new file mode 100644 index 00000000..992a74d0 --- /dev/null +++ b/src/tconstruct/blocks/SignalBus.java @@ -0,0 +1,601 @@ +package tconstruct.blocks; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.naming.Context; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import tconstruct.TConstruct; +import tconstruct.blocks.SignalTerminal.TerminalGeometry; +import tconstruct.blocks.logic.CastingChannelLogic; +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.blocks.logic.SignalTerminalLogic; +import tconstruct.client.block.BlockRenderCastingChannel; +import tconstruct.client.block.SignalBusRender; +import tconstruct.items.blocks.SignalBusItem; +import tconstruct.library.TConstructRegistry; +import tconstruct.library.multiblock.IMultiblockMember; +import tconstruct.library.multiblock.MultiblockMasterBaseLogic; +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChatMessageComponent; +import net.minecraft.util.EnumMovingObjectType; +import net.minecraft.util.Icon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.ForgeSubscribe; + +public class SignalBus extends Block implements ITileEntityProvider { + public static class Geometry { + public static double cable_width_min = 0.375D; + public static double cable_width_max = 1 - cable_width_min; + public static double cable_low_height = 0.2D; + public static double cable_low_offset = 0.0D; + + public static double cable_high_height = 1.0D; + public static double cable_high_offset = 1 - cable_low_height; + + public static double cable_extend_min = 0.0D; + public static double cable_extend_max = 1.0D; + + public static double cable_corner_min = cable_high_offset - 1; + public static double cable_corner_max = cable_low_height + 1; + + public static double zfight = 0.0000001D; + } + + public static int HITBOXES = 6; + + public Icon[] icons; + public String[] textureNames = new String[] { "signalbus" }; + + public SignalBus(int par1) { + super(par1, Material.circuits); + this.setHardness(0.1F); + this.setResistance(1); + this.setStepSound(soundMetalFootstep); + setCreativeTab(TConstructRegistry.blockTab); + } + + @Override + public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) { + if (par1World.isRemote) { return false; } + TileEntity te = par1World.getBlockTileEntity(par2, par3, par4); + if (te != null && te instanceof SignalBusLogic) { + TConstruct.logger.info(((SignalBusLogic)te).debugString()); + if (((SignalBusLogic)te).getMultiblockMaster() != null) { + TConstruct.logger.info((((SignalBusLogic)te).getMultiblockMaster().debugString())); + } + } + + return false; + } + + @Override + public void onNeighborTileChange(World world, int x, int y, int z, int tileX, int tileY, int tileZ) { + TileEntity te = world.getBlockTileEntity(tileX, tileY, tileZ); + if (te instanceof SignalBusLogic) { + if (((SignalBusLogic)te).getMultiblockMaster() != null) { + ((SignalBusLogic)te).getMultiblockMaster().detachBlock((IMultiblockMember)te, false); + } + } + } + + @Override + public void onBlockAdded(World world, int x, int y, int z) { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te != null && te instanceof SignalBusLogic) { + ((SignalBusLogic)te).onBlockAdded(world, x, y, z); + } + } + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon (int side, int metadata) + { + return icons[0]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons (IconRegister iconRegister) + { + this.icons = new Icon[textureNames.length]; + + for (int i = 0; i < this.icons.length; ++i) + { + this.icons[i] = iconRegister.registerIcon("tinker:" + textureNames[i]); + } + } + +// @Override +// public void setBlockBoundsBasedOnState (IBlockAccess world, int x, int y, int z) +// { +// SignalBusLogic tile = (SignalBusLogic) world.getBlockTileEntity(x, y, z); +// if (!(tile instanceof SignalBusLogic)) return; +// float minX = 0.375F; +// float maxX = 0.625F; +// float minZ = 0.375F; +// float maxZ = 0.625F; +// if (tile.isConnected(ForgeDirection.DOWN, ForgeDirection.NORTH)) +// minZ = 0F; +// if (tile.isConnected(ForgeDirection.DOWN, ForgeDirection.SOUTH)) +// maxZ = 1F; +// if (tile.isConnected(ForgeDirection.DOWN, ForgeDirection.WEST)) +// minX = 0F; +// if (tile.isConnected(ForgeDirection.DOWN, ForgeDirection.EAST)) +// maxX = 1F; +// +// //this.setBlockBounds(minX, 0.0F, minZ, maxX, 0.2F, maxZ); +// this.setBlockBounds(0, 0, 0, 1, 1, 1); +// } + + @Override + public boolean renderAsNormalBlock () + { + return false; + } + + @Override + public boolean isOpaqueCube () + { + return false; + } + + @Override + public int getRenderType () + { + return SignalBusRender.renderID; + } + + public void addCollisionBoxesToList (World world, int x, int y, int z, AxisAlignedBB collisionTest, List collisionBoxList, Entity entity) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalBusLogic) + { + for (AxisAlignedBB aabb : getBoxes((SignalBusLogic) te)) + { + if (aabb == null) + { + continue; + } + + aabb = AxisAlignedBB.getBoundingBox(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + aabb.minX += x; + aabb.minY += y; + aabb.minZ += z; + aabb.maxX += x; + aabb.maxY += y; + aabb.maxZ += z; + + if (collisionTest.intersectsWith(aabb)) + { + collisionBoxList.add(aabb); + } + } + } + else + { + super.addCollisionBoxesToList(world, x, y, z, collisionTest, collisionBoxList, entity); + } + } + + @Override + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered (IBlockAccess par1iBlockAccess, int par2, int par3, int par4, int par5) + { + return true; + } + + @Override + public MovingObjectPosition collisionRayTrace (World world, int x, int y, int z, Vec3 start, Vec3 end) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalBusLogic) + { + MovingObjectPosition closest = null; + AxisAlignedBB[] boxes = getBoxes((SignalBusLogic)te); + + double closestCalc = Double.MAX_VALUE; + double hitDistance = 0D; + + for (int i = 0; i < boxes.length; i++) + { + if (boxes[i] == null) + { + continue; + } + this.setBlockBounds((float)boxes[i].minX, (float)boxes[i].minY, (float)boxes[i].minZ, (float)boxes[i].maxX, (float)boxes[i].maxY, (float)boxes[i].maxZ); + MovingObjectPosition hit = super.collisionRayTrace(world, x, y, z, start, end); + if (hit != null) + { + hitDistance = start.distanceTo(hit.hitVec); + if (hitDistance < closestCalc) + { + closestCalc = hitDistance; + closest = hit; + } + } + } + return closest; + } + + return null; + } + + private static AxisAlignedBB[] getBoxes (SignalBusLogic logic) + { + boolean placed[] = logic.placedSides(); + boolean connected[]; + boolean corners[]; + boolean renderDir[]; + + AxisAlignedBB[] parts = new AxisAlignedBB[HITBOXES]; + + double minX; + double minY; + double minZ; + double maxX; + double maxY; + double maxZ; + boolean didRender = false; + + if (placed[ForgeDirection.DOWN.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.DOWN); + corners = logic.getRenderCorners(ForgeDirection.DOWN); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_low_offset; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_low_height; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + parts[0] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (placed[ForgeDirection.UP.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.UP); + corners = logic.getRenderCorners(ForgeDirection.UP); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_high_offset; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_high_height; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + parts[1] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (placed[ForgeDirection.NORTH.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.NORTH); + corners = logic.getRenderCorners(ForgeDirection.NORTH); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_low_offset; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_low_height; + + + parts[2] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (placed[ForgeDirection.SOUTH.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.SOUTH); + corners = logic.getRenderCorners(ForgeDirection.SOUTH); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_high_offset; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_high_height; + + parts[3] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (placed[ForgeDirection.WEST.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.WEST); + corners = logic.getRenderCorners(ForgeDirection.WEST); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = Geometry.cable_low_offset; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_low_height; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + parts[4] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (placed[ForgeDirection.EAST.ordinal()]) + { + connected = logic.connectedSides(ForgeDirection.EAST); + corners = logic.getRenderCorners(ForgeDirection.EAST); + renderDir = new boolean[] { + (connected[0] || placed[0] || corners[0]), + (connected[1] || placed[1] || corners[1]), + (connected[2] || placed[2] || corners[2]), + (connected[3] || placed[3] || corners[3]), + (connected[4] || placed[4] || corners[4]), + (connected[5] || placed[5] || corners[5]) + }; + minX = Geometry.cable_high_offset; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_high_height; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + parts[5] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + didRender = true; + } + if (!didRender) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_low_offset; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_low_height; + maxZ = Geometry.cable_width_max; + + parts[0] = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ); + } + + return parts; + } + + private static int closestClicked (EntityPlayer player, double reachDistance, SignalBusLogic terminal, AxisAlignedBB[] parts) + { + int closest = -1; + + Vec3 playerPosition = Vec3.createVectorHelper(player.posX - terminal.xCoord, player.posY - terminal.yCoord + player.getEyeHeight(), player.posZ - terminal.zCoord); + Vec3 playerLook = player.getLookVec(); + + Vec3 playerViewOffset = Vec3.createVectorHelper(playerPosition.xCoord + playerLook.xCoord * reachDistance, playerPosition.yCoord + playerLook.yCoord * reachDistance, playerPosition.zCoord + + playerLook.zCoord * reachDistance); + double closestCalc = Double.MAX_VALUE; + double hitDistance = 0D; + + for (int i = 0; i < parts.length; i++) + { + if (parts[i] == null) + { + continue; + } + MovingObjectPosition hit = parts[i].calculateIntercept(playerPosition, playerViewOffset); + if (hit != null) + { + hitDistance = playerPosition.distanceTo(hit.hitVec); + if (hitDistance < closestCalc) + { + closestCalc = hitDistance; + closest = i; + } + } + } + return closest; + } + @SideOnly(Side.CLIENT) + @ForgeSubscribe + public void onBlockHighlight (DrawBlockHighlightEvent event) + { + return; +// if (event.target.typeOfHit == EnumMovingObjectType.TILE && event.player.worldObj.getBlockId(event.target.blockX, event.target.blockY, event.target.blockZ) == this.blockID) +// { +// TileEntity te = event.player.worldObj.getBlockTileEntity(event.target.blockX, event.target.blockY, event.target.blockZ); +// if (!(te instanceof SignalBusLogic)) +// { +// return; +// } +// AxisAlignedBB[] boxes = getBoxes((SignalBusLogic)te); +// double reach = Minecraft.getMinecraft().playerController.getBlockReachDistance(); +// int hitbox = closestClicked(event.player, reach, (SignalBusLogic)te, boxes); +// +// if (hitbox > 0 && hitbox < HITBOXES) +// { +// float f1 = 0.002F; +// double d0 = event.player.lastTickPosX + (event.player.posX - event.player.lastTickPosX) * (double)event.partialTicks; +// double d1 = event.player.lastTickPosY + (event.player.posY - event.player.lastTickPosY) * (double)event.partialTicks; +// double d2 = event.player.lastTickPosZ + (event.player.posZ - event.player.lastTickPosZ) * (double)event.partialTicks; +// drawOutlinedBoundingBox(boxes[hitbox].expand((double)f1, (double)f1, (double)f1).getOffsetBoundingBox(-d0, -d1, -d2)); +// +// } +// event.setCanceled(true); +// } + + } + + /** + * Draws lines for the edges of the bounding box. + */ + private static void drawOutlinedBoundingBox(AxisAlignedBB par1AxisAlignedBB) + { + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawing(3); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.minY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.minY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.minY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.minY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.minY, par1AxisAlignedBB.minZ); + tessellator.draw(); + tessellator.startDrawing(3); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.minZ); + tessellator.draw(); + tessellator.startDrawing(1); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.minY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.minY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.minZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.minY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.maxX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.minY, par1AxisAlignedBB.maxZ); + tessellator.addVertex(par1AxisAlignedBB.minX, par1AxisAlignedBB.maxY, par1AxisAlignedBB.maxZ); + tessellator.draw(); + } + + @Override + public TileEntity createTileEntity(World world, int metadata) { + return new SignalBusLogic(); + } + + @Override + public TileEntity createNewTileEntity(World world) { + return new SignalBusLogic(); + } + + @Override + public ArrayList getBlockDropped (World world, int x, int y, int z, int metadata, int fortune) + { + return new ArrayList(); + } + + @Override + public void onBlockPlacedBy (World world, int x, int y, int z, EntityLivingBase entityLiving, ItemStack itemStack) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalBusLogic) + { + NBTTagCompound data = itemStack.stackTagCompound; + if (data != null && data.hasKey("connectedSide")) + { + ((SignalBusLogic) te).addPlacedSide(data.getInteger("connectedSide")); + itemStack.stackTagCompound = null; + } + } + } + + @Override + public void onNeighborBlockChange (World par1World, int par2, int par3, int par4, int par5) + { + super.onNeighborBlockChange(par1World, par2, par3, par4, par5); + + if (par5 == this.blockID) + { + return; + } + TileEntity te = par1World.getBlockTileEntity(par2, par3, par4); + if (te instanceof SignalBusLogic) + { + ((SignalBusLogic)te).forceNeighborCheck(); + } + } + + @Override + public void breakBlock (World world, int x, int y, int z, int id, int meta) + { + int dropBus, dropWire = 0; + float jumpX, jumpY, jumpZ; + ItemStack tempStack; + Random rand = new Random(); + + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalBusLogic) + { + dropBus = ((SignalBusLogic) te).getDroppedBuses(); + dropWire = ((SignalBusLogic) te).getDroppedWire(); + if (dropBus > 0) + { + tempStack = new ItemStack(TConstruct.instance.content.signalBus.blockID, dropBus, 0); + jumpX = rand.nextFloat() * 0.8F + 0.1F; + jumpY = rand.nextFloat() * 0.8F + 0.1F; + jumpZ = rand.nextFloat() * 0.8F + 0.1F; + + EntityItem entityitem = new EntityItem(world, (double) ((float) x + jumpX), (double) ((float) y + jumpY), (double) ((float) z + jumpZ), tempStack); + + float offset = 0.05F; + entityitem.motionX = (double) ((float) rand.nextGaussian() * offset); + entityitem.motionY = (double) ((float) rand.nextGaussian() * offset + 0.2F); + entityitem.motionZ = (double) ((float) rand.nextGaussian() * offset); + world.spawnEntityInWorld(entityitem); + } + if (dropWire > 0) + { + tempStack = new ItemStack(TConstruct.instance.content.lengthWire, dropWire); + jumpX = rand.nextFloat() * 0.8F + 0.1F; + jumpY = rand.nextFloat() * 0.8F + 0.1F; + jumpZ = rand.nextFloat() * 0.8F + 0.1F; + + EntityItem entityitem = new EntityItem(world, (double) ((float) x + jumpX), (double) ((float) y + jumpY), (double) ((float) z + jumpZ), tempStack); + + float offset = 0.05F; + entityitem.motionX = (double) ((float) rand.nextGaussian() * offset); + entityitem.motionY = (double) ((float) rand.nextGaussian() * offset + 0.2F); + entityitem.motionZ = (double) ((float) rand.nextGaussian() * offset); + world.spawnEntityInWorld(entityitem); + } + ((SignalBusLogic) te).notifyBreak(); + } + + super.breakBlock(world, x, y, z, id, meta); + } + +} diff --git a/src/tconstruct/blocks/SignalTerminal.java b/src/tconstruct/blocks/SignalTerminal.java new file mode 100644 index 00000000..99f5ac58 --- /dev/null +++ b/src/tconstruct/blocks/SignalTerminal.java @@ -0,0 +1,567 @@ +package tconstruct.blocks; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import codechicken.nei.api.IHighlightHandler; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +import tconstruct.TConstruct; +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.blocks.logic.SignalTerminalLogic; +import tconstruct.client.block.SignalBusRender; +import tconstruct.client.block.SignalTerminalRender; +import tconstruct.library.TConstructRegistry; +import net.minecraft.block.Block; +import net.minecraft.block.ITileEntityProvider; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.Direction; +import net.minecraft.util.EnumMovingObjectType; +import net.minecraft.util.Icon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.common.ForgeDirection.*; +import net.minecraftforge.event.ForgeSubscribe; + +public class SignalTerminal extends Block implements ITileEntityProvider +{ + + public static class TerminalGeometry + { + public static float plate_width_min = 0.25F; + public static float plate_width_max = 0.75F; + public static float plate_low_max = 0.15F; + public static float plate_high_max = 1.0F; + public static float plate_low_min = 0.0F; + public static float plate_high_min = 1 - plate_low_max; + public static float center_min = 0.375F; + public static float center_max = 0.625F; + public static float channel_width_min = 0.375F; + public static float channel_width_max = 0.625F; + public static float channel_low_max = center_min; + public static float channel_high_max = plate_high_min; + public static float channel_low_min = plate_low_max; + public static float channel_high_min = center_max; + } + + public static int HITBOXES = 13; + public static int[] sideBoxMapping = new int[] { -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; + + public Icon[] icons; + public Icon[] channelIcons; + public String[] textureNames = new String[] { "signalbus" }; + public String[] channelTextureNames = new String[] { "white", "orange", "magenta", "lightblue", "yellow", "lime", "pink", "gray", "lightgray", "cyan", "purple", "blue", "brown", "green", "red", + "black" }; + + public SignalTerminal(int par1) + { + super(par1, Material.circuits); + this.setHardness(0.1F); + this.setResistance(1); + this.setStepSound(soundMetalFootstep); + setCreativeTab(TConstructRegistry.blockTab); + } + + @Override + @SideOnly(Side.CLIENT) + public Icon getIcon (int side, int metadata) + { + return icons[0]; + } + + public Icon getChannelIcon (int channel) + { + if (channel < 0 || channel >= channelIcons.length) + { + return channelIcons[0]; + } + + return channelIcons[channel]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons (IconRegister iconRegister) + { + this.icons = new Icon[textureNames.length]; + + for (int i = 0; i < this.icons.length; ++i) + { + this.icons[i] = iconRegister.registerIcon("tinker:" + textureNames[i]); + } + + this.channelIcons = new Icon[channelTextureNames.length]; + + for (int i = 0; i < this.channelIcons.length; ++i) + { + this.channelIcons[i] = iconRegister.registerIcon("tinker:glass/stainedglass_" + channelTextureNames[i]); + } + } + + /** + * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been + * cleared to be reused) + */ + public AxisAlignedBB getCollisionBoundingBoxFromPool (World par1World, int par2, int par3, int par4) + { + return null; + } + + /** + * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two + * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block. + */ + public boolean isOpaqueCube () + { + return false; + } + + /** + * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc) + */ + public boolean renderAsNormalBlock () + { + return false; + } + + @Override + public boolean isBlockSolidOnSide (World world, int x, int y, int z, ForgeDirection side) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te != null && te instanceof SignalTerminalLogic) + { + if (((SignalTerminalLogic) te).getConnectedSides()[side.ordinal()] != -1) + { + return true; + } + } + return false; + } + + /** + * The type of render function that is called for this block + */ + @Override + public int getRenderType () + { + return SignalTerminalRender.renderID; + } + + /** + * How many world ticks before ticking + */ + public int tickRate (World par1World) + { + return 1; + } + + /** + * checks to see if you can place this block can be placed on that side of a block: BlockLever overrides + */ + public boolean canPlaceBlockOnSide (World world, int x, int y, int z, int side) + { + ForgeDirection dir = ForgeDirection.getOrientation(side); + return true || (dir == ForgeDirection.NORTH && world.isBlockSolidOnSide(x, y, z + 1, ForgeDirection.NORTH)) + || (dir == ForgeDirection.SOUTH && world.isBlockSolidOnSide(x, y, z - 1, ForgeDirection.SOUTH)) + || (dir == ForgeDirection.WEST && world.isBlockSolidOnSide(x + 1, y, z, ForgeDirection.WEST)) + || (dir == ForgeDirection.EAST && world.isBlockSolidOnSide(x - 1, y, z, ForgeDirection.EAST)) || (dir == ForgeDirection.UP && world.isBlockSolidOnSide(x, y - 1, z, ForgeDirection.UP)) + || (dir == ForgeDirection.DOWN && world.isBlockSolidOnSide(x, y + 1, z, ForgeDirection.DOWN)); + } + + /** + * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z + */ + public boolean canPlaceBlockAt (World world, int x, int y, int z) + { + return world.isBlockSolidOnSide(x - 1, y, z, ForgeDirection.EAST) || world.isBlockSolidOnSide(x + 1, y, z, ForgeDirection.WEST) || world.isBlockSolidOnSide(x, y, z - 1, ForgeDirection.SOUTH) + || world.isBlockSolidOnSide(x, y, z + 1, ForgeDirection.NORTH) || world.isBlockSolidOnSide(x, y - 1, z, ForgeDirection.UP) + || world.isBlockSolidOnSide(x, y + 1, z, ForgeDirection.DOWN); + } + + /** + * Updates the blocks bounds based on its current state. Args: world, x, y, z + */ + public void setBlockBoundsBasedOnState (IBlockAccess world, int x, int y, int z) + { + float minX = 1; + float minY = 1; + float minZ = 1; + float maxX = 0; + float maxY = 0; + float maxZ = 0; + + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + for (AxisAlignedBB aabb : getBoxes((SignalTerminalLogic) te)) + { + if (aabb == null) + { + continue; + } + + minX = Math.min(minX, (float) aabb.minX); + minY = Math.min(minY, (float) aabb.minY); + minZ = Math.min(minZ, (float) aabb.minZ); + maxX = Math.max(maxX, (float) aabb.maxX); + maxY = Math.max(maxY, (float) aabb.maxY); + maxZ = Math.max(maxZ, (float) aabb.maxZ); + } + + setBlockBounds(minX, minY, minZ, maxX, maxY, maxZ); + } + else + { + this.setBlockBounds(0.375F, 0.375F, 0.375F, 0.625F, 0.625F, 0.625F); + } + return; + } + + public void addCollisionBoxesToList (World world, int x, int y, int z, AxisAlignedBB collisionTest, List collisionBoxList, Entity entity) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + for (AxisAlignedBB aabb : getBoxes((SignalTerminalLogic) te)) + { + if (aabb == null) + { + continue; + } + + aabb = AxisAlignedBB.getBoundingBox(aabb.minX, aabb.minY, aabb.minZ, aabb.maxX, aabb.maxY, aabb.maxZ); + aabb.minX += x; + aabb.minY += y; + aabb.minZ += z; + aabb.maxX += x; + aabb.maxY += y; + aabb.maxZ += z; + + if (collisionTest.intersectsWith(aabb)) + { + collisionBoxList.add(aabb); + } + } + } + else + { + super.addCollisionBoxesToList(world, x, y, z, collisionTest, collisionBoxList, entity); + } + } + + /** + * Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube + * returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X, + * Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. + */ + public int isProvidingWeakPower (IBlockAccess world, int x, int y, int z, int localSide) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + return ((SignalTerminalLogic) te).isProvidingWeakPower(localSide); + } + + return 0; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered (IBlockAccess par1iBlockAccess, int par2, int par3, int par4, int par5) + { + return true; + } + + /** + * Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z, + * side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block. + */ + public int isProvidingStrongPower (IBlockAccess world, int x, int y, int z, int localSide) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + return ((SignalTerminalLogic) te).isProvidingStrongPower(localSide); + } + + return 0; + } + + @Override + public boolean shouldCheckWeakPower (World world, int x, int y, int z, int side) + { + return true; + } + + /** + * Can this block provide power. Only wire currently seems to have this change based on its state. + */ + public boolean canProvidePower () + { + return true; + } + + @Override + public TileEntity createNewTileEntity (World world) + { + return new SignalTerminalLogic(); + } + + @Override + public void onNeighborBlockChange (World world, int x, int y, int z, int neighborID) + { + super.onNeighborBlockChange(world, x, y, z, neighborID); + + // if (neighborID == blockID) { + // return; + // } + + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + ((SignalTerminalLogic) te).onNeighborBlockChange(); + + } + + } + + private static AxisAlignedBB[] getBoxes (SignalTerminalLogic logic) + { + byte connected[] = logic.getConnectedSides(); + + AxisAlignedBB[] parts = new AxisAlignedBB[HITBOXES]; + + // Center + parts[0] = AxisAlignedBB.getBoundingBox(TerminalGeometry.center_min, TerminalGeometry.center_min, TerminalGeometry.center_min, TerminalGeometry.center_max, TerminalGeometry.center_max, + TerminalGeometry.center_max); + + if (connected[ForgeDirection.DOWN.ordinal()] != -1) + { + parts[1] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_width_min, TerminalGeometry.plate_low_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_max, + TerminalGeometry.plate_low_max, TerminalGeometry.plate_width_max); + parts[2] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_width_min, TerminalGeometry.channel_low_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_max, + TerminalGeometry.channel_low_max, TerminalGeometry.channel_width_max); + } + + if (connected[ForgeDirection.UP.ordinal()] != -1) + { + parts[3] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_width_min, TerminalGeometry.plate_high_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_max, + TerminalGeometry.plate_high_max, TerminalGeometry.plate_width_max); + parts[4] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_width_min, TerminalGeometry.channel_high_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_max, + TerminalGeometry.channel_high_max, TerminalGeometry.channel_width_max); + } + + if (connected[ForgeDirection.NORTH.ordinal()] != -1) + { + parts[5] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_high_min, TerminalGeometry.plate_width_max, + TerminalGeometry.plate_width_max, TerminalGeometry.plate_high_max); + parts[6] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_high_min, TerminalGeometry.channel_width_max, + TerminalGeometry.channel_width_max, TerminalGeometry.channel_high_max); + } + + if (connected[ForgeDirection.SOUTH.ordinal()] != -1) + { + parts[7] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_low_min, TerminalGeometry.plate_width_max, + TerminalGeometry.plate_width_max, TerminalGeometry.plate_low_max); + parts[8] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_low_min, TerminalGeometry.channel_width_max, + TerminalGeometry.channel_width_max, TerminalGeometry.channel_low_max); + } + + if (connected[ForgeDirection.WEST.ordinal()] != -1) + { + parts[9] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_low_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_low_max, + TerminalGeometry.plate_width_max, TerminalGeometry.plate_width_max); + parts[10] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_low_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_low_max, + TerminalGeometry.channel_width_max, TerminalGeometry.channel_width_max); + } + + if (connected[ForgeDirection.EAST.ordinal()] != -1) + { + parts[11] = AxisAlignedBB.getBoundingBox(TerminalGeometry.plate_high_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_width_min, TerminalGeometry.plate_high_max, + TerminalGeometry.plate_width_max, TerminalGeometry.plate_width_max); + parts[12] = AxisAlignedBB.getBoundingBox(TerminalGeometry.channel_high_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_width_min, TerminalGeometry.channel_high_max, + TerminalGeometry.channel_width_max, TerminalGeometry.channel_width_max); + } + + return parts; + } + + private static int closestClicked (EntityPlayer player, double reachDistance, SignalTerminalLogic terminal, AxisAlignedBB[] parts) + { + int closest = -1; + + Vec3 playerPosition = Vec3.createVectorHelper(player.posX - terminal.xCoord, player.posY - terminal.yCoord + player.getEyeHeight(), player.posZ - terminal.zCoord); + Vec3 playerLook = player.getLookVec(); + + Vec3 playerViewOffset = Vec3.createVectorHelper(playerPosition.xCoord + playerLook.xCoord * reachDistance, playerPosition.yCoord + playerLook.yCoord * reachDistance, playerPosition.zCoord + + playerLook.zCoord * reachDistance); + double closestCalc = Double.MAX_VALUE; + double hitDistance = 0D; + + for (int i = 0; i < parts.length; i++) + { + if (parts[i] == null) + { + continue; + } + MovingObjectPosition hit = parts[i].calculateIntercept(playerPosition, playerViewOffset); + if (hit != null) + { + hitDistance = playerPosition.distanceTo(hit.hitVec); + if (hitDistance < closestCalc) + { + closestCalc = hitDistance; + closest = i; + } + } + } + return closest; + } + + @Override + public boolean onBlockActivated (World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) + { + int meta = par1World.getBlockMetadata(par2, par3, par4); + TileEntity te = par1World.getBlockTileEntity(par2, par3, par4); + + if (!par1World.isRemote) + { + if (te != null && te instanceof SignalTerminalLogic) + { + // ((SignalTerminalLogic) te).nextChannel(); + if (!par1World.isRemote) + { + // par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1); + // par1World.markBlockForRenderUpdate(par2, par3, par4); + par1World.markBlockForUpdate(par2, par3, par4); + } + int boxHit = closestClicked(par5EntityPlayer, 3.0F, (SignalTerminalLogic) te, getBoxes((SignalTerminalLogic) te)); + if (boxHit < 0 || boxHit >= HITBOXES) + { + return false; + } + if (boxHit == 0) + { + return false; + } + int side = sideBoxMapping[boxHit]; + + if (side < 0 || side >= 6) + { + return false; + } + + if (par5EntityPlayer.isSneaking()) + { + ((SignalTerminalLogic) te).prevChannel(side); + } + else + { + ((SignalTerminalLogic) te).nextChannel(side); + } + } + } + + if (te instanceof SignalTerminalLogic) + { + TConstruct.logger.info(((SignalTerminalLogic) te).debugString()); + } + + TConstruct.logger.info("meta: " + meta); + + //this.setBlockBoundsBasedOnState(par1World, par2, par3, par4); + + return false; + } + + @Override + public void onBlockPlacedBy (World world, int x, int y, int z, EntityLivingBase entityLiving, ItemStack itemStack) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + NBTTagCompound data = itemStack.stackTagCompound; + if (data != null && data.hasKey("connectedSide")) + { + ((SignalTerminalLogic) te).addPendingSide(data.getInteger("connectedSide")); + itemStack.stackTagCompound = null; + } + ((SignalTerminalLogic) te).connectPending(); + } + } + + + + @Override + public ArrayList getBlockDropped (World world, int x, int y, int z, int metadata, int fortune) + { + return new ArrayList(); + } + + @Override + public void breakBlock (World world, int x, int y, int z, int id, int meta) + { + int dropTerm, dropWire = 0; + float jumpX, jumpY, jumpZ; + ItemStack tempStack; + Random rand = new Random(); + + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te instanceof SignalTerminalLogic) + { + dropTerm = ((SignalTerminalLogic) te).getDroppedTerminals(); + dropWire = ((SignalTerminalLogic) te).getDroppedWire(); + + if (dropTerm > 0) + { + tempStack = new ItemStack(TConstruct.instance.content.signalTerminal.blockID, dropTerm, 0); + jumpX = rand.nextFloat() * 0.8F + 0.1F; + jumpY = rand.nextFloat() * 0.8F + 0.1F; + jumpZ = rand.nextFloat() * 0.8F + 0.1F; + + EntityItem entityitem = new EntityItem(world, (double) ((float) x + jumpX), (double) ((float) y + jumpY), (double) ((float) z + jumpZ), tempStack); + + float offset = 0.05F; + entityitem.motionX = (double) ((float) rand.nextGaussian() * offset); + entityitem.motionY = (double) ((float) rand.nextGaussian() * offset + 0.2F); + entityitem.motionZ = (double) ((float) rand.nextGaussian() * offset); + world.spawnEntityInWorld(entityitem); + } + if (dropWire > 0) + { + tempStack = new ItemStack(TConstruct.instance.content.lengthWire, dropWire); + jumpX = rand.nextFloat() * 0.8F + 0.1F; + jumpY = rand.nextFloat() * 0.8F + 0.1F; + jumpZ = rand.nextFloat() * 0.8F + 0.1F; + + EntityItem entityitem = new EntityItem(world, (double) ((float) x + jumpX), (double) ((float) y + jumpY), (double) ((float) z + jumpZ), tempStack); + + float offset = 0.05F; + entityitem.motionX = (double) ((float) rand.nextGaussian() * offset); + entityitem.motionY = (double) ((float) rand.nextGaussian() * offset + 0.2F); + entityitem.motionZ = (double) ((float) rand.nextGaussian() * offset); + world.spawnEntityInWorld(entityitem); + } + ((SignalTerminalLogic) te).notifyBreak(); + } + + super.breakBlock(world, x, y, z, id, meta); + } + +} diff --git a/src/tconstruct/blocks/component/SignalBusMasterLogic.java b/src/tconstruct/blocks/component/SignalBusMasterLogic.java new file mode 100644 index 00000000..a7d6a84b --- /dev/null +++ b/src/tconstruct/blocks/component/SignalBusMasterLogic.java @@ -0,0 +1,255 @@ +package tconstruct.blocks.component; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.library.multiblock.IMultiblockMember; +import tconstruct.library.multiblock.MultiblockMasterBaseLogic; +import tconstruct.library.util.CoordTuple; + +public class SignalBusMasterLogic extends MultiblockMasterBaseLogic +{ + private boolean forceUpdate = false; + private boolean signalUpdate = false; + private byte[] masterSignals = new byte[16]; + private CoordTuple[] signalProviderCoords = new CoordTuple[16]; + + //private List tetheredBuses = new LinkedList(); // Buses that contain linked Terminals + private Map tetheredBuses = new HashMap(); + + public SignalBusMasterLogic(World world) + { + super(world); + + for (int i = 0; i < 16; i++) + { + masterSignals[i] = 0; + } + } + + @Override + public boolean doUpdate () + { + if (worldObj.isRemote || !forceUpdate) + { + return false; + } + + forceUpdate = false; + + TileEntity te; + + // Calculate new signals from last tick's information + byte[] oldSignals = masterSignals; + masterSignals = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (byte[] signals : tetheredBuses.values()) + { + calcSignals(signals); + } + + if (!Arrays.equals(oldSignals, masterSignals)) + { + // Send updates to SignalBuses + for (CoordTuple coord : tetheredBuses.keySet()) + { + if (worldObj.getChunkProvider().chunkExists(coord.x >> 4, coord.z >> 4)) + { + te = worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (te instanceof SignalBusLogic) + { + ((SignalBusLogic) te).updateLocalSignals(masterSignals); + ((SignalBusLogic) te).multiBlockTick(); + } + } + } + } + + return true; + } + + public void updateBusSignals (CoordTuple bus, byte[] signals) + { + if (!Arrays.equals(tetheredBuses.get(bus), signals)) + { + tetheredBuses.put(bus, signals); + forceUpdate = true; + } + } + + public byte[] getSignals () + { + return masterSignals.clone(); + } + + @Override + protected void onBlockAdded (IMultiblockMember newMember) + { + + } + + @Override + protected void onBlockRemoved (IMultiblockMember oldMember) + { + if (tetheredBuses.containsKey(oldMember.getCoordInWorld())) + { + tetheredBuses.remove(oldMember.getCoordInWorld()); + forceUpdate = true; + } + } + + @Override + protected void onDataMerge (MultiblockMasterBaseLogic newMaster) + { + byte[] oldSignals = ((SignalBusMasterLogic) newMaster).getSignals(); + + byte[] newMasterSignals = ((SignalBusMasterLogic) newMaster).getSignals(); + + if (tetheredBuses.size() > 0) + { + ((SignalBusMasterLogic) newMaster).mergeTethered(tetheredBuses); + } + + ((SignalBusMasterLogic) newMaster).calcSignals(masterSignals); + + if (!Arrays.equals(oldSignals, ((SignalBusMasterLogic) newMaster).getSignals())) + { + ((SignalBusMasterLogic) newMaster).forceUpdate(); + } + + } + + protected void calcSignals (byte[] signals) + { + if (signals[0] > masterSignals[0]) + { + masterSignals[0] = signals[0]; + } + if (signals[1] > masterSignals[1]) + { + masterSignals[1] = signals[1]; + } + if (signals[2] > masterSignals[2]) + { + masterSignals[2] = signals[2]; + } + if (signals[3] > masterSignals[3]) + { + masterSignals[3] = signals[3]; + } + if (signals[4] > masterSignals[4]) + { + masterSignals[4] = signals[4]; + } + if (signals[5] > masterSignals[5]) + { + masterSignals[5] = signals[5]; + } + if (signals[6] > masterSignals[6]) + { + masterSignals[6] = signals[6]; + } + if (signals[7] > masterSignals[7]) + { + masterSignals[7] = signals[7]; + } + if (signals[8] > masterSignals[8]) + { + masterSignals[8] = signals[8]; + } + if (signals[9] > masterSignals[9]) + { + masterSignals[9] = signals[9]; + } + if (signals[10] > masterSignals[10]) + { + masterSignals[10] = signals[10]; + } + if (signals[11] > masterSignals[11]) + { + masterSignals[11] = signals[11]; + } + if (signals[12] > masterSignals[12]) + { + masterSignals[12] = signals[12]; + } + if (signals[13] > masterSignals[13]) + { + masterSignals[13] = signals[13]; + } + if (signals[14] > masterSignals[14]) + { + masterSignals[14] = signals[14]; + } + if (signals[15] > masterSignals[15]) + { + masterSignals[15] = signals[15]; + } + } + + protected void mergeTethered (Map oldMasterTethered) + { + tetheredBuses.putAll(oldMasterTethered); + } + + @Override + public void writeToNBT (NBTTagCompound data) + { + // Nothing important at the moment + } + + @Override + public void readFromNBT (NBTTagCompound data) + { + // Nothing important at the moment + } + + @Override + public void formatDescriptionPacket (NBTTagCompound data) + { + // Nothing important at the moment + } + + @Override + public void decodeDescriptionPacket (NBTTagCompound data) + { + // Nothing important at the moment + } + + @Override + public String debugString () + { + String fromSuper = super.debugString(); + + if (worldObj.isRemote) + { + return fromSuper; + } + + String tstring = "Tethered Buses: " + tetheredBuses.size() + "\n Signals: ["; + for (int n = 0; n < 16; n++) + { + tstring += n + ":" + masterSignals[n]; + + if (n != 15) + tstring += ", "; + } + tstring += "]"; + + return fromSuper + "\n" + tstring; + } + + public void forceUpdate () + { + forceUpdate = true; + } + +} diff --git a/src/tconstruct/blocks/logic/SignalBusLogic.java b/src/tconstruct/blocks/logic/SignalBusLogic.java new file mode 100644 index 00000000..49b6db27 --- /dev/null +++ b/src/tconstruct/blocks/logic/SignalBusLogic.java @@ -0,0 +1,690 @@ +package tconstruct.blocks.logic; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.swing.text.MaskFormatter; + +import net.minecraft.entity.item.EntityItem; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.Packet132TileEntityData; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidEvent; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; +import net.minecraftforge.fluids.IFluidTank; +import tconstruct.TConstruct; +import tconstruct.blocks.component.SignalBusMasterLogic; +import tconstruct.library.component.ISignalBusConnectable; +import tconstruct.library.multiblock.IMultiblockMember; +import tconstruct.library.multiblock.MultiblockBaseLogic; +import tconstruct.library.multiblock.MultiblockMasterBaseLogic; +import tconstruct.library.signal.ISignalTransceiver; +import tconstruct.library.util.CoordTuple; +import tconstruct.library.util.IActiveLogic; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class SignalBusLogic extends MultiblockBaseLogic implements IActiveLogic, ISignalBusConnectable +{ + private int ticks = 0; + private Map transceivers = new HashMap(); + private byte[] localHighSignals = new byte[16]; + private byte[] cachedReceivedSignals = new byte[16]; + + private boolean southboundSignalsChanged = false; + private boolean northboundSignalsChanged = false; + private boolean forceCheck = false; + + private boolean[] placedSides = new boolean[] { false, false, false, false, false, false }; + + public SignalBusLogic() + { + + } + + @Override + public boolean canUpdate () + { + return true; + } + + @Override + public IMultiblockMember[] getNeighboringMembers () + { + List corners = new LinkedList(); + + int i, j; + int tX, tY, tZ; + TileEntity te; + for (i = 0; i < 6; ++i) + { + if (!placedSides[i]) + { + continue; + } + for (j = 0; j < 6; ++j) + { + if (j == i || j == ForgeDirection.OPPOSITES[i]) + { + continue; + } + tX = ForgeDirection.VALID_DIRECTIONS[j].offsetX + xCoord; + tY = ForgeDirection.VALID_DIRECTIONS[j].offsetY + yCoord; + tZ = ForgeDirection.VALID_DIRECTIONS[j].offsetZ + zCoord; + if (worldObj.isBlockOpaqueCube(tX, tY, tZ)) + { + continue; + } + tX += ForgeDirection.VALID_DIRECTIONS[i].offsetX; + tY += ForgeDirection.VALID_DIRECTIONS[i].offsetY; + tZ += ForgeDirection.VALID_DIRECTIONS[i].offsetZ; + te = worldObj.getBlockTileEntity(tX, tY, tZ); + if (te instanceof IMultiblockMember && ((IMultiblockMember) te).isCompatible((Object) this)) + { + corners.add((IMultiblockMember) te); + } + } + } + + corners.addAll(Arrays.asList(super.getNeighboringMembers())); + IMultiblockMember[] tmp = new IMultiblockMember[corners.size()]; + return corners.toArray(tmp); + } + + public void broadcastSouthboundSignals () + { + if (southboundSignalsChanged) + { + TileEntity te = null; + + for (CoordTuple coord : transceivers.keySet()) + { + if (worldObj.getChunkProvider().chunkExists(coord.x >> 4, coord.z >> 4)) + { + te = worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (te instanceof ISignalTransceiver) + { + ((ISignalTransceiver) te).receiveSignalUpdate(cachedReceivedSignals); + } + } + } + + southboundSignalsChanged = false; + } + } + + public void multiBlockTick () + { + + } + + @Override + public void updateEntity () + { + if (worldObj.isRemote) + { + return; + } + + if (!this.isConnected()) + { + return; + } + + if (forceCheck) + { + forceCheck = false; + super.onBlockAdded(worldObj, xCoord, yCoord, zCoord); + this.getMultiblockMaster().revisitBlocks(); + } + + if (northboundSignalsChanged) + { + + TileEntity te; + byte[] signals; + + localHighSignals = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (CoordTuple coord : transceivers.keySet()) + { + + signals = transceivers.get(coord); + + if (signals[0] > localHighSignals[0]) + { + localHighSignals[0] = signals[0]; + } + if (signals[1] > localHighSignals[1]) + { + localHighSignals[1] = signals[1]; + } + if (signals[2] > localHighSignals[2]) + { + localHighSignals[2] = signals[2]; + } + if (signals[3] > localHighSignals[3]) + { + localHighSignals[3] = signals[3]; + } + if (signals[4] > localHighSignals[4]) + { + localHighSignals[4] = signals[4]; + } + if (signals[5] > localHighSignals[5]) + { + localHighSignals[5] = signals[5]; + } + if (signals[6] > localHighSignals[6]) + { + localHighSignals[6] = signals[6]; + } + if (signals[7] > localHighSignals[7]) + { + localHighSignals[7] = signals[7]; + } + if (signals[8] > localHighSignals[8]) + { + localHighSignals[8] = signals[8]; + } + if (signals[9] > localHighSignals[9]) + { + localHighSignals[9] = signals[9]; + } + if (signals[10] > localHighSignals[10]) + { + localHighSignals[10] = signals[10]; + } + if (signals[11] > localHighSignals[11]) + { + localHighSignals[11] = signals[11]; + } + if (signals[12] > localHighSignals[12]) + { + localHighSignals[12] = signals[12]; + } + if (signals[13] > localHighSignals[13]) + { + localHighSignals[13] = signals[13]; + } + if (signals[14] > localHighSignals[14]) + { + localHighSignals[14] = signals[14]; + } + if (signals[15] > localHighSignals[15]) + { + localHighSignals[15] = signals[15]; + } + } + + ((SignalBusMasterLogic) getMultiblockMaster()).updateBusSignals(getCoordInWorld(), localHighSignals); + + northboundSignalsChanged = false; + + } + + broadcastSouthboundSignals(); + } + + public boolean registerTerminal (World world, int x, int y, int z, boolean rehome) + { + if (worldObj.isRemote) + { + return false; + } + if (world == worldObj && world.isRemote == worldObj.isRemote) + { + if (worldObj.getBlockTileEntity(x, y, z) instanceof ISignalTransceiver) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + CoordTuple coords = new CoordTuple(x, y, z); + byte[] signals = null; + + if (transceivers.containsKey(coords)) + { + return true; + } + int dropWire = ((ISignalTransceiver) te).doUnregister(rehome); + if (dropWire > 0) + { + Random rand = new Random(); + ItemStack tempStack = new ItemStack(TConstruct.instance.content.lengthWire, dropWire); + float jumpX = rand.nextFloat() * 0.8F + 0.1F; + float jumpY = rand.nextFloat() * 0.8F + 0.1F; + float jumpZ = rand.nextFloat() * 0.8F + 0.1F; + + EntityItem entityitem = new EntityItem(world, (double) ((float) xCoord + jumpX), (double) ((float) yCoord + jumpY), (double) ((float) zCoord + jumpZ), tempStack); + + float offset = 0.05F; + entityitem.motionX = (double) ((float) rand.nextGaussian() * offset); + entityitem.motionY = (double) ((float) rand.nextGaussian() * offset + 0.2F); + entityitem.motionZ = (double) ((float) rand.nextGaussian() * offset); + world.spawnEntityInWorld(entityitem); + } + ((ISignalTransceiver) te).setBusCoords(world, xCoord, yCoord, zCoord); + + signals = ((ISignalTransceiver) te).getReceivedSignals(); + + transceivers.put(coords, signals); + northboundSignalsChanged = true; + + updateLocalSignals(((SignalBusMasterLogic)getMultiblockMaster()).getSignals()); + ((ISignalTransceiver) te).receiveSignalUpdate(cachedReceivedSignals); + return true; + } + } + + return false; + } + + @Override + public void onDetached (MultiblockMasterBaseLogic oldMaster) + { + + super.onDetached(oldMaster); + } + + @Override + public void onAttached (MultiblockMasterBaseLogic newMaster) + { + super.onAttached(newMaster); + + if (transceivers != null || !transceivers.isEmpty()) + { + northboundSignalsChanged = true; + + updateLocalSignals(((SignalBusMasterLogic)getMultiblockMaster()).getSignals()); + } + } + + public boolean isRegisteredTerminal (World world, int x, int y, int z) + { + if (worldObj.isRemote) + { + return false; + } + return transceivers.containsKey(new CoordTuple(x, y, z)); + } + + public boolean unregisterTerminal (World world, int x, int y, int z) + { + if (worldObj.isRemote) + { + return false; + } + if (transceivers.remove(new CoordTuple(x, y, z)) != null) + { + northboundSignalsChanged = true; + return true; + } + return false; + } + + public boolean hasTerminals () + { + return (transceivers.size() > 0); + } + + @Override + public boolean isCompatible (Object other) + { + return (other.getClass() == this.getClass()); + } + + @Override + public void readFromNBT (NBTTagCompound tags) + { + super.readFromNBT(tags); + readCustomNBT(tags); + } + + public void readCustomNBT (NBTTagCompound tags) + { + int temp = tags.getInteger("placedSides"); + + for (int i = 0; i < 6; ++i) + { + placedSides[i] = (temp >> i & 1) == 1; + } + } + + @Override + public void writeToNBT (NBTTagCompound tags) + { + super.writeToNBT(tags); + writeCustomNBT(tags); + } + + public void writeCustomNBT (NBTTagCompound tags) + { + int temp = 0; + + for (int i = 0; i < 6; ++i) + { + if (placedSides[i]) + { + temp |= 1 << i; + } + } + + tags.setInteger("placedSides", temp); + } + + @Override + public Packet getDescriptionPacket () + { + NBTTagCompound tag = new NBTTagCompound(); + writeCustomNBT(tag); + return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, tag); + } + + @Override + public void onDataPacket (INetworkManager net, Packet132TileEntityData packet) + { + readCustomNBT(packet.data); + this.worldObj.markBlockForRenderUpdate(this.xCoord, this.yCoord, this.zCoord); + } + + @Override + public boolean getActive () + { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setActive (boolean flag) + { + // TODO Auto-generated method stub + + } + + public boolean[] placedSides () + { + return placedSides.clone(); + } + + public boolean[] connectedSides (ForgeDirection fromFace) + { + boolean[] connected = new boolean[6]; + + TileEntity te; + ForgeDirection dir; + int neighborX; + int neighborY; + int neighborZ; + for (int i = 0; i < 6; ++i) + { + if (i == fromFace.ordinal() || i == fromFace.getOpposite().ordinal()) + { + continue; + } + dir = ForgeDirection.getOrientation(i); + neighborX = xCoord + dir.offsetX; + neighborY = yCoord + dir.offsetY; + neighborZ = zCoord + dir.offsetZ; + + te = worldObj.getBlockTileEntity(neighborX, neighborY, neighborZ); + connected[i] = (te instanceof ISignalBusConnectable && ((ISignalBusConnectable) te).connectableOnFace(fromFace)); + } + + return connected; + } + + // Face is the face in the block; e.g. DOWN = on top of the block below. + public boolean connectableOnFace (ForgeDirection side) + { + return placedSides[side.ordinal()]; + } + + public boolean isConnected (ForgeDirection side, ForgeDirection dir) + { + TileEntity te; + + switch (dir) + { + case DOWN: + return (this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord - 1, this.zCoord) instanceof SignalBusLogic); + case NORTH: + return (this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord - 1) instanceof SignalBusLogic); + case SOUTH: + return (this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord + 1) instanceof SignalBusLogic); + case WEST: + return (this.worldObj.getBlockTileEntity(this.xCoord - 1, this.yCoord, this.zCoord) instanceof SignalBusLogic); + case EAST: + return (this.worldObj.getBlockTileEntity(this.xCoord + 1, this.yCoord, this.zCoord) instanceof SignalBusLogic); + default: + return false; + } + } + + @Override + public MultiblockMasterBaseLogic getNewMultiblockMasterObject () + { + return new SignalBusMasterLogic(this.worldObj); + } + + public String debugString () + { + return "Connected: " + transceivers.size(); + } + + public byte[] getLocalSignals () + { + return localHighSignals; + } + + public void updateTransceiverSignals (CoordTuple coords, byte[] signals) + { + if (!Arrays.equals(signals, transceivers.get(coords))) + { + transceivers.put(coords, signals); + northboundSignalsChanged = true; + } + } + + // Southbound signals update from master + public void updateLocalSignals (byte[] signals) + { + if (!Arrays.equals(signals, cachedReceivedSignals)) + { + cachedReceivedSignals = signals.clone(); + southboundSignalsChanged = true; + } + } + + public void addPlacedSide (int side) + { + placedSides[side] = true; + forceCheck = true; + } + + public boolean[] getRenderCorners (ForgeDirection fromFace) + { + boolean[] corners = new boolean[6]; + + TileEntity te; + ForgeDirection dir; + int neighborX; + int neighborY; + int neighborZ; + for (int i = 0; i < 6; ++i) + { + if (i == fromFace.ordinal() || i == fromFace.getOpposite().ordinal()) + { + continue; + } + dir = ForgeDirection.getOrientation(i); + neighborX = xCoord + dir.offsetX; + neighborY = yCoord + dir.offsetY; + neighborZ = zCoord + dir.offsetZ; + if (worldObj.isBlockOpaqueCube(neighborX, neighborY, neighborZ)) + { + continue; + } + neighborX += fromFace.offsetX; + neighborY += fromFace.offsetY; + neighborZ += fromFace.offsetZ; + + te = worldObj.getBlockTileEntity(neighborX, neighborY, neighborZ); + corners[i] = (te instanceof ISignalBusConnectable && ((ISignalBusConnectable) te).connectableOnCorner(fromFace.getOpposite(), dir.getOpposite())); + } + + return corners; + } + + @Override + public boolean connectableOnCorner (ForgeDirection side, ForgeDirection turn) + { + if (!placedSides[side.ordinal()] && placedSides[turn.ordinal()]) + { + return true; + } + return false; + } + + @Override + public boolean willConnect (CoordTuple coord) + { + int i, j; + ForgeDirection iDir, jDir; + TileEntity te; + + for (i = 0; i < 6; ++i) + { + iDir = ForgeDirection.VALID_DIRECTIONS[i]; + if (!placedSides[i]) + { + continue; + } + + for (j = 0; j < 6; ++j) + { + if (placedSides[j] || j == i || j == i || j == iDir.getOpposite().ordinal()) + { + continue; + } + jDir = ForgeDirection.VALID_DIRECTIONS[j]; + if (xCoord + jDir.offsetX == coord.x && yCoord + jDir.offsetY == coord.y && zCoord + jDir.offsetZ == coord.z) + { + te = worldObj.getBlockTileEntity(xCoord + jDir.offsetX, yCoord + jDir.offsetY, zCoord + jDir.offsetZ); + if (te instanceof ISignalBusConnectable && ((ISignalBusConnectable)te).connectableOnFace(iDir)) + { + return true; + } + } + if (worldObj.isBlockOpaqueCube(xCoord + jDir.offsetX, yCoord + jDir.offsetY, zCoord + jDir.offsetZ)) + { + continue; + } + if (xCoord + iDir.offsetX + jDir.offsetX == coord.x && yCoord + iDir.offsetY + jDir.offsetY == coord.y && xCoord + iDir.offsetZ + jDir.offsetZ == coord.z) + { + te = worldObj.getBlockTileEntity(xCoord + iDir.offsetX + jDir.offsetX, yCoord + iDir.offsetY + jDir.offsetY, zCoord + iDir.offsetZ + jDir.offsetZ); + if (te instanceof ISignalBusConnectable && ((ISignalBusConnectable)te).connectableOnCorner(iDir.getOpposite(), jDir.getOpposite())) + { + return true; + } + } + } + } + return false; + } + + @Override + protected CoordTuple[] getNeighborCoords () + { + List cornerCoords = new LinkedList(); + + int i, j; + ForgeDirection iDir, jDir; + CoordTuple coord; + + for (i = 0; i < 6; ++i) + { + if (!placedSides[i]) + { + continue; + } + iDir = ForgeDirection.VALID_DIRECTIONS[i]; + for (j = 0; j < 6; ++j) + { + if (placedSides[j] || j == i || j == iDir.getOpposite().ordinal()) + { + continue; + } + jDir = ForgeDirection.VALID_DIRECTIONS[j]; + if (worldObj.isBlockOpaqueCube(xCoord + jDir.offsetX, yCoord + jDir.offsetY, zCoord + jDir.offsetZ)) + { + continue; + } + coord = new CoordTuple(xCoord + iDir.offsetX + jDir.offsetX, yCoord + iDir.offsetY + jDir.offsetY, zCoord + iDir.offsetZ + jDir.offsetZ); + } + } + + cornerCoords.addAll(Arrays.asList(super.getNeighborCoords())); + CoordTuple[] tmp = new CoordTuple[cornerCoords.size()]; + return cornerCoords.toArray(tmp); + } + + public void forceNeighborCheck () + { + forceCheck = true; + } + + public int getDroppedBuses () + { + int calc = 0; + for (int i = 0; i < 6; ++i) + { + if (placedSides[i]) + { + ++calc; + } + } + + return calc; + } + + public int getDroppedWire () + { + int calc = 0; + TileEntity te; + for (CoordTuple coord : transceivers.keySet()) + { + te = worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (te instanceof ISignalTransceiver) + { + calc += ((ISignalTransceiver) te).getDroppedWire(); + } + } + + return calc; + } + + public void notifyBreak () + { + TileEntity te; + for (CoordTuple coord : transceivers.keySet()) + { + te = worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (te instanceof ISignalTransceiver) + { + ((ISignalTransceiver) te).doUnregister(true); + } + } + this.detachSelf(false); + } +} diff --git a/src/tconstruct/blocks/logic/SignalTerminalLogic.java b/src/tconstruct/blocks/logic/SignalTerminalLogic.java new file mode 100644 index 00000000..cfa02d28 --- /dev/null +++ b/src/tconstruct/blocks/logic/SignalTerminalLogic.java @@ -0,0 +1,700 @@ +package tconstruct.blocks.logic; + +import java.util.Arrays; + +import tconstruct.TConstruct; +import tconstruct.blocks.SignalTerminal; +import tconstruct.blocks.TConstructBlock; +import tconstruct.common.TContent; +import tconstruct.library.signal.ISignalTransceiver; +import tconstruct.library.util.CoordTuple; +import net.minecraft.block.Block; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.Packet132TileEntityData; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Facing; +import net.minecraft.util.Icon; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +public class SignalTerminalLogic extends TileEntity implements ISignalTransceiver +{ + private byte[] connectedSides = new byte[6]; + private byte[] receivingSides = new byte[6]; + private byte[] sideChannel = new byte[6]; + + private boolean forceUpdateSide; + private boolean neighborChanged; + + private byte[] cachedSouthboundSignals; + + private int pendingSide = -1; + private CoordTuple signalBus = null; + private boolean doUpdate = false; + private boolean isRegistered = false; + + public SignalTerminalLogic() + { + super(); + + for (int i = 0; i < 6; i++) + { + connectedSides[i] = -1; + receivingSides[i] = -1; + sideChannel[i] = 0; + forceUpdateSide = false; + } + + neighborChanged = false; + + } + + private void tryRegister () + { + boolean wasRegistered = isRegistered; + if (!(worldObj instanceof World)) + { + return; + } + if (!(signalBus instanceof CoordTuple)) + { + return; + } + + TileEntity te = worldObj.getBlockTileEntity(signalBus.x, signalBus.y, signalBus.z); + if (!(te instanceof SignalBusLogic)) + { + return; + } + + isRegistered = ((SignalBusLogic) te).registerTerminal(worldObj, xCoord, yCoord, zCoord, false); + + if (isRegistered != wasRegistered) + { + if (isRegistered) + { + doUpdate = true; + + } + else + { + signalBus = null; + doUpdate = true; + } + } + } + + @Override + public void readFromNBT (NBTTagCompound data) + { + super.readFromNBT(data); + + sideChannel = data.getByteArray("sideChannel"); + receivingSides = data.getByteArray("receivingSides"); + connectedSides = data.getByteArray("connectedSides"); + + if (sideChannel.length != 6) + { + sideChannel = new byte[] { 0, 0, 0, 0, 0, 0 }; + } + if (receivingSides.length != 6) + { + receivingSides = new byte[] { -1, -1, -1, -1, -1, -1 }; + } + if (connectedSides.length != 6) + { + connectedSides = new byte[] { -1, -1, -1, -1, -1, -1 }; + } + + int tX = data.getInteger("BusX"); + int tY = data.getInteger("BusY"); + int tZ = data.getInteger("BusZ"); + + if (tX == xCoord && tY == yCoord && tZ == zCoord) + { + signalBus = null; + } + else + { + signalBus = new CoordTuple(tX, tY, tZ); + } + + if (!isRegistered) + { + tryRegister(); + } + + doUpdate = true; + } + + @Override + public void writeToNBT (NBTTagCompound data) + { + super.writeToNBT(data); + + data.setByteArray("sideChannel", sideChannel); + data.setByteArray("receivingSides", receivingSides); + data.setByteArray("connectedSides", connectedSides); + + if (signalBus != null) + { + data.setInteger("BusX", signalBus.x); + data.setInteger("BusY", signalBus.y); + data.setInteger("BusZ", signalBus.z); + } + else + { + data.setInteger("BusX", xCoord); + data.setInteger("BusY", yCoord); + data.setInteger("BusZ", zCoord); + } + } + + @Override + public void updateEntity () + { + if (pendingSide >= 0 && pendingSide < 6 && connectedSides[pendingSide] == -1) + { + connectedSides[pendingSide] = 0; + pendingSide = -1; + forceUpdateSide = true; + } + + if (worldObj.isRemote) + { + return; + } + + if (forceUpdateSide || neighborChanged) + { + checkNeighbors(); + neighborChanged = false; + forceUpdateSide = false; + } + + if (!doUpdate) + { + return; + } + + if (!isRegistered) + { + tryRegister(); + } + + if (cachedSouthboundSignals != null) + { + processSignalUpdate(cachedSouthboundSignals); + } + + doUpdate = false; + + return; + } + + // Receive Southbound Signal Updates + public void receiveSignalUpdate (byte[] signals) + { + if (!Arrays.equals(cachedSouthboundSignals, signals)) + { + cachedSouthboundSignals = signals.clone(); + doUpdate = true; + } + } + + private void processSignalUpdate (byte[] signals) + { + int oldValue; + int targetX = 0; + int targetY = 0; + int targetZ = 0; + int oSide; + + for (int i = 0; i < 6; i++) + { + if (connectedSides[i] != -1) + { + oldValue = connectedSides[i]; + connectedSides[i] = signals[sideChannel[i]]; + + if (oldValue != connectedSides[i]) + { + targetX = xCoord; + targetY = yCoord; + targetZ = zCoord; + switch (i) + { + case 0: + targetY += -1; + oSide = 1; + break; + case 1: + targetY += 1; + oSide = 0; + break; + case 2: + targetZ += 1; + oSide = 2; + break; + case 3: + targetZ += -1; + oSide = 3; + break; + case 4: + targetX += -1; + oSide = 5; + break; + case 5: + targetX += 1; + oSide = 4; + break; + default: + oSide = 0; + } + + worldObj.notifyBlockOfNeighborChange(targetX, targetY, targetZ, TConstruct.instance.content.signalTerminal.blockID); + worldObj.notifyBlocksOfNeighborChange(targetX, targetY, targetZ, TConstruct.instance.content.signalTerminal.blockID, oSide); + //worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, TConstruct.instance.content.signalTerminal.blockID); + } + } + } + } + + // Callback from Un/Registration + public void setBusCoords (World world, int x, int y, int z) + { + if (world.provider.dimensionId == worldObj.provider.dimensionId && !world.isRemote && !worldObj.isRemote) + { + signalBus = new CoordTuple(x, y, z); + world.markBlockForUpdate(xCoord, yCoord, zCoord); + } + doUpdate = true; + } + + public int isProvidingWeakPower (int side) + { + return isProvidingStrongPower(side); + } + + public int isProvidingStrongPower (int side) + { + int tside = side; + + switch (side) + { + case 0: + tside = 1; + break; + case 1: + tside = 0; + break; + case 2: + tside = 2; + break; + case 3: + tside = 3; + break; + case 4: + tside = 5; + break; + case 5: + tside = 4; + break; + default: + tside = side; + } + + if (tside >= 0 && tside < 6 && connectedSides[tside] > 0) + { + return connectedSides[tside] - 1; + } + + return 0; + } + + public void addPendingSide (int side) + { + pendingSide = side; + } + + public void connectPending () + { + if (pendingSide >= 0 && pendingSide < 6 && connectedSides[pendingSide] == -1) + { + connectedSides[pendingSide] = 0; + } + pendingSide = -1; + doUpdate = true; + } + + public byte[] getConnectedSides () + { + return connectedSides.clone(); + } + + public String debugString () + { + String tstr = ""; + + if (!worldObj.isRemote) + { + byte tbyte = (byte) 0; + for (int n = 0; n < 6; n++) + { + if (connectedSides[n] != -1) + { + tbyte &= (1 << n); + } + } + tstr += "Sides: " + tbyte + "\n"; + } + + return tstr; + } + + /* Packets */ + @Override + public Packet getDescriptionPacket () + { + NBTTagCompound tag = new NBTTagCompound(); + writeToNBT(tag); + return new Packet132TileEntityData(xCoord, yCoord, zCoord, 1, tag); + } + + @Override + public void onDataPacket (INetworkManager net, Packet132TileEntityData packet) + { + readFromNBT(packet.data); + onInventoryChanged(); + worldObj.markBlockForRenderUpdate(xCoord, yCoord, zCoord); + this.doUpdate = true; + } + + public static Icon getChannelIcon (IBlockAccess world, int x, int y, int z, int side) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (te != null && te instanceof SignalTerminalLogic) + { + int channel = ((SignalTerminalLogic) te).sideChannel[side]; + + return ((SignalTerminal) TConstruct.instance.content.signalTerminal).getChannelIcon(channel); + } + + return ((SignalTerminal) TConstruct.instance.content.signalTerminal).getChannelIcon(0); + } + + public static Icon[] getChannelIcons () + { + return ((SignalTerminal) TConstruct.instance.content.signalTerminal).channelIcons; + } + + public static Icon getChannelIcon (int channel) + { + return getChannelIcons()[channel]; + } + + public Icon getChannelIconFromLogic (int side) + { + return getChannelIcons()[sideChannel[side]]; + } + + public void nextChannel (int side) + { + if (worldObj.isRemote) + { + return; + } + + sideChannel[side]++; + + if (sideChannel[side] >= 16) + { + sideChannel[side] = 0; + } + + doUpdate = true; + } + + public void prevChannel (int side) + { + if (worldObj.isRemote) + { + return; + } + + sideChannel[side]--; + + if (sideChannel[side] < 0) + { + sideChannel[side] = 15; + } + + doUpdate = true; + } + + public void notifyBreak () + { + if (!(worldObj instanceof World) || worldObj.isRemote) + { + return; + } + if (!(signalBus instanceof CoordTuple)) + { + return; + } + + TileEntity te = worldObj.getBlockTileEntity(signalBus.x, signalBus.y, signalBus.z); + if (te == null || !(te instanceof SignalBusLogic)) + { + return; + } + + ((SignalBusLogic) te).unregisterTerminal(worldObj, xCoord, yCoord, zCoord); + } + + public void onNeighborBlockChange () + { + if (worldObj.isRemote) + { + return; + } + + neighborChanged = true; + } + + public void checkNeighbors () + { + if (signalBus != null && signalBus instanceof CoordTuple) + { + TileEntity te = worldObj.getBlockTileEntity(signalBus.x, signalBus.y, signalBus.z); + + if (te instanceof SignalBusLogic) + { + ((SignalBusLogic) te).updateTransceiverSignals(new CoordTuple(xCoord, yCoord, zCoord), getReceivedSignals()); + } + } + else + { + // We can redistribute signals locally at least + receiveSignalUpdate(getReceivedSignals()); + } + } + + public Icon[] getSideIcons () + { + Icon[] icons = getChannelIcons(); + Icon[] sideIcons = new Icon[6]; + + for (int i = 0; i < 6; i++) + { + if (sideChannel[i] > 0) + { + sideIcons[i] = icons[sideChannel[i]]; + } + else + { + sideIcons[i] = icons[0]; + } + } + + return sideIcons; + } + + // Provide Northbound Signals + public byte[] getReceivedSignals (boolean vanillaRedstoneKludge) + { + byte[] highChannel = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + int[] offset = new int[] { 0, 0, 0 }; + int oSide; + int tempStrength; + byte temporarySide; + + for (int i = 0; i < 6; i++) + { + if (connectedSides[i] != -1) + { + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + switch (i) + { + case 0: + offset[1] += -1; + oSide = 1; + break; + case 1: + offset[1] += 1; + oSide = 0; + break; + case 2: + offset[2] += 1; + oSide = 3; + break; + case 3: + offset[2] += -1; + oSide = 2; + break; + case 4: + offset[0] += -1; + oSide = 5; + break; + case 5: + offset[0] += 1; + oSide = 4; + break; + default: + oSide = i; + } + + tempStrength = 0; + if (connectedSides[i] > 0) + { + // We are currently powering this side, we need to identify if we are the only source or not + temporarySide = connectedSides[i]; + connectedSides[i] = -1; + tempStrength = worldObj.getIndirectPowerLevelTo(xCoord + offset[0], yCoord + offset[1], zCoord + offset[2], oSide); + //tempStrength = worldObj.getStrongestIndirectPower(xCoord + offset[0], yCoord + offset[1], zCoord + offset[2]); + if (tempStrength > 0 && tempStrength == (temporarySide - 1)) + { + // Let's make sure we're not dealing with vanilla redstone + + int bid = 0; + int power = 0; + int temp = 0; + + for (int j = 0; j < 6; ++j) + { + if (offset[0] + Facing.offsetsXForSide[j] == 0 && offset[1] + Facing.offsetsYForSide[j] == 0 && offset[2] + Facing.offsetsZForSide[j] == 0) + { + continue; + } + temp = worldObj.getIndirectPowerLevelTo(xCoord + offset[0] + Facing.offsetsXForSide[j], yCoord + offset[1] + Facing.offsetsYForSide[j], zCoord + offset[2] + Facing.offsetsZForSide[j], j); + + if (temp > power) + { + + bid = worldObj.getBlockId(xCoord + offset[0] + Facing.offsetsXForSide[j], yCoord + offset[1] + Facing.offsetsYForSide[j], zCoord + offset[2] + + Facing.offsetsZForSide[j]); + if (bid != Block.redstoneWire.blockID) + { + power = temp; + } + } + + if (power == tempStrength) + { + // We've found our highest source that's not RS, let's save some cycles + break; + } + } + tempStrength = power; + + } + connectedSides[i] = temporarySide; + } + else + { + tempStrength = worldObj.getIndirectPowerLevelTo(xCoord + offset[0], yCoord + offset[1], zCoord + offset[2], oSide); +// tempStrength = worldObj.getStrongestIndirectPower(xCoord + offset[0], yCoord + offset[1], zCoord + offset[2]); + } + + // if (tempStrength > 0 && tempStrength < receivingSides[i]){ + // receivingSides[i] = 0; + // connectedSides[i] = 0; + // } + // else { + // receivingSides[i] = (byte)Math.max((byte)tempStrength, 0); + // } + if (tempStrength > 0) + { + receivingSides[i] = (byte) (tempStrength - 1); + } + else + { + receivingSides[i] = 0; + } + + // if ((receivingSides[i] - 1) > connectedSides[i]) { + // connectedSides[i] = (byte)(receivingSides[i] - 1); + // } + + if (receivingSides[i] > highChannel[sideChannel[i]]) + { + highChannel[sideChannel[i]] = (byte) receivingSides[i]; + } + + } + } + + return highChannel; + } + + @Override + public int doUnregister (boolean reHoming) + { + int dropWire = 0; + + if (signalBus != null) + { + TileEntity te = worldObj.getBlockTileEntity(signalBus.x, signalBus.y, signalBus.z); + dropWire = Math.abs(xCoord - signalBus.x) + Math.abs(yCoord - signalBus.y) + Math.abs(zCoord - signalBus.z); + if (te instanceof SignalBusLogic) + { + ((SignalBusLogic)te).unregisterTerminal(worldObj, xCoord, yCoord, zCoord); + } + } + // Remove signalBus coords + signalBus = null; + + + // Calculate new local received signals and provide them to local connections + receiveSignalUpdate(getReceivedSignals()); + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + return (reHoming) ? dropWire : 0; + } + + @Override + public byte[] getReceivedSignals () + { + return getReceivedSignals(false); + } + + public int getDroppedTerminals () + { + int count = 0; + for (int i = 0; i < 6; ++i) + { + if (connectedSides[i] != -1) + { + ++count; + } + } + + return count; + } + + public int getDroppedWire () + { + int calcWire = 0; + if (signalBus instanceof CoordTuple) + { + calcWire += Math.abs(signalBus.x - xCoord); + calcWire += Math.abs(signalBus.y - yCoord); + calcWire += Math.abs(signalBus.z - zCoord); + + return calcWire; + } + return 0; + } + + @Override + public CoordTuple getBusCoords () + { + return signalBus; + } +} diff --git a/src/tconstruct/client/SignalTetherWorldOverlayRenderer.java b/src/tconstruct/client/SignalTetherWorldOverlayRenderer.java new file mode 100644 index 00000000..324d7932 --- /dev/null +++ b/src/tconstruct/client/SignalTetherWorldOverlayRenderer.java @@ -0,0 +1,119 @@ +package tconstruct.client; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import org.lwjgl.opengl.GL11; + +import codechicken.lib.math.MathHelper; + +import tconstruct.TConstruct; +import tconstruct.library.signal.ISignalTransceiver; +import tconstruct.library.util.CoordTuple; +import tconstruct.library.util.CoordTuplePair; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.event.ForgeSubscribe; + +public class SignalTetherWorldOverlayRenderer +{ + + @ForgeSubscribe + public void onWorldRenderLast (RenderWorldLastEvent event) + { + if (event.context.mc.thePlayer == null || event.context.mc.thePlayer.getHeldItem() == null) + { + return; + } + if (event.context.mc.thePlayer.getHeldItem().itemID == TConstruct.instance.content.spoolWire.itemID) + { + GL11.glPushMatrix(); + Entity entity = event.context.mc.renderViewEntity; + + double posX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * event.partialTicks; + double posY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * event.partialTicks; + double posZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * event.partialTicks; + + GL11.glTranslated(-posX, -posY, -posZ); + + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glLineWidth(2.5F); + GL11.glBegin(GL11.GL_LINES); + + GL11.glColor4f(1, 0, 0, 1); + + World world = entity.worldObj; + int x1 = (int) entity.posX; + int z1 = (int) entity.posZ; + int y1 = (int) ((entity.posY > world.getHeight()-16) ? world.getHeight()-16 : ((entity.posY < 16) ? 16 : entity.posY)); + AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0); + + GL11.glColor4f(1, 0, 0, 1); + + Chunk chunks[] = new Chunk[9]; + + chunks[4] = world.getChunkFromBlockCoords(x1, z1); + int cX = chunks[4].xPosition; + int cZ = chunks[4].zPosition; + + chunks[0] = world.getChunkFromChunkCoords(cX - 1, cZ - 1); + chunks[1] = world.getChunkFromChunkCoords(cX , cZ - 1); + chunks[2] = world.getChunkFromChunkCoords(cX + 1, cZ - 1); + + chunks[3] = world.getChunkFromChunkCoords(cX - 1, cZ ); + chunks[5] = world.getChunkFromChunkCoords(cX + 1, cZ ); + + chunks[6] = world.getChunkFromChunkCoords(cX - 1, cZ + 1); + chunks[7] = world.getChunkFromChunkCoords(cX , cZ + 1); + chunks[8] = world.getChunkFromChunkCoords(cX + 1, cZ + 1); + + Queue transceivers = new LinkedList(); + CoordTuple src; + CoordTuple dst; + for (int c = 0; c < 9; ++c) + { + for(Object obj : chunks[c].chunkTileEntityMap.values()) + { + if (obj instanceof ISignalTransceiver && obj instanceof TileEntity) + { + dst = ((ISignalTransceiver) obj).getBusCoords(); + if (dst != null) + { + src = new CoordTuple(((TileEntity)obj).xCoord, ((TileEntity)obj).yCoord, ((TileEntity)obj).zCoord); + transceivers.add(new CoordTuplePair(src,dst)); + } + } + } + } + + CoordTuplePair renderPair; + while (transceivers.size() > 0) + { + renderPair = transceivers.remove(); + + GL11.glVertex3d(renderPair.a.x + 0.5, renderPair.a.y + 0.5, renderPair.a.z + 0.5); + GL11.glVertex3d(renderPair.b.x + 0.5, renderPair.b.y, renderPair.b.z + 0.5); + } + +// GL11.glVertex3d(x, y+0.004, z); +// GL11.glVertex3d(x+1, y+0.004, z+1); +// GL11.glVertex3d(x+1, y+0.004, z); +// GL11.glVertex3d(x, y+0.004, z+1); + + GL11.glEnd(); + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_BLEND); + + GL11.glPopMatrix(); + } + } +} diff --git a/src/tconstruct/client/TProxyClient.java b/src/tconstruct/client/TProxyClient.java index 744a27cb..79f78681 100644 --- a/src/tconstruct/client/TProxyClient.java +++ b/src/tconstruct/client/TProxyClient.java @@ -26,6 +26,7 @@ import net.minecraftforge.fluids.RenderBlockFluid; import org.lwjgl.opengl.GL11; import org.w3c.dom.Document; import tconstruct.TConstruct; +import tconstruct.blocks.SignalTerminal; import tconstruct.blocks.SlimeExplosive; import tconstruct.blocks.logic.*; import tconstruct.client.armor.RenderArmorCast; @@ -45,6 +46,7 @@ import tconstruct.inventory.ContainerLandmine; import tconstruct.library.TConstructRegistry; import tconstruct.library.client.*; import tconstruct.library.crafting.ToolBuilder; +import tconstruct.library.multiblock.MultiblockServerTickHandler; import tconstruct.library.tools.ToolCore; import tconstruct.util.config.PHConstruct; import tconstruct.util.player.*; @@ -197,6 +199,7 @@ public class TProxyClient extends TProxyCommon // TickRegistry.registerTickHandler(new TimeTicker(), Side.CLIENT); // TickRegistry.registerTickHandler(new TCommonTickHandler(), // Side.CLIENT); + TickRegistry.registerScheduledTickHandler(new MultiblockServerTickHandler(), Side.SERVER); } /* Registers any rendering code. */ @@ -223,6 +226,9 @@ public class TProxyClient extends TProxyCommon RenderingRegistry.registerBlockHandler(new BlockRenderCastingChannel()); RenderingRegistry.registerBlockHandler(new SlimeChannelRender()); RenderingRegistry.registerBlockHandler(new SlimePadRender()); + RenderingRegistry.registerBlockHandler(new SignalBusRender()); + RenderingRegistry.registerBlockHandler(new SignalTerminalRender()); + if (!PHConstruct.newSmeltery) RenderingRegistry.registerBlockHandler(new SmelteryRender()); diff --git a/src/tconstruct/client/block/SignalBusRender.java b/src/tconstruct/client/block/SignalBusRender.java new file mode 100644 index 00000000..05880f45 --- /dev/null +++ b/src/tconstruct/client/block/SignalBusRender.java @@ -0,0 +1,458 @@ +package tconstruct.client.block; + +import org.lwjgl.opengl.GL11; + +import tconstruct.blocks.logic.CastingChannelLogic; +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.blocks.SignalBus.Geometry; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.ForgeDirection; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; + +public class SignalBusRender implements ISimpleBlockRenderingHandler +{ + public static int renderID = RenderingRegistry.getNextAvailableRenderId(); + +// public static double cable_width_min = 0.375D; +// public static double cable_width_max = 1 - cable_width_min; +// public static double cable_low_height = 0.2D; +// public static double cable_low_offset = 0.0D; +// +// public static double cable_high_height = 1.0D; +// public static double cable_high_offset = 1 - cable_low_height; +// +// public static double cable_extend_min = 0.0D; +// public static double cable_extend_max = 1.0D; +// +// public static double zfight = 0.0000001D; +// + @Override + public void renderInventoryBlock (Block block, int metadata, int modelID, RenderBlocks renderer) + { + //Base + renderer.setRenderBounds(0.375D, 0.0D, 0.375D, 0.625D, 0.2D, 0.625D); + this.renderStandardBlock(block, metadata, renderer); + //Extend Z- + renderer.setRenderBounds(0.375D, 0.0D, 0.0D, 0.625D, 0.2D, 0.375D); + this.renderStandardBlock(block, metadata, renderer); + //Extend Z+ + renderer.setRenderBounds(0.375D, 0.0D, 0.625D, 0.625D, 0.2D, 1D); + this.renderStandardBlock(block, metadata, renderer); + } + + @Override + public boolean renderWorldBlock (IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) + { + boolean[] placedSides; + boolean[] connectedSides; + boolean[] corners; + boolean didRender = false; + if (modelId == renderID) + { + SignalBusLogic tile = (SignalBusLogic) world.getBlockTileEntity(x, y, z); + placedSides = tile.placedSides(); + + for (int i = 0; i < 6; ++i) + { + if (!placedSides[i]){ + continue; + } + didRender = true; + connectedSides = tile.connectedSides(ForgeDirection.getOrientation(i)); + corners = tile.getRenderCorners(ForgeDirection.getOrientation(i)); + + renderFaceWithConnections(renderer, block, x, y, z, i, placedSides, connectedSides, corners); + } + if (!didRender) + { + double minX = Geometry.cable_width_min; + double minY = Geometry.cable_low_offset; + double minZ = Geometry.cable_width_min; + double maxX = Geometry.cable_width_max; + double maxY = Geometry.cable_low_height; + double maxZ = Geometry.cable_width_max; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + + } + return true; + } + + private void renderFaceWithConnections (RenderBlocks renderer, Block block, int x, int y, int z, int side, boolean[] placed, boolean[] connectedSides, boolean[] corners) + { + double minX = 0D; + double minY = 0D; + double minZ = 0D; + double maxX = 1D; + double maxY = 1D; + double maxZ = 1D; + int renderCount = 0; + + boolean[] renderDir = { + (connectedSides[0] || placed[0] || corners[0]), + (connectedSides[1] || placed[1] || corners[1]), + (connectedSides[2] || placed[2] || corners[2]), + (connectedSides[3] || placed[3] || corners[3]), + (connectedSides[4] || placed[4] || corners[4]), + (connectedSides[5] || placed[5] || corners[5]) + }; + + switch (side) + { + case 0: // DOWN + // Render East/West + if (renderDir[ForgeDirection.WEST.ordinal()] || renderDir[ForgeDirection.EAST.ordinal()]) + { + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_low_offset; + minZ = Geometry.cable_width_min; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_low_height; + maxZ = Geometry.cable_width_max; + + maxY += Geometry.zfight; + + minX = (corners[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_corner_min : minX; + maxX = (corners[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_corner_max : maxX; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render North/South + if (renderDir[ForgeDirection.NORTH.ordinal()] || renderDir[ForgeDirection.SOUTH.ordinal()]) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_low_offset; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_low_height; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + minZ = (corners[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_corner_min : minZ; + maxZ = (corners[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_corner_max : maxZ; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_low_offset; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_low_height; + maxZ = Geometry.cable_width_max; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + case 1: // UP + // Render East/West + if (renderDir[ForgeDirection.WEST.ordinal()] || renderDir[ForgeDirection.EAST.ordinal()]) + { + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_high_offset; + minZ = Geometry.cable_width_min; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_high_height; + maxZ = Geometry.cable_width_max; + + minY -= Geometry.zfight; + + minX = (corners[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_corner_min : minX; + maxX = (corners[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_corner_max : maxX; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render North/South + if (renderDir[ForgeDirection.NORTH.ordinal()] || renderDir[ForgeDirection.SOUTH.ordinal()]) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_high_offset; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_high_height; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + minZ = (corners[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_corner_min : minZ; + maxZ = (corners[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_corner_max : maxZ; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_high_offset; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_high_height; + maxZ = Geometry.cable_width_max; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + case 2: // NORTH + // Render East/West + if (renderDir[ForgeDirection.WEST.ordinal()] || renderDir[ForgeDirection.EAST.ordinal()]) + { + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_low_offset; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_low_height; + + maxZ += Geometry.zfight; + + minX = (corners[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_corner_min : minX; + maxX = (corners[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_corner_max : maxX; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render Up/Down + if (renderDir[ForgeDirection.DOWN.ordinal()] || renderDir[ForgeDirection.UP.ordinal()]) + { + minX = Geometry.cable_width_min; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_low_offset; + maxX = Geometry.cable_width_max; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_low_height; + + minY = (corners[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_corner_min : minY; + maxY = (corners[ForgeDirection.UP.ordinal()]) ? Geometry.cable_corner_max : maxY; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_low_offset; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_low_height; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + case 3: // SOUTH + // Render East/West + if (renderDir[ForgeDirection.WEST.ordinal()] || renderDir[ForgeDirection.EAST.ordinal()]) + { + minX = (renderDir[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_high_offset; + maxX = (renderDir[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_high_height; + + minZ -= Geometry.zfight; + + minX = (corners[ForgeDirection.WEST.ordinal()]) ? Geometry.cable_corner_min : minX; + maxX = (corners[ForgeDirection.EAST.ordinal()]) ? Geometry.cable_corner_max : maxX; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render Up/Down + if (renderDir[ForgeDirection.DOWN.ordinal()] || renderDir[ForgeDirection.UP.ordinal()]) + { + minX = Geometry.cable_width_min; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_high_offset; + maxX = Geometry.cable_width_max; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_high_height; + + minY = (corners[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_corner_min : minY; + maxY = (corners[ForgeDirection.UP.ordinal()]) ? Geometry.cable_corner_max : maxY; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_width_min; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_high_offset; + maxX = Geometry.cable_width_max; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_high_height; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + case 4: // WEST + // Render North/South + if (renderDir[ForgeDirection.NORTH.ordinal()] || renderDir[ForgeDirection.SOUTH.ordinal()]) + { + minX = Geometry.cable_low_offset; + minY = Geometry.cable_width_min; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_low_height; + maxY = Geometry.cable_width_max; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + maxX += Geometry.zfight; + + minZ = (corners[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_corner_min : minZ; + maxZ = (corners[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_corner_max : maxZ; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render Up/Down + if (renderDir[ForgeDirection.DOWN.ordinal()] || renderDir[ForgeDirection.UP.ordinal()]) + { + minX = Geometry.cable_low_offset; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_low_height; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_width_max; + + minY = (corners[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_corner_min : minY; + maxY = (corners[ForgeDirection.UP.ordinal()]) ? Geometry.cable_corner_max : maxY; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_low_offset; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_low_height; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_width_max; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + case 5: // EAST + // Render North/South + if (renderDir[ForgeDirection.NORTH.ordinal()] || renderDir[ForgeDirection.SOUTH.ordinal()]) + { + minX = Geometry.cable_high_offset; + minY = Geometry.cable_width_min; + minZ = (renderDir[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + maxX = Geometry.cable_high_height; + maxY = Geometry.cable_width_max; + maxZ = (renderDir[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + + minX -= Geometry.zfight; + + minZ = (corners[ForgeDirection.NORTH.ordinal()]) ? Geometry.cable_corner_min : minZ; + maxZ = (corners[ForgeDirection.SOUTH.ordinal()]) ? Geometry.cable_corner_max : maxZ; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + // Render Up/Down + if (renderDir[ForgeDirection.DOWN.ordinal()] || renderDir[ForgeDirection.UP.ordinal()]) + { + minX = Geometry.cable_high_offset; + minY = (renderDir[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_extend_min : Geometry.cable_width_min; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_high_height; + maxY = (renderDir[ForgeDirection.UP.ordinal()]) ? Geometry.cable_extend_max : Geometry.cable_width_max; + maxZ = Geometry.cable_width_max; + + minY = (corners[ForgeDirection.DOWN.ordinal()]) ? Geometry.cable_corner_min : minY; + maxY = (corners[ForgeDirection.UP.ordinal()]) ? Geometry.cable_corner_max : maxY; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + ++renderCount; + } + if (renderCount == 0) + { + minX = Geometry.cable_high_offset; + minY = Geometry.cable_width_min; + minZ = Geometry.cable_width_min; + maxX = Geometry.cable_high_height; + maxY = Geometry.cable_width_max; + maxZ = Geometry.cable_width_max; + + renderer.setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ); + renderer.renderStandardBlock(block, x, y, z); + } + break; + default: + return; + } + + } + + private void renderStandardBlock (Block block, int meta, RenderBlocks renderer) + { + Tessellator tessellator = Tessellator.instance; + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(0, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(1, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1.0F); + renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(2, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(3, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(4, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(5, meta)); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + + @Override + public boolean shouldRender3DInInventory () + { + // TODO Auto-generated method stub + return true; + } + + @Override + public int getRenderId () + { + return renderID; + } +} diff --git a/src/tconstruct/client/block/SignalTerminalRender.java b/src/tconstruct/client/block/SignalTerminalRender.java new file mode 100644 index 00000000..f9e92f76 --- /dev/null +++ b/src/tconstruct/client/block/SignalTerminalRender.java @@ -0,0 +1,208 @@ +package tconstruct.client.block; + +import org.lwjgl.opengl.GL11; + +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.blocks.logic.SignalTerminalLogic; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.ForgeDirection; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; + +import static tconstruct.blocks.SignalTerminal.TerminalGeometry.*; + +public class SignalTerminalRender implements ISimpleBlockRenderingHandler +{ + public static int renderID = RenderingRegistry.getNextAvailableRenderId(); + + @Override + public void renderInventoryBlock (Block block, int metadata, int modelID, RenderBlocks renderer) + { + // Render X- + renderer.setRenderBounds(plate_low_min, plate_width_min, plate_width_min, plate_low_max, plate_width_max, plate_width_max); + this.renderStandardBlock(block, metadata, renderer); + + renderer.setRenderBounds(center_min, center_min, center_min, center_max, center_max, center_max); + this.renderStandardBlock(block, metadata, renderer); + + renderer.setRenderBounds(channel_low_min, channel_width_min, channel_width_min, channel_low_max, channel_width_max, channel_width_max); + renderer.setOverrideBlockTexture(SignalTerminalLogic.getChannelIcon(0)); + this.renderStandardBlock(block, metadata, renderer); + renderer.clearOverrideBlockTexture(); + } + + @Override + public boolean renderWorldBlock (IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) + { + int sidesRendered = 0; + + if (modelId == renderID) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + if (!(te instanceof SignalTerminalLogic)) + { + // Render X- + renderer.setRenderBounds(plate_low_min, plate_width_min, plate_width_min, plate_low_max, plate_width_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(center_min, center_min, center_min, center_max, center_max, center_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_low_min, channel_width_min, channel_width_min, channel_low_max, channel_width_max, channel_width_max); + renderer.setOverrideBlockTexture(SignalTerminalLogic.getChannelIcon(0)); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + return true; + } + byte[] connectedSides = ((SignalTerminalLogic) te).getConnectedSides(); + Icon channelIcons[] = ((SignalTerminalLogic) te).getSideIcons(); + + // Center + renderer.setRenderBounds(center_min, center_min, center_min, center_max, center_max, center_max); + renderer.renderStandardBlock(block, x, y, z); + + if (connectedSides[ForgeDirection.WEST.ordinal()] != -1) + { + // Render X- + renderer.setRenderBounds(plate_low_min, plate_width_min, plate_width_min, plate_low_max, plate_width_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_low_min, channel_width_min, channel_width_min, channel_low_max, channel_width_max, channel_width_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.WEST.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + if (connectedSides[ForgeDirection.EAST.ordinal()] != -1) + { + //Extend X+ + renderer.setRenderBounds(plate_high_min, plate_width_min, plate_width_min, plate_high_max, plate_width_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_high_min, channel_width_min, channel_width_min, channel_high_max, channel_width_max, channel_width_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.EAST.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + if (connectedSides[ForgeDirection.SOUTH.ordinal()] != -1) + { + //Extend Z- + renderer.setRenderBounds(plate_width_min, plate_width_min, plate_low_min, plate_width_max, plate_width_max, plate_low_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_width_min, channel_width_min, channel_low_min, channel_width_max, channel_width_max, channel_low_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.SOUTH.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + if (connectedSides[ForgeDirection.NORTH.ordinal()] != -1) + { + //Extend Z+ + renderer.setRenderBounds(plate_width_min, plate_width_min, plate_high_min, plate_width_max, plate_width_max, plate_high_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_width_min, channel_width_min, channel_high_min, channel_width_max, channel_width_max, channel_high_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.NORTH.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + if (connectedSides[ForgeDirection.DOWN.ordinal()] != -1) + { + //Extend Y- + renderer.setRenderBounds(plate_width_min, plate_low_min, plate_width_min, plate_width_max, plate_low_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_width_min, channel_low_min, channel_width_min, channel_width_max, channel_low_max, channel_width_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.DOWN.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + if (connectedSides[ForgeDirection.UP.ordinal()] != -1) + { + //Extend Y+ + renderer.setRenderBounds(plate_width_min, plate_high_min, plate_width_min, plate_width_max, plate_high_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_width_min, channel_high_min, channel_width_min, channel_width_max, channel_high_max, channel_width_max); + renderer.setOverrideBlockTexture(channelIcons[ForgeDirection.UP.ordinal()]); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + sidesRendered++; + } + + if (sidesRendered == 0) + { + // Render X- + renderer.setRenderBounds(plate_low_min, plate_width_min, plate_width_min, plate_low_max, plate_width_max, plate_width_max); + renderer.renderStandardBlock(block, x, y, z); + + renderer.setRenderBounds(channel_low_min, channel_width_min, channel_width_min, channel_low_max, channel_width_max, channel_width_max); + renderer.setOverrideBlockTexture(SignalTerminalLogic.getChannelIcon(0)); + renderer.renderStandardBlock(block, x, y, z); + renderer.clearOverrideBlockTexture(); + + } + return true; + } + return false; + } + + private void renderStandardBlock (Block block, int meta, RenderBlocks renderer) + { + Tessellator tessellator = Tessellator.instance; + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(0, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(1, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1.0F); + renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(2, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(3, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, block.getIcon(4, meta)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, block.getIcon(5, meta)); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + + @Override + public boolean shouldRender3DInInventory () + { + return true; + } + + @Override + public int getRenderId () + { + return this.renderID; + } +} diff --git a/src/tconstruct/common/SpoolRepairRecipe.java b/src/tconstruct/common/SpoolRepairRecipe.java new file mode 100644 index 00000000..d9bd1e52 --- /dev/null +++ b/src/tconstruct/common/SpoolRepairRecipe.java @@ -0,0 +1,102 @@ +package tconstruct.common; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.world.World; + +public class SpoolRepairRecipe implements IRecipe +{ + ItemStack spool; + ItemStack wire; + + public SpoolRepairRecipe(ItemStack spool, ItemStack wire) + { + this.spool = spool.copy(); + this.spool.setItemDamage(256); + this.wire = wire.copy(); + } + @Override + public boolean matches (InventoryCrafting inventorycrafting, World world) + { + int invLength = inventorycrafting.getSizeInventory(); + boolean foundSpool = false; + int countWire = 0; + ItemStack tmpStack; + for (int i = 0; i < invLength; ++i) + { + tmpStack = inventorycrafting.getStackInSlot(i); + if (tmpStack instanceof ItemStack) + { + if (tmpStack.itemID == spool.itemID) + { + if (foundSpool) + { + return false; + } + foundSpool = true; + } + else if (tmpStack.itemID == wire.itemID && tmpStack.getItemDamage() == wire.getItemDamage()) + { + ++countWire; + } + else + { + return false; + } + } + if (countWire > 0 && foundSpool) + { + return true; + } + } + + return false; + } + + @Override + public ItemStack getCraftingResult (InventoryCrafting inventorycrafting) + { + int invLength = inventorycrafting.getSizeInventory(); + boolean foundSpool = false; + ItemStack newSpool = null; + int countWire = 0; + ItemStack tmpStack; + for (int i = 0; i < invLength; ++i) + { + tmpStack = inventorycrafting.getStackInSlot(i); + if (tmpStack instanceof ItemStack) + { + if (tmpStack.itemID == spool.itemID) + { + newSpool = tmpStack.copy(); + foundSpool = true; + } + else if (tmpStack.itemID == wire.itemID && tmpStack.getItemDamage() == wire.getItemDamage()) + { + ++countWire; + } + } + } + if (countWire > 0 && newSpool != null) + { + newSpool.setItemDamage(newSpool.getItemDamage() - countWire); + } + + return newSpool; + } + + @Override + public int getRecipeSize () + { + // TODO Auto-generated method stub + return 9; + } + + @Override + public ItemStack getRecipeOutput () + { + return spool.copy(); + } + +} diff --git a/src/tconstruct/common/TContent.java b/src/tconstruct/common/TContent.java index 315bfd4c..dcf7fb40 100644 --- a/src/tconstruct/common/TContent.java +++ b/src/tconstruct/common/TContent.java @@ -279,6 +279,13 @@ public class TContent implements IFuelHandler public static Item leggingsWood; public static Item bootsWood; public static EnumArmorMaterial materialWood; + + //Signal & Logic + public static Block signalBus; + public static Block signalTerminal; + + public static Item spoolWire; + public static Item lengthWire; //Temporary items //public static Item armorTest = new ArmorStandard(2445, 4, EnumArmorPart.HELMET).setCreativeTab(CreativeTabs.tabAllSearch); @@ -825,6 +832,16 @@ public class TContent implements IFuelHandler //Rail woodenRail = new WoodRail(PHConstruct.woodenRail).setStepSound(Block.soundWoodFootstep).setCreativeTab(TConstructRegistry.blockTab).setUnlocalizedName("rail.wood"); GameRegistry.registerBlock(woodenRail, "rail.wood"); + + //Signal & Logic + signalBus = (new SignalBus(PHConstruct.signalBus)).setUnlocalizedName("tconstruct.signalbus"); + GameRegistry.registerBlock(signalBus, SignalBusItem.class, "SignalBus"); + GameRegistry.registerTileEntity(SignalBusLogic.class, "SignalBus"); + + signalTerminal = (new SignalTerminal(PHConstruct.signalTerminal)).setUnlocalizedName("tconstruct.signalterminal"); + GameRegistry.registerBlock(signalTerminal, SignalTerminalItem.class, "SignalTerminal"); + GameRegistry.registerTileEntity(SignalTerminalLogic.class, "SignalTerminal"); + } void registerItems () @@ -964,6 +981,9 @@ public class TContent implements IFuelHandler leggingsWood = new ArmorBasic(PHConstruct.woodPants, materialWood, 2, "wood").setUnlocalizedName("tconstruct.leggingsWood"); bootsWood = new ArmorBasic(PHConstruct.woodBoots, materialWood, 3, "wood").setUnlocalizedName("tconstruct.bootsWood"); + spoolWire = new SpoolOfWire(PHConstruct.spoolWire).setUnlocalizedName("spoolwire"); + lengthWire = new LengthWire(PHConstruct.lengthWire).setUnlocalizedName("lengthwire"); + // essenceCrystal = new EssenceCrystal(PHConstruct.essenceCrystal).setUnlocalizedName("tconstruct.crystal.essence"); String[] materialStrings = { "paperStack", "greenSlimeCrystal", "searedBrick", "ingotCobalt", "ingotArdite", "ingotManyullyn", "mossBall", "lavaCrystal", "necroticBone", "ingotCopper", @@ -989,7 +1009,10 @@ public class TContent implements IFuelHandler TConstructRegistry.addItemStackToDirectory("canisterEmpty", new ItemStack(heartCanister, 1, 0)); TConstructRegistry.addItemStackToDirectory("miniRedHeart", new ItemStack(heartCanister, 1, 1)); TConstructRegistry.addItemStackToDirectory("canisterRedHeart", new ItemStack(heartCanister, 1, 2)); - + + TConstructRegistry.addItemStackToDirectory("spoolWire", new ItemStack(spoolWire, 1, 0)); + TConstructRegistry.addItemStackToDirectory("lengthWire", new ItemStack(lengthWire, 1, 0)); + //Vanilla stack sizes Item.doorWood.setMaxStackSize(16); Item.doorIron.setMaxStackSize(16); @@ -1341,6 +1364,13 @@ public class TContent implements IFuelHandler GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(landmine, 1, 3), "mcm", "rpr", 'm', Item.redstoneRepeater, 'c', new ItemStack(blankPattern, 1, 1), 'r', Item.redstone, 'p', Block.pressurePlateStone)); + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(signalBus.blockID, 1, 0), "www", "sss", 'w', lengthWire, 's', new ItemStack(Block.stoneSingleSlab, 1, OreDictionary.WILDCARD_VALUE))); + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(signalTerminal.blockID, 1, 0), "b", "g", "b", 'b', new ItemStack(signalBus.blockID, 1, 0), 'g', new ItemStack(Block.glass, 1, OreDictionary.WILDCARD_VALUE))); + + GameRegistry.addRecipe(new ItemStack(lengthWire, 8), "a", "a", 'a', aluBrass); + GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(spoolWire, 1, 256 - 8), "www", "wrw", "www", 'w', lengthWire, 'r', "stoneRod")); + GameRegistry.addRecipe(new SpoolRepairRecipe(new ItemStack(spoolWire, 1, 256), new ItemStack(lengthWire, 1))); + //Ultra hardcore recipes Object goldType = null; RecipeRemover.removeShapedRecipe(new ItemStack(Item.appleGold)); @@ -1463,7 +1493,7 @@ public class TContent implements IFuelHandler patternOutputs = new Item[] { toolRod, pickaxeHead, shovelHead, hatchetHead, swordBlade, wideGuard, handGuard, crossbar, binding, frypanHead, signHead, knifeBlade, chiselHead, toughRod, toughBinding, largePlate, broadAxeHead, scytheBlade, excavatorHead, largeSwordBlade, hammerHead, fullGuard, null, null, arrowhead }; - int[] nonMetals = { 0, 1, 3, 4, 5, 6, 7, 8, 9, 17 }; + int[] nonMetals = { 0, 1, 3, 4, 5, 6, 7, 8, 9 }; if (PHConstruct.craftMetalTools) { @@ -1597,6 +1627,7 @@ public class TContent implements IFuelHandler //Buckets ItemStack bucket = new ItemStack(Item.bucketEmpty); + for (int sc = 0; sc < 24; sc++) { tableCasting.addCastingRecipe(new ItemStack(buckets, 1, sc), new FluidStack(fluids[sc], FluidContainerRegistry.BUCKET_VOLUME), bucket, true, 10); @@ -1732,6 +1763,7 @@ public class TContent implements IFuelHandler Smeltery.addMelting(FluidType.Steel, new ItemStack(toolShard, 1, 16), 0, TConstruct.chunkLiquidValue); // Items + Smeltery.addMelting(FluidType.AluminumBrass, new ItemStack(blankPattern, 4, 1), -50, TConstruct.ingotLiquidValue); Smeltery.addMelting(FluidType.Gold, new ItemStack(blankPattern, 4, 1), -50, TConstruct.ingotLiquidValue); @@ -2002,7 +2034,7 @@ public class TContent implements IFuelHandler ensureOreIsRegistered("stoneMossy", new ItemStack(Block.stoneBrick, 1, 1)); ensureOreIsRegistered("stoneMossy", new ItemStack(Block.cobblestoneMossy)); - + ensureOreIsRegistered("crafterWood", new ItemStack(Block.workbench, 1)); String[] matNames = { "wood", "stone", "iron", "flint", "cactus", "bone", "obsidian", "netherrack", "slime", "paper", "cobalt", "ardite", "manyullyn", "copper", "bronze", "alumite", "steel", diff --git a/src/tconstruct/common/TProxyCommon.java b/src/tconstruct/common/TProxyCommon.java index 06a2789f..4fa9f1c8 100644 --- a/src/tconstruct/common/TProxyCommon.java +++ b/src/tconstruct/common/TProxyCommon.java @@ -2,6 +2,8 @@ package tconstruct.common; import cpw.mods.fml.common.network.IGuiHandler; import cpw.mods.fml.common.registry.LanguageRegistry; +import cpw.mods.fml.common.registry.TickRegistry; +import cpw.mods.fml.relauncher.Side; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; import net.minecraft.world.World; @@ -9,6 +11,7 @@ import tconstruct.TConstruct; import tconstruct.blocks.logic.TileEntityLandmine; import tconstruct.inventory.*; import tconstruct.library.blocks.InventoryLogic; +import tconstruct.library.multiblock.MultiblockServerTickHandler; import tconstruct.util.player.TPlayerStats; /** @@ -85,6 +88,7 @@ public class TProxyCommon implements IGuiHandler public void registerTickHandler () { //TickRegistry.registerTickHandler(new TimeTicker(), Side.SERVER); + TickRegistry.registerScheduledTickHandler(new MultiblockServerTickHandler(), Side.SERVER); } /* Registers any rendering code. Does nothing server-side */ diff --git a/src/tconstruct/items/LengthWire.java b/src/tconstruct/items/LengthWire.java new file mode 100644 index 00000000..a5255301 --- /dev/null +++ b/src/tconstruct/items/LengthWire.java @@ -0,0 +1,58 @@ +package tconstruct.items; + +import java.util.List; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import tconstruct.library.TConstructRegistry; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Icon; +import net.minecraft.util.MathHelper; + +public class LengthWire extends Item +{ + public String[] textureNames = new String[] { "lengthwire" }; + public String[] unlocalizedNames = new String[] { "lengthwire" }; + public String folder = "logic/"; + public Icon[] icons; + + + public LengthWire(int id) + { + super(id); + this.setCreativeTab(TConstructRegistry.toolTab); + this.maxStackSize = 64; + this.setHasSubtypes(false); + } + + + @SideOnly(Side.CLIENT) + public Icon getIconFromDamage (int meta) + { + int arr = MathHelper.clamp_int(meta, 0, unlocalizedNames.length); + return icons[arr]; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons (IconRegister iconRegister) + { + this.icons = new Icon[textureNames.length]; + + for (int i = 0; i < this.icons.length; ++i) + { + if (!(textureNames[i].equals(""))) + this.icons[i] = iconRegister.registerIcon("tinker:" + folder + textureNames[i]); + } + } + + public void getSubItems (int id, CreativeTabs tab, List list) + { + for (int i = 0; i < unlocalizedNames.length; i++) + if (!(textureNames[i].equals(""))) + list.add(new ItemStack(id, 1, i)); + } +} diff --git a/src/tconstruct/items/SpoolOfWire.java b/src/tconstruct/items/SpoolOfWire.java new file mode 100644 index 00000000..342878c2 --- /dev/null +++ b/src/tconstruct/items/SpoolOfWire.java @@ -0,0 +1,145 @@ +package tconstruct.items; + +import java.util.List; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import tconstruct.blocks.logic.SignalBusLogic; +import tconstruct.blocks.logic.SignalTerminalLogic; +import tconstruct.library.TConstructRegistry; +import net.minecraft.client.renderer.texture.IconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Icon; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; + +public class SpoolOfWire extends Item +{ + public String textureName = "spoolwire"; + public String unlocalizedName = "spoolwire"; + public String folder = "logic/"; + public Icon icon; + + public SpoolOfWire(int id) + { + super(id); + this.setCreativeTab(TConstructRegistry.toolTab); + this.maxStackSize = 1; + this.setMaxDamage(256); + this.setHasSubtypes(true); + } + + @Override + public ItemStack getContainerItemStack (ItemStack itemStack) + { + return new ItemStack(this.itemID, 1, this.getMaxDamage()); + } + + @Override + @SideOnly(Side.CLIENT) + public void addInformation (ItemStack stack, EntityPlayer player, List list, boolean par4) + { + switch (stack.getItemDamage()) + { + case 0: + list.add("Wirey!"); + break; + } + } + + public String getUnlocalizedName (ItemStack stack) + { + return "item." + unlocalizedName; + } + + @Override + public boolean onItemUse (ItemStack itemstack, EntityPlayer player, World world, int x, int y, int z, int par7, float par8, float par9, float par10) + { + TileEntity te = world.getBlockTileEntity(x, y, z); + NBTTagCompound data = itemstack.stackTagCompound; + NBTTagCompound spoolData = null; + + if (world.isRemote) + { + return false; + } + + if (data == null) + { + data = new NBTTagCompound(); + itemstack.stackTagCompound = data; + } + if (te != null && te instanceof SignalBusLogic) + { + if (data.hasKey("spoolWireData")) + { + spoolData = data.getCompoundTag("spoolWireData"); + + int targetDim = spoolData.getInteger("targetDim"); + int targetX = spoolData.getInteger("targetX"); + int targetY = spoolData.getInteger("targetY"); + int targetZ = spoolData.getInteger("targetZ"); + + int calc = Math.abs(targetX - x) + Math.abs(targetY - y) + Math.abs(targetZ - z); + if ((itemstack.getMaxDamage() - itemstack.getItemDamage()) < calc) + { + return false; + } + if (targetDim == world.provider.dimensionId && calc < 16) + { + ((SignalBusLogic) te).registerTerminal(world, targetX, targetY, targetZ, true); + data.removeTag("spoolWireData"); + + itemstack.damageItem(calc, player); + return true; + } + } + + return false; + } + if (te != null && te instanceof SignalTerminalLogic) + { + data = itemstack.stackTagCompound; + spoolData = null; + if (data.hasKey("spoolWireData")) + { + data.removeTag("spoolWireData"); + } + spoolData = new NBTTagCompound(); + + spoolData.setInteger("targetDim", world.provider.dimensionId); + spoolData.setInteger("targetX", x); + spoolData.setInteger("targetY", y); + spoolData.setInteger("targetZ", z); + + data.setCompoundTag("spoolWireData", spoolData); + + return true; + } + + return false; + } + + @SideOnly(Side.CLIENT) + public Icon getIconFromDamage (int meta) + { + return icon; + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons (IconRegister iconRegister) + { + this.icon = iconRegister.registerIcon("tinker:" + folder + textureName); + } + + public void getSubItems (int id, CreativeTabs tab, List list) + { + list.add(new ItemStack(id, 1, 0)); + } +} diff --git a/src/tconstruct/items/blocks/SignalBusItem.java b/src/tconstruct/items/blocks/SignalBusItem.java new file mode 100644 index 00000000..506863ce --- /dev/null +++ b/src/tconstruct/items/blocks/SignalBusItem.java @@ -0,0 +1,167 @@ +package tconstruct.items.blocks; + +import java.util.List; + +import tconstruct.blocks.logic.SignalBusLogic; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +public class SignalBusItem extends ItemBlock +{ + public static final String blockType[] = { "signalbus" }; + + public SignalBusItem(int id) + { + super(id); + this.maxStackSize = 64; + this.setHasSubtypes(false); + } + + public int getMetadata (int meta) + { + return meta; + } + + public String getUnlocalizedName (ItemStack itemstack) + { + int pos = MathHelper.clamp_int(itemstack.getItemDamage(), 0, blockType.length - 1); + return (new StringBuilder()).append("tile.").append(blockType[pos]).toString(); + } + + + @Override + @SideOnly(Side.CLIENT) + public boolean canPlaceItemBlockOnSide (World world, int x, int y, int z, int side, EntityPlayer entityPlayer, ItemStack itemStack) + { + return super.canPlaceItemBlockOnSide(world, x, y, z, side, entityPlayer, itemStack) || _canPlaceItemBlockOnSide(world, x, y, z, side); + } + + @Override + public boolean onItemUse (ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) + { + int tmpX = x; + int tmpY = y; + int tmpZ = z; + + switch (side) + { + case 0: + tmpY += -1; + break; + case 1: + tmpY += 1; + break; + case 2: + tmpZ += -1; + break; + case 3: + tmpZ += 1; + break; + case 4: + tmpX += -1; + break; + case 5: + tmpX += 1; + break; + default: + break; + } + + int tside = side; + switch (side) + { + case 0: // DOWN + case 1: // UP + case 2: // NORTH + case 3: // SOUTH + case 4: // EAST + case 5: // WEST + tside = ForgeDirection.OPPOSITES[side]; + break; + default: + tside = side; + break; + } + + NBTTagCompound data = new NBTTagCompound(); + stack.stackTagCompound = data; + data.setInteger("connectedSide", tside); + + if (super.onItemUse(stack, player, world, x, y, z, side, hitX, hitY, hitZ)) + { + stack.stackTagCompound = null; + return true; + } + + if (!(_canPlaceItemBlockOnSide(world, x, y, z, side))) + { + return false; + } + + TileEntity te = world.getBlockTileEntity(tmpX, tmpY, tmpZ); + + ((SignalBusLogic) te).addPlacedSide(tside); + + stack.stackTagCompound = null; + + --stack.stackSize; + + world.markBlockForRenderUpdate(x, y, z); + + return true; + + } + + private boolean _canPlaceItemBlockOnSide (World world, int x, int y, int z, int side) + { + int tmpX = x; + int tmpY = y; + int tmpZ = z; + + switch (side) + { + case 0: + tmpY += -1; + break; + case 1: + tmpY += 1; + break; + case 2: + tmpZ += -1; + break; + case 3: + tmpZ += 1; + break; + case 4: + tmpX += -1; + break; + case 5: + tmpX += 1; + break; + default: + break; + } + + if (world.getBlockId(tmpX, tmpY, tmpZ) == this.getBlockID()) + { + TileEntity te = world.getBlockTileEntity(tmpX, tmpY, tmpZ); + if (te == null || !(te instanceof SignalBusLogic)) + { + return false; + } + + return true; + } + + return false; + } +} diff --git a/src/tconstruct/items/blocks/SignalTerminalItem.java b/src/tconstruct/items/blocks/SignalTerminalItem.java new file mode 100644 index 00000000..47100225 --- /dev/null +++ b/src/tconstruct/items/blocks/SignalTerminalItem.java @@ -0,0 +1,176 @@ +package tconstruct.items.blocks; + +import java.util.List; + +import tconstruct.blocks.logic.SignalTerminalLogic; +import tconstruct.library.TConstructRegistry; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +public class SignalTerminalItem extends ItemBlock +{ + public static final String blockType[] = { "signalterminal" }; + + public SignalTerminalItem(int id) + { + super(id); + this.maxStackSize = 64; + this.setHasSubtypes(false); + } + + public int getMetadata (int meta) + { + return meta; + } + + public String getUnlocalizedName (ItemStack itemstack) + { + int pos = MathHelper.clamp_int(itemstack.getItemDamage(), 0, blockType.length - 1); + return (new StringBuilder()).append("tile.").append(blockType[pos]).toString(); + } + + @Override + public boolean placeBlockAt (ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ, int metadata) + { + return super.placeBlockAt(stack, player, world, x, y, z, side, hitX, hitY, hitZ, metadata); + } + + @Override + @SideOnly(Side.CLIENT) + public boolean canPlaceItemBlockOnSide (World world, int x, int y, int z, int side, EntityPlayer entityPlayer, ItemStack itemStack) + { + if (super.canPlaceItemBlockOnSide(world, x, y, z, side, entityPlayer, itemStack) || _canPlaceItemBlockOnSide(world, x, y, z, side)) + { + return true; + } + + return false; + } + + @Override + public boolean onItemUse (ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) + { + int tmpX = x; + int tmpY = y; + int tmpZ = z; + + switch (side) + { + case 0: + tmpY += -1; + break; + case 1: + tmpY += 1; + break; + case 2: + tmpZ += -1; + break; + case 3: + tmpZ += 1; + break; + case 4: + tmpX += -1; + break; + case 5: + tmpX += 1; + break; + default: + break; + } + + int tside = side; + switch (side) + { + case 0: // DOWN + case 1: // UP + case 4: // EAST + case 5: // WEST + tside = ForgeDirection.OPPOSITES[side]; + break; + default: + tside = side; + break; + } + NBTTagCompound data = new NBTTagCompound(); + stack.stackTagCompound = data; + data.setInteger("connectedSide", tside); + + if (super.onItemUse(stack, player, world, x, y, z, side, hitX, hitY, hitZ)) + { + return true; + } + + if (!(_canPlaceItemBlockOnSide(world, x, y, z, side))) + { + return false; + } + + TileEntity te = world.getBlockTileEntity(tmpX, tmpY, tmpZ); + + ((SignalTerminalLogic) te).addPendingSide(tside); + ((SignalTerminalLogic) te).connectPending(); + + stack.stackTagCompound = null; + + --stack.stackSize; + + world.markBlockForRenderUpdate(x, y, z); + + return true; + + } + + private boolean _canPlaceItemBlockOnSide (World world, int x, int y, int z, int side) + { + int tmpX = x; + int tmpY = y; + int tmpZ = z; + + switch (side) + { + case 0: + tmpY += -1; + break; + case 1: + tmpY += 1; + break; + case 2: + tmpZ += -1; + break; + case 3: + tmpZ += 1; + break; + case 4: + tmpX += -1; + break; + case 5: + tmpX += 1; + break; + default: + break; + } + + if (world.getBlockId(tmpX, tmpY, tmpZ) == this.getBlockID()) + { + TileEntity te = world.getBlockTileEntity(tmpX, tmpY, tmpZ); + if (te == null || !(te instanceof SignalTerminalLogic)) + { + return false; + } + + return true; + } + + return false; + } +} diff --git a/src/tconstruct/library/component/ISignalBusConnectable.java b/src/tconstruct/library/component/ISignalBusConnectable.java new file mode 100644 index 00000000..1e4206fd --- /dev/null +++ b/src/tconstruct/library/component/ISignalBusConnectable.java @@ -0,0 +1,10 @@ +package tconstruct.library.component; + +import net.minecraftforge.common.ForgeDirection; + +public interface ISignalBusConnectable +{ + public boolean connectableOnFace (ForgeDirection side); + + public boolean connectableOnCorner (ForgeDirection side, ForgeDirection turn); +} diff --git a/src/tconstruct/library/multiblock/BlockMultiblock.java b/src/tconstruct/library/multiblock/BlockMultiblock.java new file mode 100644 index 00000000..f86c8066 --- /dev/null +++ b/src/tconstruct/library/multiblock/BlockMultiblock.java @@ -0,0 +1,20 @@ +package tconstruct.library.multiblock; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockContainer; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public abstract class BlockMultiblock extends BlockContainer +{ + + protected BlockMultiblock(int par1, Material par2Material) + { + super(par1, par2Material); + } + + @Override + public abstract TileEntity createNewTileEntity (World world); + +} diff --git a/src/tconstruct/library/multiblock/IMultiblockMember.java b/src/tconstruct/library/multiblock/IMultiblockMember.java new file mode 100644 index 00000000..021cfe9e --- /dev/null +++ b/src/tconstruct/library/multiblock/IMultiblockMember.java @@ -0,0 +1,52 @@ +package tconstruct.library.multiblock; + +import net.minecraft.world.World; +import tconstruct.library.util.CoordTuple; + +public interface IMultiblockMember +{ + + public boolean isCompatible (Object other); + + public boolean isConnected (); + + public MultiblockMasterBaseLogic getMultiblockMaster (); + + public CoordTuple getCoordInWorld (); + + public void onAttached (MultiblockMasterBaseLogic newMaster); + + public void onDetached (MultiblockMasterBaseLogic oldMaster); + + public void createNewMultiblock (); + + public MultiblockMasterBaseLogic getNewMultiblockMasterObject (); + + public void onMasterMerged (MultiblockMasterBaseLogic newMaster); + + public void setVisited (); + + public void setUnivisted (); + + public boolean isVisited (); + + public void becomeMultiblockSaveDelegate (); + + public void forfeitMultiblockSaveDelegate (); + + public boolean isMultiblockSaveDelegate (); + + public IMultiblockMember[] getNeighboringMembers (); + + public void onBlockAdded (World world, int x, int y, int z); + + public void onChunkLoad (); + + public void onOrphaned (); + + public void onChunkUnloaded (); + + public World getWorldObj (); + + public boolean willConnect (CoordTuple coord); +} diff --git a/src/tconstruct/library/multiblock/MultiblockBaseLogic.java b/src/tconstruct/library/multiblock/MultiblockBaseLogic.java new file mode 100644 index 00000000..c4488f2e --- /dev/null +++ b/src/tconstruct/library/multiblock/MultiblockBaseLogic.java @@ -0,0 +1,395 @@ +package tconstruct.library.multiblock; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import tconstruct.library.util.CoordTuple; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.INetworkManager; +import net.minecraft.network.packet.Packet132TileEntityData; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; + +public abstract class MultiblockBaseLogic extends TileEntity implements IMultiblockMember +{ + + private MultiblockMasterBaseLogic master; + private byte visited; + private static final byte kUnvisited = 0; + private static final byte kVisited = 1; + + private boolean saveMultiblockData; + private NBTTagCompound cachedMultiblockData; + private boolean doUpdate; + + public MultiblockBaseLogic() + { + super(); + master = null; + visited = kUnvisited; + saveMultiblockData = false; + doUpdate = false; + cachedMultiblockData = null; + } + + public boolean isCompatible (Object other) + { + return other.getClass().equals(this.getClass()); + } + + public void doMultiblockTick () + { + } + + @Override + public boolean isConnected () + { + return (master != null); + } + + @Override + public boolean willConnect (CoordTuple coord) + { + return true; + } + + @Override + public MultiblockMasterBaseLogic getMultiblockMaster () + { + return master; + } + + @Override + public CoordTuple getCoordInWorld () + { + return new CoordTuple(this.xCoord, this.yCoord, this.zCoord); + } + + @Override + public void onAttached (MultiblockMasterBaseLogic newMaster) + { + this.master = newMaster; + } + + @Override + public void onDetached (MultiblockMasterBaseLogic oldMaster) + { + if (this.master != oldMaster) + { + throw new IllegalArgumentException("Detaching from wrong master"); + } + + this.master = null; + } + + @Override + public void createNewMultiblock () + { + MultiblockMasterBaseLogic newMaster = getNewMultiblockMasterObject(); + newMaster.attachBlock(this); + } + + @Override + public void onMasterMerged (MultiblockMasterBaseLogic newMaster) + { + assert (this.master != newMaster); + + this.master = newMaster; + } + + @Override + public void setVisited () + { + this.visited = kVisited; + } + + @Override + public void setUnivisted () + { + this.visited = kUnvisited; + } + + @Override + public boolean isVisited () + { + return this.visited != kUnvisited; + } + + @Override + public void becomeMultiblockSaveDelegate () + { + this.saveMultiblockData = true; + } + + @Override + public void forfeitMultiblockSaveDelegate () + { + this.saveMultiblockData = false; + } + + @Override + public boolean isMultiblockSaveDelegate () + { + return this.saveMultiblockData; + } + + @Override + public IMultiblockMember[] getNeighboringMembers () + { + CoordTuple[] neighbors = getNeighborCoords(); + TileEntity te; + List neighborMembers = new LinkedList(); + for (CoordTuple neighbor : neighbors) + { + te = this.worldObj.getBlockTileEntity(neighbor.x, neighbor.y, neighbor.z); + if (te instanceof IMultiblockMember) + { + // Verify compatible member + if (((IMultiblockMember) te).isCompatible((Object) this) && ((IMultiblockMember) te).willConnect(getCoordInWorld())) + { + neighborMembers.add((IMultiblockMember) te); + } + } + } + IMultiblockMember[] tmp = new IMultiblockMember[neighborMembers.size()]; + return neighborMembers.toArray(tmp); + } + + @Override + public void onBlockAdded (World world, int x, int y, int z) + { + IMultiblockMember[] neighbors = getNeighboringMembers(); + + List masters = new LinkedList(); + + for (IMultiblockMember neighbor : neighbors) + { + if (neighbor.isConnected() && !masters.contains(neighbor.getMultiblockMaster())) + { + masters.add(neighbor.getMultiblockMaster()); + } + } + + if (masters.size() > 0) + { + MultiblockMasterBaseLogic targetMaster = null; + + for (MultiblockMasterBaseLogic candidateMaster : masters) + { + if (targetMaster == null) + { + targetMaster = candidateMaster; + } + else + { + int comparison = targetMaster.getReferenceCoord().compareTo(candidateMaster.getReferenceCoord()); + if (comparison < 0) + { + continue; + } + else if (comparison == 0) + { + throw new IllegalStateException(String.format("Found two controllers (hashes %d, %d) with identical reference coord %s", targetMaster.hashCode(), candidateMaster.hashCode(), + targetMaster.getReferenceCoord().toString())); + } + else + { + targetMaster = candidateMaster; + } + } + } + + assert (targetMaster != null); + + masters.remove(targetMaster); + targetMaster.attachBlock(this); + + if (masters.size() > 0) + { + CoordTuple hostLoc = this.master.getReferenceCoord(); + this.master.beginMerging(); + for (MultiblockMasterBaseLogic masterToMerge : masters) + { + this.master.merge(masterToMerge); + } + this.master.endMerging(); + } + } + else + { + this.createNewMultiblock(); + } + } + + @Override + public void onOrphaned () + { + if (this.isConnected()) + { + // Turns out, we're not an orphan after all + return; + } + + createNewMultiblock(); + // Now for fun. Add all neighbors and DFS out into the world. + Queue membersToCheck = new LinkedList(); + // Add all unconnected neighbors + CoordTuple[] neighborCoords = getNeighborCoords(); + for (CoordTuple coord : neighborCoords) + { + TileEntity neighborTE = this.worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (neighborTE instanceof IMultiblockMember && !((IMultiblockMember) neighborTE).isConnected() && ((IMultiblockMember) neighborTE).willConnect(getCoordInWorld())) + { + membersToCheck.add((IMultiblockMember) neighborTE); + } + } + + IMultiblockMember member; + while (!membersToCheck.isEmpty()) + { + member = membersToCheck.remove(); + if (member.isConnected()) + { + // This member has better things to do + continue; + } + + // We're already connected by virtue of the new master + this.master.attachBlock(member); + + // Add all unconnected neighbors of this member + IMultiblockMember[] neighborMembers = member.getNeighboringMembers(); + for (IMultiblockMember neighbor : neighborMembers) + { + if (!neighbor.isConnected()) + { + membersToCheck.add(neighbor); + } + } + } + } + + @Override + public void readFromNBT (NBTTagCompound data) + { + super.readFromNBT(data); + + // We can't directly initialize a multiblock master yet, so we cache the data here until + // we receive a validate() call, which creates the controller and hands off the cached data. + if (data.hasKey("multiblockData")) + { + this.cachedMultiblockData = data.getCompoundTag("multiblockData"); + } + } + + @Override + public void writeToNBT (NBTTagCompound data) + { + super.writeToNBT(data); + + if (this.saveMultiblockData) + { + NBTTagCompound multiblockData = new NBTTagCompound(); + this.master.writeToNBT(multiblockData); + data.setCompoundTag("multiblockData", multiblockData); + } + } + + // Ignore Vanilla TE updates + @Override + public boolean canUpdate () + { + return false; + } + + @Override + public void invalidate () + { + super.invalidate(); + + detachSelf(false); + } + + @Override + public void onChunkUnload () + { + super.onChunkUnload(); + + if (this.worldObj.isRemote) + { + detachSelf(true); + } + } + + @Override + public void onChunkLoad () + { + if (this.cachedMultiblockData != null) + { + // We need to create a multiblock BUT we cannot check the world yet. + // So we do something stupid and special. + MultiblockMasterBaseLogic newMaster = getNewMultiblockMasterObject(); + newMaster.restore(this.cachedMultiblockData); + this.cachedMultiblockData = null; + newMaster.attachBlock(this); // This should grab any other connected blocks in the chunk + } + else + { + if (!this.isConnected()) + { + // Ignore blocks that are already connected + this.onBlockAdded(this.worldObj, xCoord, yCoord, zCoord); + } + } + } + + @Override + public void onChunkUnloaded () + { + detachSelf(true); + } + + @Override + public void validate () + { + super.validate(); + + if (!this.worldObj.isRemote) + { + MultiblockRegistry.registerMember(this.worldObj, ChunkCoordIntPair.chunkXZ2Int(xCoord >> 4, zCoord >> 4), this); + + if (!this.worldObj.getChunkProvider().chunkExists(xCoord >> 4, zCoord >> 4)) + { + boolean master = this.cachedMultiblockData != null; + MultiblockRegistry.onMemberLoad(this.worldObj, ChunkCoordIntPair.chunkXZ2Int(xCoord >> 4, zCoord >> 4), this, master); + } + } + } + + @Override + public abstract MultiblockMasterBaseLogic getNewMultiblockMasterObject (); + + protected void attachSelf (World world, MultiblockMasterBaseLogic newMaster) + { + this.master = newMaster; + this.master.attachBlock(this); + } + + protected void detachSelf (boolean chunkUnloading) + { + if (this.master != null) + { + this.master.detachBlock(this, chunkUnloading); + this.master = null; + } + } + + protected CoordTuple[] getNeighborCoords () + { + return new CoordTuple[] { new CoordTuple(this.xCoord - 1, this.yCoord, this.zCoord), new CoordTuple(this.xCoord, this.yCoord - 1, this.zCoord), + new CoordTuple(this.xCoord, this.yCoord, this.zCoord - 1), new CoordTuple(this.xCoord, this.yCoord, this.zCoord + 1), new CoordTuple(this.xCoord, this.yCoord + 1, this.zCoord), + new CoordTuple(this.xCoord + 1, this.yCoord, this.zCoord) }; + } +} diff --git a/src/tconstruct/library/multiblock/MultiblockEventHandler.java b/src/tconstruct/library/multiblock/MultiblockEventHandler.java new file mode 100644 index 00000000..27d95c9b --- /dev/null +++ b/src/tconstruct/library/multiblock/MultiblockEventHandler.java @@ -0,0 +1,42 @@ +package tconstruct.library.multiblock; + +import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.event.EventPriority; +import net.minecraftforge.event.ForgeSubscribe; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.WorldEvent; + +public class MultiblockEventHandler +{ + @ForgeSubscribe(priority = EventPriority.NORMAL) + public void onChunkLoad (ChunkEvent.Load loadEvent) + { + Chunk chunk = loadEvent.getChunk(); + World world = loadEvent.world; + if (world.isRemote) + { + return; + } + MultiblockRegistry.onChunkLoaded(world, ChunkCoordIntPair.chunkXZ2Int(chunk.xPosition, chunk.zPosition)); + } + + @ForgeSubscribe(priority = EventPriority.NORMAL) + public void onChunkUnload (ChunkEvent.Unload unloadEvent) + { + Chunk chunk = unloadEvent.getChunk(); + World world = unloadEvent.world; + if (world.isRemote) + { + return; + } + MultiblockRegistry.onChunkUnloaded(world, ChunkCoordIntPair.chunkXZ2Int(chunk.xPosition, chunk.zPosition)); + } + + @ForgeSubscribe(priority = EventPriority.NORMAL) + public void onWorldUnload (WorldEvent.Unload unloadWorldEvent) + { + MultiblockRegistry.onWorldUnloaded(unloadWorldEvent.world); + } +} diff --git a/src/tconstruct/library/multiblock/MultiblockMasterBaseLogic.java b/src/tconstruct/library/multiblock/MultiblockMasterBaseLogic.java new file mode 100644 index 00000000..197d731e --- /dev/null +++ b/src/tconstruct/library/multiblock/MultiblockMasterBaseLogic.java @@ -0,0 +1,400 @@ +package tconstruct.library.multiblock; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatMessageComponent; +import net.minecraft.world.World; + +import tconstruct.library.util.CoordTuple; + +public abstract class MultiblockMasterBaseLogic +{ + protected World worldObj; + protected Set connectedBlocks; + protected CoordTuple referenceCoord; + protected CoordTuple minimumCoord; + protected CoordTuple maximumCoord; + protected boolean forceRecheck; + protected boolean chunksHaveLoaded; + protected boolean doUpdates; + + protected MultiblockMasterBaseLogic(World world) + { + worldObj = world; + connectedBlocks = new CopyOnWriteArraySet(); + referenceCoord = null; + + minimumCoord = new CoordTuple(0, 0, 0); + maximumCoord = new CoordTuple(0, 0, 0); + + forceRecheck = false; + chunksHaveLoaded = false; + + doUpdates = true; + } + + public void restore (NBTTagCompound savedData) + { + this.readFromNBT(savedData); + MultiblockRegistry.register(this); + } + + public boolean hasBlock (CoordTuple blockCoord) + { + return connectedBlocks.contains(blockCoord); + } + + public void attachBlock (IMultiblockMember member) + { + CoordTuple coords = member.getCoordInWorld(); + boolean newMultiblock = this.connectedBlocks.isEmpty(); + + if (connectedBlocks.contains(coords)) + { + return; + } + + connectedBlocks.add(coords); + member.onAttached(this); + this.onBlockAdded(member); + this.worldObj.markBlockForUpdate(coords.x, coords.y, coords.z); + + if (newMultiblock) + { + MultiblockRegistry.register(this); + } + + if (this.referenceCoord == null) + { + referenceCoord = coords; + member.becomeMultiblockSaveDelegate(); + } + else if (coords.compareTo(referenceCoord) < 0) + { + TileEntity te = this.worldObj.getBlockTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + ((IMultiblockMember) te).forfeitMultiblockSaveDelegate(); + + referenceCoord = coords; + member.becomeMultiblockSaveDelegate(); + } + + forceRecheck = true; + } + + protected abstract void onBlockAdded (IMultiblockMember newMember); + + protected abstract void onBlockRemoved (IMultiblockMember oldMember); + + public void detachBlock (IMultiblockMember member, boolean chunkUnloading) + { + _detachBlock(member, chunkUnloading); + + if (!chunkUnloading && forceRecheck) + { + this.revisitBlocks(); + } + } + + private void _detachBlock (IMultiblockMember member, boolean chunkUnloading) + { + CoordTuple coords = member.getCoordInWorld(); + if (chunkUnloading) + { + this.disableUpdates(); + } + + if (connectedBlocks.contains(coords)) + { + member.onDetached(this); + connectedBlocks.remove(coords); + this.onBlockRemoved(member); + + if (referenceCoord != null && referenceCoord.equals(coords)) + { + member.forfeitMultiblockSaveDelegate(); + referenceCoord = null; + } + } + + if (connectedBlocks.isEmpty()) + { + MultiblockRegistry.unregister(this); + return; + } + + if (!forceRecheck && chunkUnloading) + { + this.chunksHaveLoaded = true; + } + else if (this.chunksHaveLoaded) + { + this.chunksHaveLoaded = chunkUnloading; + } + + forceRecheck = true; + + if (referenceCoord == null) + { + if (!this.connectedBlocks.isEmpty()) + { + for (CoordTuple tcoord : connectedBlocks) + { + TileEntity te = this.worldObj.getBlockTileEntity(tcoord.x, tcoord.y, tcoord.z); + if (te == null) + { + continue; + } + + if (referenceCoord == null) + { + referenceCoord = tcoord; + } + else if (tcoord.compareTo(referenceCoord) < 0) + { + referenceCoord = tcoord; + } + } + } + + if (referenceCoord != null) + { + TileEntity te = this.worldObj.getBlockTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + ((IMultiblockMember) te).becomeMultiblockSaveDelegate(); + } + } + } + + private void disableUpdates () + { + doUpdates = false; + } + + private void enableUpdates () + { + doUpdates = true; + } + + private boolean getUpdateState () + { + return doUpdates; + } + + public void beginMerging () + { + } + + public void merge (MultiblockMasterBaseLogic other) + { + if (this.referenceCoord.compareTo(other.referenceCoord) >= 0) + { + throw new IllegalArgumentException("You're doing it wrong"); + } + + TileEntity te; + Set acquiredMembers = new CopyOnWriteArraySet(other.connectedBlocks); + + other.onMergedIntoOtherMaster(this); + + IMultiblockMember acquiredMember; + for (CoordTuple coord : acquiredMembers) + { + this.connectedBlocks.add(coord); + te = this.worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + acquiredMember = (IMultiblockMember) te; + acquiredMember.onMasterMerged(this); + this.onBlockAdded(acquiredMember); + } + } + + private void onMergedIntoOtherMaster (MultiblockMasterBaseLogic newMaster) + { + this.disableUpdates(); + + if (referenceCoord != null) + { + TileEntity te = this.worldObj.getBlockTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + ((IMultiblockMember) te).forfeitMultiblockSaveDelegate(); + this.referenceCoord = null; + } + + this.connectedBlocks.clear(); + MultiblockRegistry.unregister(this); + + this.onDataMerge(newMaster); + } + + protected abstract void onDataMerge (MultiblockMasterBaseLogic newMaster); + + public void endMerging () + { + } + + public final void doMultiblockTick () + { + if (this.connectedBlocks.isEmpty()) + { + MultiblockRegistry.unregister(this); + return; + } + + if (this.forceRecheck) + { + // Recheck structure + this.doStructureCheck(); + this.forceRecheck = false; + } + + if (this.doUpdates) + { + if (doUpdate()) + { + // Force save delegate to update data + } + } + } + + // Override to provide sanity checking on structure + public void doStructureCheck () + { + } + + // Return true to force chunk saving + public boolean doUpdate () + { + return false; + } + + public void revisitBlocks () + { + TileEntity te; + // Ensure that our current reference coords are valid. If not, invalidate it. + if (referenceCoord != null && this.worldObj.getBlockTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z) == null) + { + referenceCoord = null; + } + + // Reset visitations and find the minimum coordinate + for (CoordTuple coord : connectedBlocks) + { + + if (!this.worldObj.getChunkProvider().chunkExists(coord.x >> 4, coord.z >> 4)) + { + continue; + } + + te = this.worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (te == null) + { + continue; + } // this happens during chunk unload; ignore it + + ((IMultiblockMember) te).setUnivisted(); + + if (referenceCoord == null) + { + referenceCoord = coord; + } + else if (coord.compareTo(referenceCoord) < 0) + { + referenceCoord = coord; + } + } + + if (referenceCoord == null) + { + // There are no valid parts remaining. This is due to a chunk unload. + return; + } + + // Now visit all connected parts, breadth-first, starting from reference coord. + LinkedList membersToCheck = new LinkedList(); + IMultiblockMember[] nearbyMembers = null; + IMultiblockMember member = (IMultiblockMember) this.worldObj.getBlockTileEntity(referenceCoord.x, referenceCoord.y, referenceCoord.z); + + membersToCheck.add(member); + while (!membersToCheck.isEmpty()) + { + member = membersToCheck.removeFirst(); + member.setVisited(); + + nearbyMembers = member.getNeighboringMembers(); + for (IMultiblockMember nearbyMember : nearbyMembers) + { + // Ignore different machines + if (nearbyMember.getMultiblockMaster() != this) + { + continue; + } + + if (!nearbyMember.isVisited()) + { + nearbyMember.setVisited(); + membersToCheck.add(nearbyMember); + } + } + } + + // First, remove any blocks that are still disconnected + List orphans = new LinkedList(); + List deadBlocks = new ArrayList(); + for (CoordTuple coord : connectedBlocks) + { + if (!this.worldObj.getChunkProvider().chunkExists(coord.x >> 4, coord.z >> 4)) + { + deadBlocks.add(coord); + continue; + } + member = (IMultiblockMember) this.worldObj.getBlockTileEntity(coord.x, coord.y, coord.z); + if (!member.isVisited()) + { + orphans.add(member); + } + } + + this.connectedBlocks.removeAll(deadBlocks); + + // Remove all orphaned parts. i.e. Actually orphan them + for (IMultiblockMember orphan : orphans) + { + this._detachBlock(orphan, false); + } + + // Now go through and start up as many new masters as possible + for (IMultiblockMember orphan : orphans) + { + if (!orphan.isConnected()) + { + orphan.onOrphaned(); + } + } + } + + public CoordTuple getReferenceCoord () + { + return referenceCoord; + } + + public int getNumConnectedBlocks () + { + return connectedBlocks.size(); + } + + public abstract void writeToNBT (NBTTagCompound data); + + public abstract void readFromNBT (NBTTagCompound data); + + public abstract void formatDescriptionPacket (NBTTagCompound data); + + public abstract void decodeDescriptionPacket (NBTTagCompound data); + + public String debugString () + { + return "refCoords: [" + referenceCoord.x + "," + referenceCoord.y + "," + referenceCoord.z + "]"; + } +} diff --git a/src/tconstruct/library/multiblock/MultiblockRegistry.java b/src/tconstruct/library/multiblock/MultiblockRegistry.java new file mode 100644 index 00000000..004ec5ed --- /dev/null +++ b/src/tconstruct/library/multiblock/MultiblockRegistry.java @@ -0,0 +1,141 @@ +package tconstruct.library.multiblock; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import net.minecraft.world.World; + +public class MultiblockRegistry +{ + private static Set masters = new CopyOnWriteArraySet(); + private static HashMap>> preInitMembers = new HashMap>>(); + private static HashMap>> preInitMasters = new HashMap>>(); + private static HashMap>> loadedMembers = new HashMap>>(); + + public static void tick (World world) + { + for (MultiblockMasterBaseLogic logic : masters) + { + if (logic.worldObj == world && logic.worldObj.isRemote == world.isRemote) + { + logic.doMultiblockTick(); + } + } + } + + public static void register (MultiblockMasterBaseLogic logic) + { + masters.add(logic); + } + + public static void unregister (MultiblockMasterBaseLogic logic) + { + masters.remove(logic); + } + + public static void onMemberLoad (World world, Long chunkCoord, IMultiblockMember member, boolean master) + { + HashMap>> pending = preInitMembers; + if (master) + { + pending = preInitMasters; + } + + int dimensionId = world.provider.dimensionId; + putMemberInList(pending, dimensionId, chunkCoord, member); + + } + + public static void onChunkLoaded (World world, long chunkCoord) + { + int dimensionId = world.provider.dimensionId; + List pending = getMembersFromListForWorldChunk(preInitMasters, dimensionId, chunkCoord); + if (pending != null) + { + for (IMultiblockMember member : pending) + { + member.onChunkLoad(); + } + preInitMasters.get(dimensionId).remove(chunkCoord); + } + + pending = getMembersFromListForWorldChunk(preInitMembers, dimensionId, chunkCoord); + if (pending != null) + { + for (IMultiblockMember member : pending) + { + member.onChunkLoad(); + } + preInitMembers.get(dimensionId).remove(chunkCoord); + } + } + + public static void onChunkUnloaded (World world, long chunkCoord) + { + int dimensionId = world.provider.dimensionId; + List pending = getMembersFromListForWorldChunk(loadedMembers, dimensionId, chunkCoord); + if (pending != null) + { + for (IMultiblockMember member : pending) + { + member.onChunkUnloaded(); + } + loadedMembers.get(dimensionId).remove(chunkCoord); + } + } + + public static void registerMember (World world, long chunkCoord, IMultiblockMember member) + { + putMemberInList(loadedMembers, world.provider.dimensionId, chunkCoord, member); + } + + public static void onWorldUnloaded (World world) + { + List mastersToRemove = new ArrayList(); + for (MultiblockMasterBaseLogic master : mastersToRemove) + { + if (master.worldObj.isRemote == world.isRemote && master.worldObj.provider.dimensionId == world.provider.dimensionId) + { + mastersToRemove.add(master); + } + } + + masters.removeAll(mastersToRemove); + } + + private static List getMembersFromListForWorldChunk (HashMap>> source, int dimensionId, long chunkCoord) + { + if (!source.containsKey(dimensionId)) + { + return null; + } + + if (!source.get(dimensionId).containsKey(chunkCoord)) + { + return null; + } + + return source.get(dimensionId).get(chunkCoord); + } + + private static void putMemberInList (HashMap>> destList, int dimensionId, long chunkCoord, IMultiblockMember member) + { + if (!destList.containsKey(dimensionId)) + { + destList.put(dimensionId, new HashMap>()); + } + + HashMap> innerMap = destList.get(dimensionId); + + if (!innerMap.containsKey(chunkCoord)) + { + innerMap.put(chunkCoord, new ArrayList()); + } + + innerMap.get(chunkCoord).add(member); + } +} diff --git a/src/tconstruct/library/multiblock/MultiblockServerTickHandler.java b/src/tconstruct/library/multiblock/MultiblockServerTickHandler.java new file mode 100644 index 00000000..a9d81ed1 --- /dev/null +++ b/src/tconstruct/library/multiblock/MultiblockServerTickHandler.java @@ -0,0 +1,47 @@ +package tconstruct.library.multiblock; + +import java.util.EnumSet; + +import net.minecraft.world.World; + +import cpw.mods.fml.common.IScheduledTickHandler; +import cpw.mods.fml.common.TickType; + +public class MultiblockServerTickHandler implements IScheduledTickHandler +{ + + @Override + public void tickStart (EnumSet type, Object... tickData) + { + return; + } + + @Override + public void tickEnd (EnumSet type, Object... tickData) + { + if (type.contains(TickType.WORLD)) + { + World world = (World) tickData[0]; + MultiblockRegistry.tick(world); + } + } + + @Override + public EnumSet ticks () + { + return EnumSet.of(TickType.WORLD); + } + + @Override + public String getLabel () + { + return "TConstruct:MultiblockServerTickHandler"; + } + + @Override + public int nextTickSpacing () + { + return 1; + } + +} diff --git a/src/tconstruct/library/signal/ISignalTransceiver.java b/src/tconstruct/library/signal/ISignalTransceiver.java new file mode 100644 index 00000000..5cded653 --- /dev/null +++ b/src/tconstruct/library/signal/ISignalTransceiver.java @@ -0,0 +1,21 @@ +package tconstruct.library.signal; + +import tconstruct.library.util.CoordTuple; +import net.minecraft.world.World; + +public interface ISignalTransceiver +{ + + void setBusCoords (World world, int xCoord, int yCoord, int zCoord); + + CoordTuple getBusCoords (); + + byte[] getReceivedSignals (); + + void receiveSignalUpdate (byte[] signals); + + int doUnregister (boolean reHoming); + + int getDroppedWire (); + +} diff --git a/src/tconstruct/library/util/CoordTuple.java b/src/tconstruct/library/util/CoordTuple.java index c7b8e468..dcf796e5 100644 --- a/src/tconstruct/library/util/CoordTuple.java +++ b/src/tconstruct/library/util/CoordTuple.java @@ -13,6 +13,13 @@ public class CoordTuple implements Comparable z = posZ; } + public CoordTuple(CoordTuple tuple) + { + x = tuple.x; + y = tuple.y; + z = tuple.z; + } + public boolean equalCoords (int posX, int posY, int posZ) { if (this.x == posX && this.y == posY && this.z == posZ) @@ -57,11 +64,34 @@ public class CoordTuple implements Comparable { if (o == null) throw new NullPointerException("Object cannot be null"); - - CoordTuple coord = (CoordTuple) o; - if (coord.equals(this)) - return 0; - - return (x - coord.x) + (y - coord.y) + (z - coord.z); + + CoordTuple coord = (CoordTuple) o; + + if (x < coord.x) + { + return -1; + } + if (x > coord.x) + { + return 1; + } + if (y < coord.y) + { + return -1; + } + if (y > coord.y) + { + return 1; + } + if (z < coord.z) + { + return -1; + } + if (z > coord.z) + { + return 1; + } + + return 0; } } diff --git a/src/tconstruct/library/util/CoordTuplePair.java b/src/tconstruct/library/util/CoordTuplePair.java new file mode 100644 index 00000000..b6343279 --- /dev/null +++ b/src/tconstruct/library/util/CoordTuplePair.java @@ -0,0 +1,19 @@ +package tconstruct.library.util; + +public class CoordTuplePair +{ + public CoordTuple a; + public CoordTuple b; + + public CoordTuplePair (CoordTuple a, CoordTuple b) + { + this.a = a; + this.b = b; + } + + public CoordTuplePair (int aX, int aY, int aZ, int bX, int bY, int bZ) + { + this.a = new CoordTuple(aX, aY, aZ); + this.b = new CoordTuple(bX, bY, bZ); + } +} \ No newline at end of file diff --git a/src/tconstruct/util/config/PHConstruct.java b/src/tconstruct/util/config/PHConstruct.java index f1bf84f8..470ea88e 100644 --- a/src/tconstruct/util/config/PHConstruct.java +++ b/src/tconstruct/util/config/PHConstruct.java @@ -47,7 +47,6 @@ public class PHConstruct keepHunger = config.get("Difficulty Changes", "Keep hunger on death", true).getBoolean(true); keepLevels = config.get("Difficulty Changes", "Keep levels on death", true).getBoolean(true); beginnerBook = config.get("Difficulty Changes", "Spawn beginner book", true).getBoolean(true); - superfunWorld = config.get("Superfun", "All the world is Superfun", false).getBoolean(false); enableTWood = config.get("Difficulty Changes", "Enable mod wooden tools", true).getBoolean(true); @@ -179,6 +178,8 @@ public class PHConstruct slimeExplosive = config.getBlock("SDX", 3247).getInt(3247); castingChannel = config.getBlock("Casting Channel", 3249).getInt(3249); woodenRail = config.getBlock("Wooden Rail", 3250).getInt(3250); + signalBus = config.getBlock("Signal Bus", 3251).getInt(3251); + signalTerminal = config.getBlock("Signal Terminal", 3252).getInt(3252); manual = config.getItem("Patterns and Misc", "Tinker's Manual", 14018).getInt(14018); blankPattern = config.getItem("Patterns and Misc", "Blank Patterns", 14019).getInt(14019); @@ -263,6 +264,9 @@ public class PHConstruct essenceCrystal = config.getItem("Patterns and Misc", "Essence Crystal", 14114).getInt(14114); jerky = config.getItem("Patterns and Misc", "Jerky", 14115).getInt(14115); + spoolWire = config.getItem("Logic", "SpoolWire", 14120).getInt(14120); + lengthWire = config.getItem("Logic", "LengthWire", 14121).getInt(14121); + boolean ic2 = true; boolean xycraft = true; try @@ -410,6 +414,9 @@ public class PHConstruct public static int dryingRack; public static int woodenRail; + + public static int signalBus; + public static int signalTerminal; //Crops public static int oreBerry; @@ -578,6 +585,9 @@ public class PHConstruct public static int knapsack; public static int heartCanister; + + public static int spoolWire; + public static int lengthWire; //Ore values public static boolean generateCopper;