diff --git a/src/main/java/li/cil/oc/Blocks.scala b/src/main/java/li/cil/oc/Blocks.scala index 7055dccce..3447b55f4 100644 --- a/src/main/java/li/cil/oc/Blocks.scala +++ b/src/main/java/li/cil/oc/Blocks.scala @@ -21,6 +21,7 @@ object Blocks { var case1, case2, case3: Case = _ var diskDrive: DiskDrive = _ var keyboard: Keyboard = _ + var hologram: Hologram = _ var powerConverter: PowerConverter = _ var powerDistributor: PowerDistributor = _ var redstone: Redstone = _ @@ -56,6 +57,7 @@ object Blocks { GameRegistry.registerTileEntity(classOf[tileentity.Charger], Settings.namespace + "charger") GameRegistry.registerTileEntity(classOf[tileentity.DiskDrive], Settings.namespace + "disk_drive") GameRegistry.registerTileEntity(classOf[tileentity.Keyboard], Settings.namespace + "keyboard") + GameRegistry.registerTileEntity(classOf[tileentity.Hologram], Settings.namespace + "hologram") GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "power_converter") GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor") GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone") @@ -95,6 +97,9 @@ object Blocks { // v1.2.0 serverRack = Recipes.addBlock(new Rack(blockSpecialWithRedstone), "rack") + // v1.2.2 + hologram = Recipes.addBlock(new Hologram(blockSpecial), "hologram") + register("oc:craftingCable", cable.createItemStack()) register("oc:craftingCapacitor", capacitor.createItemStack()) register("oc:craftingCaseTier1", case1.createItemStack()) diff --git a/src/main/java/li/cil/oc/client/PacketHandler.scala b/src/main/java/li/cil/oc/client/PacketHandler.scala index f209814f0..47a7c593a 100644 --- a/src/main/java/li/cil/oc/client/PacketHandler.scala +++ b/src/main/java/li/cil/oc/client/PacketHandler.scala @@ -26,6 +26,7 @@ class PacketHandler extends CommonPacketHandler { case PacketType.ChargerState => onChargerState(p) case PacketType.ComputerState => onComputerState(p) case PacketType.ComputerUserList => onComputerUserList(p) + case PacketType.HologramSet => onHologramSet(p) case PacketType.PowerState => onPowerState(p) case PacketType.RedstoneState => onRedstoneState(p) case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p) @@ -100,6 +101,18 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } + def onHologramSet(p: PacketParser) = + p.readTileEntity[Hologram]() match { + case Some(t) => + val length = p.readInt() + val count = math.max(0, math.min(length, t.volume.length)) + for (i <- 0 until count) { + t.volume(i) = p.readInt() + } + t.dirty = true + case _ => // Invalid packet. + } + def onPowerState(p: PacketParser) = p.readTileEntity[PowerInformation]() match { case Some(t) => diff --git a/src/main/java/li/cil/oc/client/Proxy.scala b/src/main/java/li/cil/oc/client/Proxy.scala index 6e1862247..c72df6230 100644 --- a/src/main/java/li/cil/oc/client/Proxy.scala +++ b/src/main/java/li/cil/oc/client/Proxy.scala @@ -28,6 +28,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Cable], CableRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Case], CaseRenderer) + ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Rack], RackRenderer) ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer) diff --git a/src/main/java/li/cil/oc/client/TexturePreloader.scala b/src/main/java/li/cil/oc/client/TexturePreloader.scala index e489214ba..b6e7bc80e 100644 --- a/src/main/java/li/cil/oc/client/TexturePreloader.scala +++ b/src/main/java/li/cil/oc/client/TexturePreloader.scala @@ -22,6 +22,7 @@ object TexturePreloader extends ResourceManagerReloadListener { val blockCable = new ResourceLocation(Settings.resourceDomain, "textures/blocks/cable.png") val blockCaseFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/case_front_on.png") + val blockHologram = new ResourceLocation(Settings.resourceDomain, "textures/blocks/hologram_effect.png") val blockPowerDistributorOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/power_distributor_on.png") val blockRackFrontOn = new ResourceLocation(Settings.resourceDomain, "textures/blocks/rack_front_on.png") val blockRobot = new ResourceLocation(Settings.resourceDomain, "textures/blocks/robot.png") diff --git a/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala new file mode 100644 index 000000000..c6a8ff2be --- /dev/null +++ b/src/main/java/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -0,0 +1,117 @@ +package li.cil.oc.client.renderer.tileentity + +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer +import net.minecraft.tileentity.TileEntity +import li.cil.oc.common.tileentity.Hologram +import net.minecraft.client.renderer.Tessellator +import org.lwjgl.opengl.GL11 +import li.cil.oc.util.RenderState +import li.cil.oc.client.TexturePreloader +import net.minecraftforge.client.MinecraftForgeClient + +object HologramRenderer extends TileEntitySpecialRenderer { + override def renderTileEntityAt(te: TileEntity, x: Double, y: Double, z: Double, f: Float) { + if (MinecraftForgeClient.getRenderPass != 0) return + + val hologram = te.asInstanceOf[Hologram] + + GL11.glPushAttrib(0xFFFFFFFF) + GL11.glDisable(GL11.GL_CULL_FACE) + +// RenderState.disableLighting() + RenderState.makeItBlend() + + GL11.glPushMatrix() + GL11.glTranslated(x - 1, y + 0.5, z - 1) + + def isSolid(hx: Int, hy: Int, hz: Int) = { + hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width && + (hologram.volume(hx + hz * hologram.width) & (1 << hy)) != 0 + } + + bindTexture(TexturePreloader.blockHologram) + val t = Tessellator.instance + t.startDrawingQuads() + t.setColorRGBA_F(1, 1, 1, 0.7f) + + val s = 1f / 16f + for (hx <- 0 until hologram.width) { + val wx = hx * s + for (hz <- 0 until hologram.width) { + val wz = hz * s + for (hy <- 0 until hologram.height) { + val wy = hy * s + + if (isSolid(hx, hy, hz)) { + /* + 0---1 + | N | + 0---3---2---1---0 + | W | U | E | D | + 5---6---7---4---5 + | S | + 5---4 + */ + + // South + if (!isSolid(hx, hy, hz + 1)) { + t.setNormal(0, 0, 1) + t.addVertex(wx + s, wy + s, wz + s) // 5 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + s, wy + 0, wz + s) // 6 + } + // North + if (!isSolid(hx, hy, hz - 1)) { + t.setNormal(0, 0, -1) + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + s, wy + s, wz + 0) // 0 + } + + // East + if (!isSolid(hx + 1, hy, hz)) { + t.setNormal(1, 0, 0) + t.addVertex(wx + s, wy + s, wz + s) // 5 + t.addVertex(wx + s, wy + 0, wz + s) // 6 + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + t.addVertex(wx + s, wy + s, wz + 0) // 0 + } + // West + if (!isSolid(hx - 1, hy, hz)) { + t.setNormal(-1, 0, 0) + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + } + + // Up + if (!isSolid(hx, hy + 1, hz)) { + t.setNormal(0, 1, 0) + t.addVertex(wx + s, wy + s, wz + 0) // 0 + t.addVertex(wx + 0, wy + s, wz + 0) // 1 + t.addVertex(wx + 0, wy + s, wz + s) // 4 + t.addVertex(wx + s, wy + s, wz + s) // 5 + } + // Down + if (!isSolid(hx, hy - 1, hz)) { + t.setNormal(0, -1, 0) + t.addVertex(wx + s, wy + 0, wz + s) // 6 + t.addVertex(wx + 0, wy + 0, wz + s) // 7 + t.addVertex(wx + 0, wy + 0, wz + 0) // 2 + t.addVertex(wx + s, wy + 0, wz + 0) // 3 + } + + } + } + } + } + + t.draw() + + GL11.glPopMatrix() + GL11.glPopAttrib() + } +} diff --git a/src/main/java/li/cil/oc/common/PacketType.scala b/src/main/java/li/cil/oc/common/PacketType.scala index eb98c912c..11013c6c1 100644 --- a/src/main/java/li/cil/oc/common/PacketType.scala +++ b/src/main/java/li/cil/oc/common/PacketType.scala @@ -8,6 +8,7 @@ object PacketType extends Enumeration { ChargerState, ComputerState, ComputerUserList, + HologramSet, PowerState, RedstoneState, RobotAnimateSwing, diff --git a/src/main/java/li/cil/oc/common/block/Delegate.scala b/src/main/java/li/cil/oc/common/block/Delegate.scala index 29defc757..626dc008f 100644 --- a/src/main/java/li/cil/oc/common/block/Delegate.scala +++ b/src/main/java/li/cil/oc/common/block/Delegate.scala @@ -41,11 +41,11 @@ trait Delegate { def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: ForgeDirection) = true - def bounds(world: World, x: Int, y: Int, z: Int) = + def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 1, 1) def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) = - parent.setBlockBounds(0, 0, 0, 1, 1, 1) + parent.setBlockBounds(bounds(world, x, y, z)) def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = parent.superCollisionRayTrace(world, x, y, z, origin, direction) diff --git a/src/main/java/li/cil/oc/common/block/Hologram.scala b/src/main/java/li/cil/oc/common/block/Hologram.scala new file mode 100644 index 000000000..9b926bb38 --- /dev/null +++ b/src/main/java/li/cil/oc/common/block/Hologram.scala @@ -0,0 +1,33 @@ +package li.cil.oc.common.block + +import java.util +import li.cil.oc.common.tileentity +import li.cil.oc.util.Tooltip +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.{ItemStack, EnumRarity} +import net.minecraft.world.{World, IBlockAccess} +import net.minecraftforge.common.ForgeDirection +import net.minecraft.util.AxisAlignedBB + +class Hologram(val parent: SpecialDelegator) extends SpecialDelegate { + val unlocalizedName = "Hologram" + + override def rarity = EnumRarity.rare + + override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + tooltip.addAll(Tooltip.get(unlocalizedName)) + } + + override def luminance(world: IBlockAccess, x: Int, y: Int, z: Int) = 15 + + override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN + + override def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = + AxisAlignedBB.getAABBPool.getAABB(0, 0, 0, 1, 0.2f, 1) + + // ----------------------------------------------------------------------- // + + override def hasTileEntity = true + + override def createTileEntity(world: World) = Some(new tileentity.Hologram()) +} diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala new file mode 100644 index 000000000..94dba39ce --- /dev/null +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -0,0 +1,93 @@ +package li.cil.oc.common.tileentity + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import li.cil.oc.api.network._ +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import li.cil.oc.{Settings, api} +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.AxisAlignedBB +import net.minecraftforge.common.ForgeDirection + +class Hologram extends Environment with SidedEnvironment { + val node = api.Network.newNode(this, Visibility.Network). + withComponent("hologram"). + withConnector(). + create() + + val width = 3 * 16 + + val height = 2 * 16 // 32 bit in an int + + val volume = new Array[Int](width * width) + + // Whether we need to send an update packet/recompile our display list. + var dirty = false + + // Time to wait before sending another update packet. + var cooldown = 0 + + // ----------------------------------------------------------------------- // + + override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP + + override def sidedNode(side: ForgeDirection) = node + + // ----------------------------------------------------------------------- // + + @Callback(direct = true, doc = """function(x:number, z:number):number -- Returns the bit mask representing the specified column.""") + def get(computer: Context, args: Arguments): Array[AnyRef] = { + val x = args.checkInteger(0) - 1 + val z = args.checkInteger(1) - 1 + result(volume(x + z * width)) + } + + @Callback(direct = true, limit = 256, doc = """function(x:number, z:number, value:number) -- Set the bit mask for the specified column.""") + def set(computer: Context, args: Arguments): Array[AnyRef] = { + val x = args.checkInteger(0) - 1 + val z = args.checkInteger(1) - 1 + val value = args.checkInteger(2) + volume(x + z * width) = value + dirty = true + null + } + + // ----------------------------------------------------------------------- // + + override def updateEntity() { + super.updateEntity() + if (isServer && dirty) { + cooldown -= 1 + if (cooldown <= 0) { + dirty = false + cooldown = 10 + ServerPacketSender.sendHologramSet(this) + } + } + } + + // ----------------------------------------------------------------------- // + + override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord - 1, yCoord, zCoord - 1, xCoord + 2, yCoord + 3, zCoord + 2) + + override def readFromNBT(nbt: NBTTagCompound) { + super.readFromNBT(nbt) + nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume) + } + + override def writeToNBT(nbt: NBTTagCompound) { + super.writeToNBT(nbt) + nbt.setIntArray(Settings.namespace + "volume", volume) + } + + @SideOnly(Side.CLIENT) + override def readFromNBTForClient(nbt: NBTTagCompound) { + super.readFromNBTForClient(nbt) + nbt.getIntArray("volume").copyToArray(volume) + dirty = true + } + + override def writeToNBTForClient(nbt: NBTTagCompound) { + super.writeToNBTForClient(nbt) + nbt.setIntArray("volume", volume) + } +} diff --git a/src/main/java/li/cil/oc/server/PacketSender.scala b/src/main/java/li/cil/oc/server/PacketSender.scala index 2e4ee1aaa..2290137f8 100644 --- a/src/main/java/li/cil/oc/server/PacketSender.scala +++ b/src/main/java/li/cil/oc/server/PacketSender.scala @@ -55,6 +55,16 @@ object PacketSender { pb.sendToNearbyPlayers(t) } + def sendHologramSet(t: Hologram) { + val pb = new PacketBuilder(PacketType.HologramSet) + + pb.writeTileEntity(t) + pb.writeInt(t.volume.length) + t.volume.foreach(pb.writeInt) + + pb.sendToNearbyPlayers(t) + } + def sendPowerState(t: PowerInformation) { val pb = new PacketBuilder(PacketType.PowerState) diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index e901711bb..8534bb21f 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -271,7 +271,7 @@ powerDistributor { rack { input: [["oc:circuitTier2", "oc:componentCardWLan", "oc:circuitTier2"] [fenceIron, chest, fenceIron] - ["oc:craftingRouter", "oc:craftingCircuitBoardPrinted","oc:craftingPowerDistributor"]] + ["oc:craftingRouter", "oc:craftingCircuitBoardPrinted", "oc:craftingPowerDistributor"]] } redstone { input: [[ingotIron, blockRedstone, ingotIron] @@ -302,4 +302,9 @@ screen3 { input: [[obsidian, yellowDust, obsidian] [yellowDust, "oc:circuitTier3", glass] [obsidian, yellowDust, obsidian]] +} +hologram { + input: [[obsidian, glass, obsidian] + ["oc:craftingCircuitBoardPrinted", diamond, "oc:craftingCircuitBoardPrinted"] + ["oc:circuitTier3", blazeRod, "oc:circuitTier3"]] } \ No newline at end of file diff --git a/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png b/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png new file mode 100644 index 000000000..e994756a3 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/blocks/hologram_effect.png differ