diff --git a/src/main/resources/assets/projectred/lang/en_US.lang b/src/main/resources/assets/projectred/lang/en_US.lang index bc2f75b6c..c2a502ca5 100644 --- a/src/main/resources/assets/projectred/lang/en_US.lang +++ b/src/main/resources/assets/projectred/lang/en_US.lang @@ -602,3 +602,39 @@ item.projectred.fabrication.icblueprint.name=IC Blueprint item.projectred.fabrication.icchip.name=IC Chip item.projectred.fabrication.icchip|0.name=IC Chip item.projectred.fabrication.icchip|1.name=Creative Mode IC Chip +gui.projectred.fabrication.debug=Debug +gui.projectred.fabrication.insulated_wires=Insulated wires +gui.projectred.fabrication.bundled_cables=Bundled cables +gui.projectred.fabrication.ios=IOs +gui.projectred.fabrication.primitives=Primitives +gui.projectred.fabrication.timing_and_clocks=Timing and Clocks +gui.projectred.fabrication.latches=Latches +gui.projectred.fabrication.misc=Misc +gui.projectred.fabrication.reset_view=Reset View +gui.projectred.fabrication.detail=Detail +gui.projectred.fabrication.copy=Copy +gui.projectred.fabrication.cut=Cut +gui.projectred.fabrication.paste=Paste +gui.projectred.fabrication.erase=Erase +gui.projectred.fabrication.io_simple=Simple IO +gui.projectred.fabrication.io_analog=Analog IO +gui.projectred.fabrication.io_bundled=Bundled IO +gui.projectred.fabrication.rotate=Rotate +gui.projectred.fabrication.configure=Configure +gui.projectred.fabrication.frequency=Frequency +gui.projectred.fabrication.state=State +gui.projectred.fabrication.max=Max +gui.projectred.fabrication.inc=Inc +gui.projectred.fabrication.dec=Dec +gui.projectred.fabrication.timer_interval=Interval +gui.projectred.fabrication.import_string=Import string from clipboard +gui.projectred.fabrication.export_string=Export string to clipboard +gui.projectred.fabrication.export_success=Blueprint exported to clipboard! +gui.projectred.fabrication.invalid_string=Not a valid blueprint string +gui.projectred.fabrication.clipboard_unavailable=Can't access system clipboard +gui.projectred.fabrication.im_ex_port=Im-/Export Blueprint Strings + + +tile.projectred.integration.icblock.name=IC Workbench/Printer +tile.projectred.integration.icblock|0.name=IC Workbench +tile.projectred.integration.icblock|1.name=IC Printer diff --git a/src/main/resources/assets/projectred/textures/blocks/fabrication/in.png b/src/main/resources/assets/projectred/textures/blocks/fabrication/in.png new file mode 100644 index 000000000..c36b845d7 Binary files /dev/null and b/src/main/resources/assets/projectred/textures/blocks/fabrication/in.png differ diff --git a/src/main/resources/assets/projectred/textures/blocks/fabrication/inout.png b/src/main/resources/assets/projectred/textures/blocks/fabrication/inout.png new file mode 100644 index 000000000..e9edff24d Binary files /dev/null and b/src/main/resources/assets/projectred/textures/blocks/fabrication/inout.png differ diff --git a/src/main/resources/assets/projectred/textures/blocks/fabrication/out.png b/src/main/resources/assets/projectred/textures/blocks/fabrication/out.png new file mode 100644 index 000000000..184de3ad7 Binary files /dev/null and b/src/main/resources/assets/projectred/textures/blocks/fabrication/out.png differ diff --git a/src/main/resources/assets/projectred/textures/gui/ic_workbench.png b/src/main/resources/assets/projectred/textures/gui/ic_workbench.png index 94b63e404..6afd14231 100644 Binary files a/src/main/resources/assets/projectred/textures/gui/ic_workbench.png and b/src/main/resources/assets/projectred/textures/gui/ic_workbench.png differ diff --git a/src/main/scala/mrtjp/projectred/fabrication/fmpgatepart.scala b/src/main/scala/mrtjp/projectred/fabrication/FMPCircuitGate.scala similarity index 98% rename from src/main/scala/mrtjp/projectred/fabrication/fmpgatepart.scala rename to src/main/scala/mrtjp/projectred/fabrication/FMPCircuitGate.scala index 8473b298f..feff24b18 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/fmpgatepart.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/FMPCircuitGate.scala @@ -10,7 +10,17 @@ import codechicken.lib.gui.GuiDraw import codechicken.lib.render.{CCRenderState, TextureUtils} import codechicken.lib.vec._ import mrtjp.core.math.MathLib -import mrtjp.projectred.fabrication.IIOCircuitPart._ +import mrtjp.projectred.fabrication.ItemICBlueprint.{ + getConnModes, + getICName, + hasICInside +} +import mrtjp.projectred.fabrication.circuitparts.io.TIOCircuitPart.{ + Analog, + Bundled, + NoConn, + Simple +} import mrtjp.projectred.integration import mrtjp.projectred.integration._ import mrtjp.projectred.transmission.BundledCommons._ @@ -296,7 +306,6 @@ class RenderCircuitGate extends GateRenderer[CircuitGatePart] { ) override def prepareInv(stack: ItemStack) { - import ItemICBlueprint._ if (hasICInside(stack)) { name = getICName(stack) val cm = getConnModes(stack) diff --git a/src/main/scala/mrtjp/projectred/fabrication/tileicprinter.scala b/src/main/scala/mrtjp/projectred/fabrication/ICPrinter.scala similarity index 98% rename from src/main/scala/mrtjp/projectred/fabrication/tileicprinter.scala rename to src/main/scala/mrtjp/projectred/fabrication/ICPrinter.scala index 006672b06..8ea0128f0 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/tileicprinter.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/ICPrinter.scala @@ -6,7 +6,6 @@ package mrtjp.projectred.fabrication import java.util.{ArrayList => JAList, List => JList} - import codechicken.lib.data.{MCDataInput, MCDataOutput} import codechicken.lib.gui.GuiDraw import codechicken.lib.render.uv.{ @@ -27,6 +26,15 @@ import mrtjp.core.world.WorldLib import mrtjp.projectred.ProjectRedCore.log import mrtjp.projectred.core.PartDefs import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.circuitparts.GateICPart +import mrtjp.projectred.fabrication.circuitparts.wire.{ + AlloyWireICPart, + BundledCableICPart, + ButtonICPart, + InsulatedWireICPart, + LeverICPart, + TorchICPart +} import mrtjp.projectred.integration.ComponentStore import mrtjp.projectred.transmission.WireDef import net.minecraft.client.renderer.RenderBlocks @@ -465,7 +473,7 @@ object TileICPrinter { getOrCacheComponents(stack).foreach(add(_, 0.25)) } - import mrtjp.projectred.fabrication.{ICGateDefinition => gd} + import mrtjp.projectred.fabrication.circuitparts.{ICGateDefinition => gd} for (part <- ic.parts.values) part match { case p: TorchICPart => add(new ItemStack(Blocks.redstone_torch), 0.25) diff --git a/src/main/scala/mrtjp/projectred/fabrication/tileicworkbench.scala b/src/main/scala/mrtjp/projectred/fabrication/ICWorkbench.scala similarity index 96% rename from src/main/scala/mrtjp/projectred/fabrication/tileicworkbench.scala rename to src/main/scala/mrtjp/projectred/fabrication/ICWorkbench.scala index c3ea71ab1..a17888f46 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/tileicworkbench.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/ICWorkbench.scala @@ -21,6 +21,7 @@ import mrtjp.core.world.WorldLib import mrtjp.projectred.ProjectRedFabrication import mrtjp.projectred.api.IScrewdriver import mrtjp.projectred.fabrication.ItemICBlueprint._ +import mrtjp.projectred.fabrication.gui.GuiICWorkbench import net.minecraft.block.material.Material import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.entity.item.EntityItem @@ -138,9 +139,7 @@ class TileICWorkbench extends TileICMachine with NetWorldCircuit { case 2 => circuit.readDesc(in) case 3 => readPartStream(in) case 4 => readICStream(in) - case 5 => - if (!hasBP) new IntegratedCircuit().readDesc(in) - else { circuit.readDesc(in); sendICDesc() } + case 5 => circuit.name = in.readString() case _ => super.read(in, key) } @@ -159,9 +158,9 @@ class TileICWorkbench extends TileICMachine with NetWorldCircuit { } } - def sendNewICToServer(ic: IntegratedCircuit) { + def sendICNameToServer(name: String) { val stream = writeStream(5) - ic.writeDesc(stream) + stream.writeString(name) stream.sendToServer() } @@ -209,7 +208,7 @@ class TileICWorkbench extends TileICMachine with NetWorldCircuit { sendHasBPUpdate() } else if (hasBP && player.isSneaking) { val stack = new ItemStack(ProjectRedFabrication.itemICBlueprint) - if (circuit.nonEmpty) { + if (circuit.parts.nonEmpty) { saveIC(circuit, stack) circuit.clear() sendICDesc() @@ -245,7 +244,8 @@ class TileICWorkbench extends TileICMachine with NetWorldCircuit { super.onBlockRemoval() if (hasBP) { val stack = new ItemStack(ProjectRedFabrication.itemICBlueprint) - if (circuit.nonEmpty) saveIC(circuit, stack) + if (circuit.parts.nonEmpty) + saveIC(circuit, stack) WorldLib.dropItem(world, x, y, z, stack) } } diff --git a/src/main/scala/mrtjp/projectred/fabrication/IntegratedCircuit.scala b/src/main/scala/mrtjp/projectred/fabrication/IntegratedCircuit.scala new file mode 100644 index 000000000..604f8f310 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/IntegratedCircuit.scala @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import mrtjp.core.vec.{Point, Rect, Size} +import mrtjp.projectred.ProjectRedCore.log +import mrtjp.projectred.fabrication.circuitparts.io.{IOGateICPart, TIOCircuitPart} +import mrtjp.projectred.fabrication.circuitparts.{CircuitPart, TClientNetCircuitPart, TErrorCircuitPart} +import mrtjp.projectred.fabrication.operations.CircuitOp +import net.minecraft.nbt.{NBTTagCompound, NBTTagList} + +import scala.collection.mutable.{Map => MMap} + +class IntegratedCircuit { + var network: WorldCircuit = null + + var name = "untitled" + + var parts = MMap[(Int, Int), CircuitPart]() + var errors = Map.empty[Point, (String, Int)] + + private var scheduledTicks = MMap[(Int, Int), Long]() + + /** Mapped inputs and outputs of this IC. Outputs go to the world, inputs come + * in from the world. OOOO OOOO OOOO OOOO IIII IIII IIII IIII + */ + val iostate = Array(0, 0, 0, 0) + + var outputChangedDelegate = { () => () } + + def setInput(r: Int, state: Int) { + iostate(r) = iostate(r) & 0xffff0000 | state & 0xffff + } + + def setOutput(r: Int, state: Int) { + iostate(r) = iostate(r) & 0xffff | (state & 0xffff) << 16 + } + + def firstSetup(): Unit = { + val ioparts = parts.values.collect { case io: IOGateICPart => io } + ioparts.foreach(_.onOutputChange(0xf)) + } + + def onInputChanged(mask: Int) { + val ioparts = parts.values.collect { case io: TIOCircuitPart => io } + for (r <- 0 until 4) if ((mask & 1 << r) != 0) { + ioparts.foreach(_.onExtInputChanged(r)) + sendInputUpdate(r) + } + } + + def onOutputChanged(mask: Int) { + val ioparts = parts.values.collect { case io: TIOCircuitPart => io } + for (r <- 0 until 4) if ((mask & 1 << r) != 0) { + ioparts.foreach(_.onExtOutputChanged(r)) + outputChangedDelegate() + sendOutputUpdate(r) + } + } + + def save(tag: NBTTagCompound) { + tag.setString("name", name) + tag.setIntArray("iost", iostate) + + val tagList = new NBTTagList + for (part <- parts.values) { + val partTag = new NBTTagCompound + partTag.setByte("id", part.id.toByte) + partTag.setInteger("xpos", part.x) + partTag.setInteger("ypos", part.y) + part.save(partTag) + tagList.appendTag(partTag) + } + tag.setTag("parts", tagList) + + // etc + } + + def load(tag: NBTTagCompound) { + clear() + name = tag.getString("name") + val ta = tag.getIntArray("iost") + for (i <- 0 until 4) iostate(i) = ta(i) + + val partList = tag.getTagList("parts", 10) + for (i <- 0 until partList.tagCount) { + val partTag = partList.getCompoundTagAt(i) + val part = CircuitPart.createPart(partTag.getByte("id") & 0xff) + setPart_do( + partTag.getInteger("xpos"), + partTag.getInteger("ypos"), + part + ) + part.load(partTag) + } + + // etc + } + + def writeDesc(out: MCDataOutput) { + out.writeString(name) + for (i <- 0 until 4) out.writeInt(iostate(i)) + + for (((x, y), part) <- parts) { + out.writeByte(part.id) + out.writeInt(x).writeInt(y) + part.writeDesc(out) + } + out.writeByte(255) + + // etc + } + + def readDesc(in: MCDataInput) { + clear() + name = in.readString() + for (i <- 0 until 4) iostate(i) = in.readInt() + + var id = in.readUByte() + while (id != 255) { + val part = CircuitPart.createPart(id) + setPart_do(in.readInt(), in.readInt(), part) + part.readDesc(in) + id = in.readUByte() + } + // etc + } + + def read(in: MCDataInput, key: Int) = { + if (!network.isRemote) { + key match { + case 3 => CircuitOp.readOp(this, in) + case 4 => + getPart(in.readInt(), in.readInt()) match { + case g: TClientNetCircuitPart => g.readClientPacket(in) + case _ => + log.error("Server IC stream received invalid client packet") + } + } + } else { + key match { + case 0 => readDesc(in) + case 1 => + val part = CircuitPart.createPart(in.readUByte()) + setPart_do(in.readInt(), in.readInt(), part) + part.readDesc(in) + case 2 => removePart(in.readInt(), in.readInt()) + case 5 => iostate(in.readUByte()) = in.readInt() + case 6 => setInput(in.readUByte(), in.readShort()) + case 7 => setOutput(in.readUByte(), in.readShort()) + } + } + } + + def sendPartAdded(part: CircuitPart) { + val out = network.getICStreamOf(1) + out.writeByte(part.id) + out.writeInt(part.x).writeInt(part.y) + part.writeDesc(out) + } + + def sendRemovePart(x: Int, y: Int) { + network.getICStreamOf(2).writeInt(x).writeInt(y) + } + + def sendOpUse(op: CircuitOp, start: Point, end: Point) = { + if (op.checkOp(this, start, end)) { + op.clientSendOperation(this, start, end, network.getICStreamOf(3)) + true + } else false + } + + def sendClientPacket( + part: TClientNetCircuitPart, + writer: MCDataOutput => Unit + ) { + val s = network.getICStreamOf(4).writeInt(part.x).writeInt(part.y) + writer(s) + } + + def sendInputUpdate(r: Int) { + network.getICStreamOf(6).writeByte(r).writeShort(iostate(r) & 0xffff) + } + + def sendOutputUpdate(r: Int) { + network.getICStreamOf(7).writeByte(r).writeShort(iostate(r) >> 16) + } + + def clear() { + parts.values.foreach { + _.unbind() + } // remove references + parts = MMap() + scheduledTicks = MMap() + name = "untitled" + for (i <- 0 until 4) iostate(i) = 0 + } + + def tick() { + val t = network.getWorld.getTotalWorldTime + var rem = Seq[(Int, Int)]() + for ((k, v) <- scheduledTicks) if (v >= t) { + getPart(k._1, k._2).scheduledTick() + rem :+= k + } + rem.foreach(scheduledTicks.remove) + + for (part <- parts.values) part.update() + } + + def refreshErrors() { + val eparts = parts.values.collect { case p: TErrorCircuitPart => p } + val elist = Map.newBuilder[Point, (String, Int)] + + for (part <- eparts) { + val error = part.postErrors + if (error != null) + elist += Point(part.x, part.y) -> error + } + + errors = elist.result() + } + + def getPartsBoundingBox(): Rect = { + val keys = parts.keys + val ((x2, y2), (x1, y1)) = if (keys.nonEmpty) { + ( + keys.reduce((p1, p2) => + (math.max(p1._1, p2._1), math.max(p1._2, p2._2)) + ), + keys.reduce((p1, p2) => + (math.min(p1._1, p2._1), math.min(p1._2, p2._2)) + ) + ) + } else { + ((1, 1), (0, 0)) + } + Rect(Point(x1, y1), Size(x2 - x1, y2 - y1)) + } + + def setPart(x: Int, y: Int, part: CircuitPart) { + setPart_do(x, y, part) + part.onAdded() + if (!network.isRemote) sendPartAdded(part) + } + + private def setPart_do(x: Int, y: Int, part: CircuitPart) { + part.bind(this, x, y) + parts += (x, y) -> part + } + + def getPart(x: Int, y: Int): CircuitPart = parts.getOrElse((x, y), null) + + def getParts( + topLeft: Point, + bottomRight: Point + ): Map[(Int, Int), CircuitPart] = { + parts + .filter(element => + element._1._1 >= topLeft.x && + element._1._1 < bottomRight.x && + element._1._2 >= topLeft.y && + element._1._2 < bottomRight.y + ) + .toMap + } + + def removePart(x: Int, y: Int) { + val part = getPart(x, y) + if (part != null) { + if (!network.isRemote) sendRemovePart(x, y) + parts.remove((x, y)) + part.onRemoved() + part.unbind() + } + } + + def notifyNeighbor(x: Int, y: Int) { + val part = getPart(x, y) + if (part != null) part.onNeighborChanged() + } + + def notifyNeighbors(x: Int, y: Int, mask: Int) { + for (r <- 0 until 4) if ((mask & 1 << r) != 0) { + val point = Point(x, y).offset(r) + val part = getPart(point.x, point.y) + if (part != null) part.onNeighborChanged() + } + } + + def scheduleTick(x: Int, y: Int, ticks: Int) { + scheduledTicks += (x, y) -> (network.getWorld.getTotalWorldTime + ticks) + } + + // Convinience functions + def setPart(p: Point, part: CircuitPart) { + setPart(p.x, p.y, part) + } + + def getPart(p: Point): CircuitPart = getPart(p.x, p.y) + + def removePart(p: Point) { + removePart(p.x, p.y) + } + + def notifyNeighbor(p: Point) { + notifyNeighbor(p.x, p.y) + } + + def notifyNeighbors(p: Point, mask: Int) { + notifyNeighbors(p.x, p.y, mask) + } + + def scheduleTick(p: Point, ticks: Int) { + scheduleTick(p.x, p.y, ticks) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/items.scala b/src/main/scala/mrtjp/projectred/fabrication/Items.scala similarity index 92% rename from src/main/scala/mrtjp/projectred/fabrication/items.scala rename to src/main/scala/mrtjp/projectred/fabrication/Items.scala index f6dddbd8f..1b9e58e3a 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/items.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/Items.scala @@ -5,15 +5,13 @@ */ package mrtjp.projectred.fabrication -import java.util.{List => JList} - import codechicken.lib.gui.GuiDraw import cpw.mods.fml.common.registry.GameRegistry import mrtjp.core.color.Colors import mrtjp.core.item.ItemCore -import mrtjp.core.vec.{Point, Size} import mrtjp.projectred.core.libmc.PRResources -import mrtjp.projectred.fabrication.IIOCircuitPart._ +import mrtjp.projectred.fabrication.circuitparts.io.TIOCircuitPart +import mrtjp.projectred.fabrication.circuitparts.io.TIOCircuitPart._ import mrtjp.projectred.integration.GateDefinition import mrtjp.projectred.{ProjectRedFabrication, ProjectRedIntegration} import net.minecraft.client.renderer.texture.IIconRegister @@ -32,6 +30,8 @@ import net.minecraftforge.client.IItemRenderer.{ } import org.lwjgl.opengl.GL11._ +import java.util.{List => JList} + class ItemICBlueprint extends ItemMap // extend ItemMap so minecraft will handle the FP render for us { @@ -70,9 +70,7 @@ class ItemICBlueprint val slist = list.asInstanceOf[JList[String]] if (ItemICBlueprint.hasICInside(stack)) { - val size = ItemICBlueprint.getICSize(stack) slist.add(GRAY + ItemICBlueprint.getICName(stack)) - slist.add(GRAY + s"${size.width} x ${size.height}") } else slist.add(GRAY + "empty blueprint") } } @@ -94,8 +92,6 @@ object ItemICBlueprint { ic.save(tag2) tag1.setTag("icdata", tag2) tag1.setString("icname", ic.name) - tag1.setByte("icw", ic.size.width.toByte) - tag1.setByte("ich", ic.size.height.toByte) } def loadIC(stack: ItemStack): IntegratedCircuit = { @@ -114,11 +110,6 @@ object ItemICBlueprint { stack.getTagCompound.getString("icname") } - def getICSize(stack: ItemStack) = { - val tag = stack.getTagCompound - Size(tag.getByte("icw"), tag.getByte("ich")) - } - def hasICInside(stack: ItemStack) = { stack.hasTagCompound && stack.getTagCompound.hasKey("icdata") } @@ -143,7 +134,7 @@ object ItemICBlueprint { def saveICToGate(ic: IntegratedCircuit, gate: ItemStack) { assertStackTag(gate) - val ioparts = ic.parts.values.collect { case io: IIOCircuitPart => + val ioparts = ic.parts.values.collect { case io: TIOCircuitPart => io }.toSeq var (ri, ro, bi, bo) = (0, 0, 0, 0) @@ -222,7 +213,7 @@ object ItemRenderICBlueprint extends IItemRenderer { if (ItemICBlueprint.hasICInside(stack)) { val ic = ItemICBlueprint.loadIC(stack) - if (ic.nonEmpty) overlayIC(ic) + overlayIC(ic) } glEnable(GL_LIGHTING) @@ -243,10 +234,12 @@ object ItemRenderICBlueprint extends IItemRenderer { } private def overlayIC(ic: IntegratedCircuit) { - val sf = 128 / math.max(ic.size.width, ic.size.height) - val rs = ic.size * sf - val rp = Point(Size(128, 128) / 2 - rs / 2) - RenderCircuit.renderOrtho(ic, rp.x, rp.y, rs.width, rs.height, 0) + val boundingBox = ic.getPartsBoundingBox() + val scale = math.min( + 8.0d / (boundingBox.width.toDouble + 1), + 8.0d / (boundingBox.height.toDouble + 1) + ) + RenderCircuit.renderCircuitOrtho(ic, scale, boundingBox.origin.vectorize) val name = ic.name diff --git a/src/main/scala/mrtjp/projectred/fabrication/proxies.scala b/src/main/scala/mrtjp/projectred/fabrication/Proxies.scala similarity index 99% rename from src/main/scala/mrtjp/projectred/fabrication/proxies.scala rename to src/main/scala/mrtjp/projectred/fabrication/Proxies.scala index 4165756a0..a51cfd638 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/proxies.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/Proxies.scala @@ -5,7 +5,6 @@ */ package mrtjp.projectred.fabrication import java.lang.{Character => JC} - import codechicken.lib.data.MCDataInput import codechicken.multipart.MultiPartRegistry import codechicken.multipart.MultiPartRegistry.IPartFactory2 @@ -20,6 +19,7 @@ import mrtjp.projectred.core.{IProxy, PartDefs} import mrtjp.projectred.integration.{GateDefinition, RenderGate} import mrtjp.projectred.{ProjectRedFabrication, ProjectRedIntegration} import mrtjp.projectred.Tags +import mrtjp.projectred.fabrication.gui.GuiICWorkbench import net.minecraft.init.{Blocks, Items} import net.minecraft.inventory.InventoryCrafting import net.minecraft.item.ItemStack diff --git a/src/main/scala/mrtjp/projectred/fabrication/RenderCircuit.scala b/src/main/scala/mrtjp/projectred/fabrication/RenderCircuit.scala new file mode 100644 index 000000000..d30d7a40c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/RenderCircuit.scala @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication + +import codechicken.lib.render.ColourMultiplier +import codechicken.lib.render.uv.{UVScale, UVTranslation} +import codechicken.lib.vec._ +import mrtjp.core.color.Colors +import mrtjp.core.vec.{Point, Size, Vec2} +import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.ICComponentStore.{ + dynamicIdx, + faceModels, + finishRender, + orthoPartT, + prepairRender +} +import mrtjp.projectred.fabrication.gui.PrefboardRenderer +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.texture.IIconRegister + +object RenderCircuit { + val BASE_SCALE = 16 + + def registerIcons(reg: IIconRegister) { + ICComponentStore.registerIcons(reg) + } + + def renderOrtho( + circuit: IntegratedCircuit, + boardSize: Size, + gridScale: Double, + gridTranslation: Vec2 + ) { + PrefboardRenderer.renderOrtho(boardSize, gridScale, gridTranslation) + renderCircuitOrtho(circuit, gridScale, gridTranslation) + } + + def renderErrors( + circuit: IntegratedCircuit, + gridScale: Double, + gridTranslation: Vec2 + ): Unit = { + if ( + Minecraft.getMinecraft.theWorld.getTotalWorldTime % 100 > 5 && circuit.errors.nonEmpty + ) { + prepairRender() + PRResources.guiPrototyper.bind() + for ((Point(x, y), (_, c)) <- circuit.errors) { + val t = orthoPartT(Vec2(x, y) - gridTranslation, gridScale) + faceModels(dynamicIdx(0, true)).render( + t, + new UVScale(64) `with` new UVTranslation( + 330, + 37 + ) `with` new UVScale(1 / 512d), + ColourMultiplier.instance(Colors(c).rgba) + ) + } + finishRender() + } + } + + def renderCircuitOrtho( + circuit: IntegratedCircuit, + scale: Double, + gridTranslation: Vec2 + ): Unit = { + val t = ICComponentStore.orthoGridT(BASE_SCALE, BASE_SCALE) + for (((x, y), part) <- circuit.parts) { + val tlist = new TransformationList( + new Scale(scale, 1, scale), + new Translation( + (x - gridTranslation.dx) * scale, + 0, + (y - gridTranslation.dy) * scale + ), + t + ) + part.renderDynamic(tlist, true, 1f) + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/WorldCircuit.scala b/src/main/scala/mrtjp/projectred/fabrication/WorldCircuit.scala new file mode 100644 index 000000000..5ea78fe9a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/WorldCircuit.scala @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.packet.PacketCustom +import codechicken.lib.vec.BlockCoord +import mrtjp.core.vec.Point +import mrtjp.projectred.ProjectRedCore.log +import mrtjp.projectred.fabrication.circuitparts.CircuitPart +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.world.World +import net.minecraftforge.fluids.FluidStack + +trait WorldCircuit { + def getIC: IntegratedCircuit + + def getWorld: World + + def getICStreamOf(key: Int): MCDataOutput + + def getPartStream(x: Int, y: Int): MCDataOutput + + def isRemote: Boolean + + def markSave() +} + +object DummyMCIO extends MCDataOutput { + override def writeVarInt(i: Int) = this + override def writeCoord(x: Int, y: Int, z: Int) = this + override def writeCoord(coord: BlockCoord) = this + override def writeString(s: String) = this + override def writeFloat(f: Float) = this + override def writeDouble(d: Double) = this + override def writeShort(s: Int) = this + override def writeVarShort(s: Int) = this + override def writeInt(i: Int) = this + override def writeFluidStack(liquid: FluidStack) = this + override def writeByteArray(array: Array[Byte]) = this + override def writeBoolean(b: Boolean) = this + override def writeItemStack(stack: ItemStack) = this + override def writeNBTTagCompound(tag: NBTTagCompound) = this + override def writeChar(c: Char) = this + override def writeLong(l: Long) = this + override def writeByte(b: Int) = this +} + +trait SimulatedWorldCircuit extends WorldCircuit { + override def getICStreamOf(key: Int) = DummyMCIO + override def getPartStream(x: Int, y: Int) = DummyMCIO + override def isRemote = false +} + +trait NetWorldCircuit extends WorldCircuit { + private var icStream: PacketCustom = null + private var partStream: PacketCustom = null + + def createPartStream(): PacketCustom + def sendPartStream(out: PacketCustom) + override def getPartStream(x: Int, y: Int): MCDataOutput = { + if (partStream == null) partStream = createPartStream() + + val part = getIC.getPart(x, y) + partStream.writeByte(part.id) + partStream.writeInt(x).writeInt(y) + + partStream + } + def flushPartStream() { + if (partStream != null) { + partStream.writeByte(255) // terminator + sendPartStream(partStream.compress()) + partStream = null + } + } + def readPartStream(in: MCDataInput) { + try { + var id = in.readUByte() + while (id != 255) { + val (x, y) = (in.readInt(), in.readInt()) + var part = getIC.getPart(x, y) + if (part == null || part.id != id) { + log.error("client part stream couldnt find part " + Point(x, y)) + part = CircuitPart.createPart(id) + } + part.read(in) + id = in.readUByte() + } + } catch { + case ex: IndexOutOfBoundsException => + log.error("Circuit part stream failed to be read.") + ex.printStackTrace() + } + } + + def createICStream(): PacketCustom + def sendICStream(out: PacketCustom) + override def getICStreamOf(key: Int): MCDataOutput = { + if (icStream == null) icStream = createICStream() + icStream.writeByte(key) + icStream + } + def flushICStream() { + if (icStream != null) { + icStream.writeByte(255) // terminator + sendICStream(icStream.compress()) + icStream = null + } + } + def readICStream(in: MCDataInput) { + try { + var id = in.readUByte() + while (id != 255) { + getIC.read(in, id) + id = in.readUByte() + } + } catch { + case ex: IndexOutOfBoundsException => + log.error("Circuit IC stream failed to be read") + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogic.scala new file mode 100644 index 000000000..33a334ad3 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogic.scala @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.circuitparts.cells.{ + BufferCell, + InvertCell, + NullCell +} + +object ArrayGateICLogic { + + import ICGateDefinition._ + + def create(gate: ArrayGateICPart, subID: Int) = subID match { + case NullCell.ordinal => new NullCell(gate) + case InvertCell.ordinal => new InvertCell(gate) + case BufferCell.ordinal => new BufferCell(gate) + case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) + } +} + +abstract class ArrayGateICLogic(val gate: ArrayGateICPart) + extends RedstoneICGateLogic[ArrayGateICPart] + with TArrayICGateLogic[ArrayGateICPart] + with TComplexICGateLogic[ArrayGateICPart] diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogicCrossing.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogicCrossing.scala new file mode 100644 index 000000000..7bc7e0cb0 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICLogicCrossing.scala @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import cpw.mods.fml.relauncher.{Side, SideOnly} +import net.minecraft.nbt.NBTTagCompound + +abstract class ArrayGateICLogicCrossing(gate: ArrayGateICPart) + extends ArrayGateICLogic(gate) { + var signal1: Byte = 0 + var signal2: Byte = 0 + + override def redwireMask(shape: Int) = 0xf + + override def propogationMask(r: Int) = if (r % 2 == 0) 0x5 else 0xa + + override def inputMask(shape: Int) = 0xf + + override def outputMask(shape: Int) = 0xf + + override def getSignal(mask: Int) = + (if (mask == 0x5) signal1 else signal2) & 0xff + + override def setSignal(mask: Int, signal: Int) { + if (mask == 0x5) signal1 = signal.toByte else signal2 = signal.toByte + } + + override def save(tag: NBTTagCompound) { + super.save(tag) + tag.setByte("s1", signal1) + tag.setByte("s2", signal2) + } + + override def load(tag: NBTTagCompound) { + super.load(tag) + signal1 = tag.getByte("s1") + signal2 = tag.getByte("s2") + } + + override def writeDesc(packet: MCDataOutput) { + super.writeDesc(packet) + packet.writeByte(signal1) + packet.writeByte(signal2) + } + + override def readDesc(packet: MCDataInput) { + super.readDesc(packet) + signal1 = packet.readByte() + signal2 = packet.readByte() + } + + override def read(packet: MCDataInput, key: Int) = key match { + case 11 => + signal1 = packet.readByte() + signal2 = packet.readByte() + case _ => + } + + def sendSignalUpdate() { + gate.writeStreamOf(11).writeByte(signal1).writeByte(signal2) + } + + override def onChange(gate: ArrayGateICPart) { + val oldSignal = (gate.state & 1) != 0 + val newSignal = signal1 != 0 + + if (oldSignal != newSignal) { + gate.setState(gate.state & 2 | (if (newSignal) 1 else 0)) + gate.onInputChange() + gate.scheduleTick(0) + } + } + + override def scheduledTick(gate: ArrayGateICPart) { + val input = (gate.state & 1) != 0 + val oldOutput = (gate.state & 2) != 0 + val newOutput = !input + + if (oldOutput != newOutput) { + gate.setState(gate.state & 1 | (if (newOutput) 2 else 0)) + gate.onOutputChange(0) + gate.onChange() + } + } + + override def onSignalUpdate() { + sendSignalUpdate() + } + + override def overrideSignal(mask: Int) = if (mask == 0xa) powerUp else false + + override def calculateSignal(mask: Int) = 255 + + def powerUp: Boolean + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: ArrayGateICPart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + + if (detailLevel >= 3) { + data += "lower: 0x" + Integer.toHexString(signal1 & 0xff) + data += "upper: 0x" + Integer.toHexString(signal2 & 0xff) + } else if (detailLevel >= 2) { + data += "lower: " + (if (signal1 != 0) "high" else "low") + data += "upper: " + (if (signal2 != 0) "high" else "low") + } + + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICPart.scala new file mode 100644 index 000000000..b9dae7491 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ArrayGateICPart.scala @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.gui.nodes.configuration.ConfigurationRotation +import mrtjp.projectred.fabrication.gui.nodes.{ConfigurationNode, TConfigurable} + +class ArrayGateICPart + extends RedstoneGateICPart + with TComplexGateICPart + with TArrayGateICPart + with TConfigurable { + private var logic: ArrayGateICLogic = null + + override def getLogic[T] = logic.asInstanceOf[T] + + override def assertLogic() { + if (logic == null) logic = ArrayGateICLogic.create(this, subID) + } + + override def getPartType = CircuitPartDefs.ArrayGate + + override def createConfigurationNode: ConfigurationNode = + new ConfigurationRotation(this) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPart.scala new file mode 100644 index 000000000..63767522c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPart.scala @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.vec.Transformation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.IntegratedCircuit +import mrtjp.projectred.fabrication.operations.CircuitOp +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.StatCollector + +object CircuitPart { + def createPart(id: Int) = CircuitPartDefs(id).createPart +} + +/** Base Class for all Gates, that are displayed in the IC Workbench + */ +abstract class CircuitPart { + var world: IntegratedCircuit = null + var loc: (Int, Int) = null + + def bind(ic: IntegratedCircuit, x: Int, y: Int) { + world = ic + loc = (x, y) + } + + def unbind() { + world = null + loc = null + } + + def x = loc._1 + + def y = loc._2 + + def id = getPartType.id + + def getPartType: CircuitPartDefs.CircuitPartDef + + def save(tag: NBTTagCompound) {} + + def load(tag: NBTTagCompound) {} + + def writeDesc(out: MCDataOutput) {} + + def readDesc(in: MCDataInput) {} + + def writeStreamOf(key: Int): MCDataOutput = + world.network.getPartStream(x, y).writeByte(key) + + def read(in: MCDataInput) { + read(in, in.readUByte()) + } + + def read(in: MCDataInput, key: Int) = key match { + case 0 => readDesc(in) + case _ => + } + + def sendDescUpdate() { + writeDesc(writeStreamOf(0)) + } + + def update() {} + + def scheduledTick() {} + + def scheduleTick(ticks: Int) { + world.scheduleTick(x, y, ticks) + } + + def onAdded() {} + + def onRemoved() {} + + def onNeighborChanged() {} + + @SideOnly(Side.CLIENT) + def onClicked() {} + + @SideOnly(Side.CLIENT) + def onActivated() {} + + @SideOnly(Side.CLIENT) + def getPartName: String + + /** Returns Circuit Operation, that would create this CircuitPart + */ + @SideOnly(Side.CLIENT) + def getCircuitOperation: CircuitOp = null + + @SideOnly(Side.CLIENT) + def getRolloverData(detailLevel: Int): Seq[String] = + if (detailLevel > 0) Seq(StatCollector.translateToLocal(getPartName)) + else Seq.empty + + @SideOnly(Side.CLIENT) + def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) {} +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPartDefs.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPartDefs.scala new file mode 100644 index 000000000..13214f0b5 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/CircuitPartDefs.scala @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.core.util.Enum +import mrtjp.projectred.fabrication.circuitparts.io.IOGateICPart +import mrtjp.projectred.fabrication.circuitparts.wire._ + +object CircuitPartDefs extends Enum { + type EnumVal = CircuitPartDef + + val Torch = CircuitPartDef(() => new TorchICPart) + val Lever = CircuitPartDef(() => new LeverICPart) + val Button = CircuitPartDef(() => new ButtonICPart) + + val AlloyWire = CircuitPartDef(() => new AlloyWireICPart) + val InsulatedWire = CircuitPartDef(() => new InsulatedWireICPart) + val BundledCable = CircuitPartDef(() => new BundledCableICPart) + + val IOGate = CircuitPartDef(() => new IOGateICPart) + val SimpleGate = CircuitPartDef(() => new ComboICGatePart) + val ComplexGate = CircuitPartDef(() => new SequentialGateICPart) + val ArrayGate = CircuitPartDef(() => new ArrayGateICPart) + + case class CircuitPartDef(factory: () => CircuitPart) extends Value { + def id = ordinal + + override def name = s"$id" + + def createPart = factory.apply() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGateLogic.scala new file mode 100644 index 000000000..45d2d6143 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGateLogic.scala @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.circuitparts.latches.TransparentLatch +import mrtjp.projectred.fabrication.circuitparts.misc.{ + DecRandomizer, + Randomizer +} +import mrtjp.projectred.fabrication.circuitparts.primitives._ +import mrtjp.projectred.fabrication.circuitparts.timing.Repeater + +abstract class ComboICGateLogic + extends RedstoneICGateLogic[ComboICGatePart] + with TSimpleRSICGateLogic[ComboICGatePart] { + override def cycleShape(gate: ComboICGatePart) = { + val oldShape = gate.shape + val newShape = cycleShape(oldShape) + if (newShape != oldShape) { + gate.setShape(newShape) + true + } else false + } + + def cycleShape(shape: Int): Int = { + if (deadSides == 0) return shape + + var shape1 = shape + import java.lang.Integer.{bitCount, numberOfLeadingZeros => lead} + do shape1 = ComboICGateLogic.advanceDead(shape1) while (bitCount( + shape1 + ) > maxDeadSides || 32 - lead(shape1) > deadSides) + shape1 + } + + def deadSides = 0 + + def maxDeadSides = deadSides - 1 +} + +object ComboICGateLogic { + val advanceDead = Seq(1, 2, 4, 0, 5, 6, 3) + + val instances = new Array[ComboICGateLogic](ICGateDefinition.values.length) + initialize() + + def initialize() { + instances(ICGateDefinition.OR.ordinal) = OR + instances(ICGateDefinition.NOR.ordinal) = NOR + instances(ICGateDefinition.NOT.ordinal) = NOT + instances(ICGateDefinition.AND.ordinal) = AND + instances(ICGateDefinition.NAND.ordinal) = NAND + instances(ICGateDefinition.XOR.ordinal) = XOR + instances(ICGateDefinition.XNOR.ordinal) = XNOR + instances(ICGateDefinition.Buffer.ordinal) = Buffer + instances(ICGateDefinition.Multiplexer.ordinal) = Multiplexer + instances(ICGateDefinition.Pulse.ordinal) = Pulse + instances(ICGateDefinition.Repeater.ordinal) = Repeater + instances(ICGateDefinition.Randomizer.ordinal) = Randomizer + instances(ICGateDefinition.TransparentLatch.ordinal) = TransparentLatch + instances(ICGateDefinition.DecRandomizer.ordinal) = DecRandomizer + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGatePart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGatePart.scala new file mode 100644 index 000000000..f554a2fbb --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ComboICGatePart.scala @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.gui.nodes.configuration.ConfigurationRotationConfig +import mrtjp.projectred.fabrication.gui.nodes.{ConfigurationNode, TConfigurable} + +class ComboICGatePart extends RedstoneGateICPart with TConfigurable { + override def getLogic[T] = ComboICGateLogic.instances(subID).asInstanceOf[T] + + def getLogicCombo = getLogic[ComboICGateLogic] + + override def getPartType = CircuitPartDefs.SimpleGate + + override def createConfigurationNode: ConfigurationNode = + new ConfigurationRotationConfig(this) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/GateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/GateICPart.scala new file mode 100644 index 000000000..c54c0d7fc --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/GateICPart.scala @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.vec.Transformation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.operations.{ + CircuitOp, + CircuitOpDefs, + OpGate +} +import net.minecraft.nbt.NBTTagCompound + +abstract class GateICPart + extends CircuitPart + with TConnectableICPart + with TICOrient + with TClientNetCircuitPart { + private var gateSubID: Byte = 0 + private var gateShape: Byte = 0 + + var schedTime = 0L + var schedDigital = false + + def getLogic[T]: T + + def getLogicPrimitive = getLogic[ICGateLogic[GateICPart]] + + def subID = gateSubID & 0xff + + def shape = gateShape & 0xff + + def setShape(s: Int) { + gateShape = s.toByte + } + + def preparePlacement(rot: Int, configuration: Int, meta: Int) { + gateSubID = meta.toByte + setRotation(rot) + gateShape = configuration.toByte + } + + override def save(tag: NBTTagCompound) { + tag.setByte("orient", orientation) + tag.setByte("subID", gateSubID) + tag.setByte("shape", gateShape) + tag.setByte("connMap", connMap) + tag.setLong("schedTime", schedTime) + } + + override def load(tag: NBTTagCompound) { + orientation = tag.getByte("orient") + gateSubID = tag.getByte("subID") + gateShape = tag.getByte("shape") + connMap = tag.getByte("connMap") + schedTime = tag.getLong("schedTime") + } + + override def writeDesc(out: MCDataOutput) { + out.writeByte(orientation) + out.writeByte(gateSubID) + out.writeByte(gateShape) + } + + override def readDesc(in: MCDataInput) { + orientation = in.readByte() + gateSubID = in.readByte() + gateShape = in.readByte() + } + + override def read(in: MCDataInput, key: Int) = key match { + case 1 => orientation = in.readByte() + case 2 => gateShape = in.readByte() + case _ => super.read(in, key) + } + + override def readClientPacket(in: MCDataInput) { + readClientPacket(in, in.readUByte()) + } + + def readClientPacket(in: MCDataInput, key: Int) = key match { + case 0 => rotate() + case 1 => configure() + case 2 => getLogicPrimitive.activate(this) + case _ => + } + + override def canConnectPart(part: CircuitPart, r: Int) = + getLogicPrimitive.canConnectTo(this, part, toInternal(r)) + + override def scheduledTick() { + getLogicPrimitive.scheduledTick(this) + } + + override def scheduleTick(ticks: Int) { + if (ticks == 0) scheduleDigitalTick() + else if (schedTime < 0) + schedTime = world.network.getWorld.getTotalWorldTime + ticks + } + + def processScheduled() { + if ( + schedTime >= 0 && world.network.getWorld.getTotalWorldTime >= schedTime + ) { + schedTime = -1 + scheduledTick() + } + } + + def scheduleDigitalTick() { + schedDigital = true + } + + var iter = 0 + + def processScheduledDigital() { + while (schedDigital && iter < 3) // recursion control + { + schedDigital = false + iter += 1 + scheduledTick() + } + } + + def onChange() { + processScheduled() + getLogicPrimitive.onChange(this) + processScheduledDigital() + } + + override def update() { + if (!world.network.isRemote) { + processScheduled() + iter = 0 + processScheduledDigital() + } + getLogicPrimitive.onTick(this) + } + + override def onNeighborChanged() { + if (!world.network.isRemote) { + updateConns() + onChange() + } + } + + override def onAdded() { + super.onAdded() + if (!world.network.isRemote) { + getLogicPrimitive.setup(this) + updateConns() + onChange() + } + } + + override def onRemoved() { + super.onRemoved() + if (!world.network.isRemote) notify(0xf) + } + + def configure() { + if (getLogicPrimitive.cycleShape(this)) { + updateConns() + world.network.markSave() + sendShapeUpdate() + notify(0xf) + onChange() + } + } + + def rotate() { + setRotation((rotation + 1) % 4) + updateConns() + world.network.markSave() + sendOrientUpdate() + notify(0xf) + onChange() + } + + def sendShapeUpdate() { + writeStreamOf(2).writeByte(gateShape) + } + + def sendOrientUpdate() { + writeStreamOf(1).writeByte(orientation) + } + + @SideOnly(Side.CLIENT) + override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { + ICGateRenderer.renderDynamic(this, t, ortho, frame) + } + + @SideOnly(Side.CLIENT) + override def getPartName = ICGateDefinition(subID).name + + @SideOnly(Side.CLIENT) + override def getRolloverData(detailLevel: Int) = { + val s = Seq.newBuilder[String] + import net.minecraft.util.EnumChatFormatting._ + s ++= getLogicPrimitive.getRolloverData(this, detailLevel) + super.getRolloverData(detailLevel) ++ s.result().map(GRAY + _) + } + + @SideOnly(Side.CLIENT) + override def onClicked() { + sendClientPacket(_.writeByte(2)) + } + + @SideOnly(Side.CLIENT) + override def getCircuitOperation: CircuitOp = { + val op = new OpGate(subID) + op.id = CircuitOpDefs.SimpleIO.ordinal + subID + op.rotation = orientation + op.configuration = gateShape + op + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateDefinition.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateDefinition.scala new file mode 100644 index 000000000..b77e833b0 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateDefinition.scala @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.core.util.Enum +import mrtjp.projectred.integration.GateDefinition.GateDef + +object ICGateDefinition extends Enum { + type EnumVal = ICGateDef + + import mrtjp.projectred.integration.{GateDefinition => gd} + + val IOSimple = + ICGateDef("gui.projectred.fabrication.io_simple", CircuitPartDefs.IOGate.id) + val IOAnalog = + ICGateDef("gui.projectred.fabrication.io_analog", CircuitPartDefs.IOGate.id) + val IOBundled = ICGateDef( + "gui.projectred.fabrication.io_bundled", + CircuitPartDefs.IOGate.id + ) + + val OR = ICGateDef( + "item.projectred.integration.gate|0.name", + CircuitPartDefs.SimpleGate.id, + gd.OR + ) + val NOR = ICGateDef( + "item.projectred.integration.gate|1.name", + CircuitPartDefs.SimpleGate.id, + gd.NOR + ) + val NOT = ICGateDef( + "item.projectred.integration.gate|2.name", + CircuitPartDefs.SimpleGate.id, + gd.NOT + ) + val AND = ICGateDef( + "item.projectred.integration.gate|3.name", + CircuitPartDefs.SimpleGate.id, + gd.AND + ) + val NAND = ICGateDef( + "item.projectred.integration.gate|4.name", + CircuitPartDefs.SimpleGate.id, + gd.NAND + ) + val XOR = ICGateDef( + "item.projectred.integration.gate|5.name", + CircuitPartDefs.SimpleGate.id, + gd.XOR + ) + val XNOR = ICGateDef( + "item.projectred.integration.gate|6.name", + CircuitPartDefs.SimpleGate.id, + gd.XNOR + ) + val Buffer = + ICGateDef( + "item.projectred.integration.gate|7.name", + CircuitPartDefs.SimpleGate.id, + gd.Buffer + ) + val Multiplexer = + ICGateDef( + "item.projectred.integration.gate|8.name", + CircuitPartDefs.SimpleGate.id, + gd.Multiplexer + ) + val Pulse = ICGateDef( + "item.projectred.integration.gate|9.name", + CircuitPartDefs.SimpleGate.id, + gd.Pulse + ) + val Repeater = + ICGateDef( + "item.projectred.integration.gate|10.name", + CircuitPartDefs.SimpleGate.id, + gd.Repeater + ) + val Randomizer = + ICGateDef( + "item.projectred.integration.gate|11.name", + CircuitPartDefs.SimpleGate.id, + gd.Randomizer + ) + val SRLatch = + ICGateDef( + "item.projectred.integration.gate|12.name", + CircuitPartDefs.ComplexGate.id, + gd.SRLatch + ) + val ToggleLatch = + ICGateDef( + "item.projectred.integration.gate|13.name", + CircuitPartDefs.ComplexGate.id, + gd.ToggleLatch + ) + val TransparentLatch = ICGateDef( + "item.projectred.integration.gate|14.name", + CircuitPartDefs.SimpleGate.id, + gd.TransparentLatch + ) + val Timer = ICGateDef( + "item.projectred.integration.gate|17.name", + CircuitPartDefs.ComplexGate.id, + gd.Timer + ) + val Sequencer = + ICGateDef( + "item.projectred.integration.gate|18.name", + CircuitPartDefs.ComplexGate.id, + gd.Sequencer + ) + val Counter = ICGateDef( + "item.projectred.integration.gate|19.name", + CircuitPartDefs.ComplexGate.id, + gd.Counter + ) + val StateCell = + ICGateDef( + "item.projectred.integration.gate|20.name", + CircuitPartDefs.ComplexGate.id, + gd.StateCell + ) + val Synchronizer = + ICGateDef( + "item.projectred.integration.gate|21.name", + CircuitPartDefs.ComplexGate.id, + gd.Synchronizer + ) + val DecRandomizer = + ICGateDef( + "item.projectred.integration.gate|33.name", + CircuitPartDefs.SimpleGate.id, + gd.DecRandomizer + ) + val NullCell = + ICGateDef( + "item.projectred.integration.gate|23.name", + CircuitPartDefs.ArrayGate.id, + gd.NullCell + ) + val InvertCell = + ICGateDef( + "item.projectred.integration.gate|24.name", + CircuitPartDefs.ArrayGate.id, + gd.InvertCell + ) + val BufferCell = + ICGateDef( + "item.projectred.integration.gate|25.name", + CircuitPartDefs.ArrayGate.id, + gd.BufferCell + ) + + case class ICGateDef( + unlocalized: String, + gateType: Int, + intDef: GateDef = null + ) extends Value { + override def name = unlocalized + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateLogic.scala new file mode 100644 index 000000000..1e89aba74 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateLogic.scala @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import cpw.mods.fml.relauncher.{Side, SideOnly} + +abstract class ICGateLogic[T <: GateICPart] { + def canConnectTo(gate: T, part: CircuitPart, r: Int): Boolean + + def cycleShape(gate: T) = false + + def onChange(gate: T) + + def scheduledTick(gate: T) + + def onTick(gate: T) {} + + def setup(gate: T) {} + + def activate(gate: T) {} + + @SideOnly(Side.CLIENT) + def getRolloverData(gate: T, detailLevel: Int): Seq[String] = Seq.empty +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateRenderer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateRenderer.scala new file mode 100644 index 000000000..08a06adee --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/ICGateRenderer.scala @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.vec.Transformation +import mrtjp.projectred.fabrication.ICComponentModel +import mrtjp.projectred.fabrication.ICComponentStore.{ + finishRender, + prepairRender +} +import mrtjp.projectred.fabrication.circuitparts.cells.{ + RenderBufferCell, + RenderInvertCell, + RenderNullCell +} +import mrtjp.projectred.fabrication.circuitparts.io.{ + RenderAnalogIO, + RenderBundledIO, + RenderSimpleIO +} +import mrtjp.projectred.fabrication.circuitparts.latches.{ + RenderSRLatch, + RenderToggleLatch, + RenderTransparentLatch +} +import mrtjp.projectred.fabrication.circuitparts.misc.{ + RenderCounter, + RenderDecRandomizer, + RenderRandomizer, + RenderSynchronizer +} +import mrtjp.projectred.fabrication.circuitparts.primitives.{ + RenderAND, + RenderBuffer, + RenderMultiplexer, + RenderNAND, + RenderNOR, + RenderNOT, + RenderOR, + RenderXNOR, + RenderXOR +} +import mrtjp.projectred.fabrication.circuitparts.timing.{ + RenderPulse, + RenderRepeater, + RenderSequencer, + RenderStateCell, + RenderTimer +} +import net.minecraft.client.renderer.texture.IIconRegister + +object ICGateRenderer { + var renderers = buildRenders() + + def buildRenders() = Seq[ICGateRenderer[_]]( + new RenderSimpleIO, + new RenderAnalogIO, + new RenderBundledIO, + new RenderOR, + new RenderNOR, + new RenderNOT, + new RenderAND, + new RenderNAND, + new RenderXOR, + new RenderXNOR, + new RenderBuffer, + new RenderMultiplexer, + new RenderPulse, + new RenderRepeater, + new RenderRandomizer, + new RenderSRLatch, + new RenderToggleLatch, + new RenderTransparentLatch, + new RenderTimer, + new RenderSequencer, + new RenderCounter, + new RenderStateCell, + new RenderSynchronizer, + new RenderDecRandomizer, + new RenderNullCell, + new RenderInvertCell, + new RenderBufferCell + ) + + def registerIcons(reg: IIconRegister) {} + + def renderDynamic( + gate: GateICPart, + t: Transformation, + ortho: Boolean, + frame: Float + ) { + val r = renderers(gate.subID).asInstanceOf[ICGateRenderer[GateICPart]] + r.prepareDynamic(gate, frame) + r.renderDynamic(gate.rotationT `with` t, ortho) + } + + def renderWithConfiguration( + configuration: Int, + t: Transformation, + id: Int + ): Unit = { + val r = renderers(id) + r.prepareStatic(configuration) + r.renderDynamic(t, true) + } + + def renderInv(t: Transformation, id: Int) { + val r = renderers(id) + r.prepareStatic(0) + r.renderDynamic(t, true) + } +} + +abstract class ICGateRenderer[T <: GateICPart] { + var reflect = false + + def coreModels: Seq[ICComponentModel] + def switchModels = Seq[ICComponentModel]() + + def prepareStatic(configuration: Int) + def prepareDynamic(gate: T, frame: Float) {} + + def renderDynamic(t: Transformation, ortho: Boolean) { + renderModels(t, if (reflect) 1 else 0, ortho) + } + + def renderModels(t: Transformation, orient: Int, ortho: Boolean) { + prepairRender() + for (m <- coreModels ++ switchModels) m.renderModel(t, orient, ortho) + finishRender() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/IWireICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/IWireICPart.scala new file mode 100644 index 000000000..7f5442fbb --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/IWireICPart.scala @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.IntegratedCircuit + +object IWireICPart { + + /** Standard operation procedure, no special propogation rules. The propogator + * signal may not have increased. + */ + final val RISING = 0 + + /** Used when the propogator signal dropped (to 0). Propagation should + * continue until a rising or constant change is encountered at which point a + * RISING should be propogated back to this wire. + */ + final val DROPPING = 1 + + /** Used when a wire's connection state has changed. Even if the signal + * remains the same, new connections still need to be recalculated + */ + final val FORCE = 2 + + /** Used when the propogator did not change signal, but a new connection may + * have been established and signal needs recalculating + */ + final val FORCED = 3 +} + +trait IWireICPart { + + /** Recalculates the signal of this wire and calls the appropriate propogation + * methods in WirePropagator. DO NOT CALL THIS YOURSELF. Use + * WirePropagator.propagateTo + * + * @param prev + * The part which called this propogation (should be connected) may be + * null. + * @param mode + * One of RISING, DROPPING, FORCE and FORCED specified above + */ + def updateAndPropagate(prev: CircuitPart, mode: Int) + + /** Called at the end of a propogation run for partChanged events. Marks the + * end of a state change for this part. + */ + def onSignalUpdate() + + /** @param r + * The rotation of this part to test for wire connection. + * @return + * true if the specified side of this block is connected to, for example, a + * 'wire' where signal should decrease by one. + */ + def diminishOnSide(r: Int): Boolean + + /** The world in which this part resides + * + * @return + */ + def world: IntegratedCircuit +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepartrs.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneGateICPart.scala similarity index 65% rename from src/main/scala/mrtjp/projectred/fabrication/gatepartrs.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneGateICPart.scala index 0988f3537..a38b603ad 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepartrs.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneGateICPart.scala @@ -3,15 +3,16 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts import codechicken.lib.data.{MCDataInput, MCDataOutput} +import mrtjp.projectred.fabrication.circuitparts.wire.IICRedwireEmitter import net.minecraft.nbt.NBTTagCompound abstract class RedstoneGateICPart extends GateICPart with TICRSAcquisitions - with IPoweredCircuitPart { + with TPoweredCircuitPart { /** Mapped inputs and outputs of the gate. OOOO IIII High nybble is output. * Low nybble is input @@ -19,7 +20,10 @@ abstract class RedstoneGateICPart private var gateState: Byte = 0 def state = gateState & 0xff - def setState(s: Int) { gateState = s.toByte } + + def setState(s: Int) { + gateState = s.toByte + } def getLogicRS = getLogic[RedstoneICGateLogic[RedstoneGateICPart]] @@ -75,30 +79,7 @@ abstract class RedstoneGateICPart override def resolveSignal(part: Any, r: Int) = part match { case re: IICRedwireEmitter => re.getRedwireSignal(r) - case ip: IPoweredCircuitPart => ip.rsOutputLevel(r) + case ip: TPoweredCircuitPart => ip.rsOutputLevel(r) case _ => 0 } } - -abstract class RedstoneICGateLogic[T <: RedstoneGateICPart] - extends ICGateLogic[T] { - override def canConnectTo(gate: T, part: CircuitPart, r: Int) = part match { - case re: IICRedwireEmitter => canConnect(gate, r) - case _ => false - } - - def canConnect(gate: T, r: Int): Boolean = canConnect(gate.shape, r) - def canConnect(shape: Int, r: Int): Boolean = - ((inputMask(shape) | outputMask(shape)) & 1 << r) != 0 - - def outputMask(shape: Int) = 0 - def inputMask(shape: Int) = 0 - - def getOutput(gate: T, r: Int) = if ((gate.state & 0x10 << r) != 0) 255 else 0 - def getInput(gate: T, mask: Int) = { - var input = 0 - for (r <- 0 until 4) - if ((mask & 1 << r) != 0 && gate.getRedstoneInput(r) > 0) input |= 1 << r - input - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneICGateLogic.scala new file mode 100644 index 000000000..9dc5b93d8 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/RedstoneICGateLogic.scala @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.circuitparts.wire.IICRedwireEmitter + +abstract class RedstoneICGateLogic[T <: RedstoneGateICPart] + extends ICGateLogic[T] { + override def canConnectTo(gate: T, part: CircuitPart, r: Int) = part match { + case re: IICRedwireEmitter => canConnect(gate, r) + case _ => false + } + + def canConnect(gate: T, r: Int): Boolean = canConnect(gate.shape, r) + def canConnect(shape: Int, r: Int): Boolean = + ((inputMask(shape) | outputMask(shape)) & 1 << r) != 0 + + def outputMask(shape: Int) = 0 + def inputMask(shape: Int) = 0 + + def getOutput(gate: T, r: Int) = if ((gate.state & 0x10 << r) != 0) 255 else 0 + def getInput(gate: T, mask: Int) = { + var input = 0 + for (r <- 0 until 4) + if ((mask & 1 << r) != 0 && gate.getRedstoneInput(r) > 0) input |= 1 << r + input + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialGateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialGateICPart.scala new file mode 100644 index 000000000..0d6611fef --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialGateICPart.scala @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.MCDataInput +import mrtjp.projectred.ProjectRedCore.log +import mrtjp.projectred.fabrication.circuitparts.latches.{SRLatch, ToggleLatch} +import mrtjp.projectred.fabrication.circuitparts.misc.{ + ICounterGuiLogic, + Synchronizer +} +import mrtjp.projectred.fabrication.circuitparts.timing.ITimerGuiLogic +import mrtjp.projectred.fabrication.gui.nodes.configuration.{ + ConfigurationCounter, + ConfigurationRotation, + ConfigurationRotationConfig, + ConfigurationTimer +} +import mrtjp.projectred.fabrication.gui.nodes.{ConfigurationNode, TConfigurable} + +class SequentialGateICPart + extends RedstoneGateICPart + with TComplexGateICPart + with TConfigurable { + var logic: SequentialICGateLogic = null + + override def assertLogic() { + if (logic == null) logic = SequentialICGateLogic.create(this, subID) + } + + override def getLogic[T]: T = logic.asInstanceOf[T] + + override def getPartType = CircuitPartDefs.ComplexGate + + override def readClientPacket(in: MCDataInput, key: Int) = key match { + case 3 => + getLogicPrimitive match { + case t: ITimerGuiLogic => + t.setTimerMax(this, in.readShort()) + case _ => + log.error( + "Server IC stream received client packet for incorrect gate type" + ) + } + case 4 => + getLogicPrimitive match { + case t: ICounterGuiLogic => + val actionID = in.readByte() + actionID match { + case 0 => t.setCounterMax(this, t.getCounterMax + in.readShort()) + case 1 => t.setCounterIncr(this, t.getCounterIncr + in.readShort()) + case 2 => t.setCounterDecr(this, t.getCounterDecr + in.readShort()) + case _ => + log.error( + "Server IC stream received client packet for incorrect gate type" + ) + } + case _ => + log.error( + "Server IC stream received client packet for incorrect gate type" + ) + } + case _ => super.readClientPacket(in, key) + } + + override def createConfigurationNode: ConfigurationNode = { + getLogicPrimitive match { + case _: ICounterGuiLogic => new ConfigurationCounter(this) + case _: ITimerGuiLogic => new ConfigurationTimer(this) + case _ => + new ConfigurationRotationConfig(this) + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialICGateLogic.scala new file mode 100644 index 000000000..656fffacb --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/SequentialICGateLogic.scala @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.circuitparts.latches._ +import mrtjp.projectred.fabrication.circuitparts.misc.{Counter, Synchronizer} +import mrtjp.projectred.fabrication.circuitparts.timing._ + +abstract class SequentialICGateLogic(val gate: SequentialGateICPart) + extends RedstoneICGateLogic[SequentialGateICPart] + with TComplexICGateLogic[SequentialGateICPart] + +object SequentialICGateLogic { + + def create(gate: SequentialGateICPart, subID: Int) = subID match { + case ICGateDefinition.SRLatch.ordinal => new SRLatch(gate) + case ICGateDefinition.ToggleLatch.ordinal => new ToggleLatch(gate) + case ICGateDefinition.Timer.ordinal => new Timer(gate) + case ICGateDefinition.Sequencer.ordinal => new Sequencer(gate) + case ICGateDefinition.Counter.ordinal => new Counter(gate) + case ICGateDefinition.StateCell.ordinal => new StateCell(gate) + case ICGateDefinition.Synchronizer.ordinal => new Synchronizer(gate) + case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayGateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayGateICPart.scala new file mode 100644 index 000000000..5665e0b62 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayGateICPart.scala @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.core.vec.Point +import mrtjp.projectred.fabrication.ICPropagator +import mrtjp.projectred.fabrication.circuitparts.wire.IRedwireICPart +import mrtjp.projectred.transmission.IWirePart + +trait TArrayGateICPart + extends RedstoneGateICPart + with IRedwireICPart + with TRSPropagatingICPart { + def getLogicArray = getLogic[TArrayICGateLogic[TArrayGateICPart]] + + override def getSignal = + getLogicArray.getSignal(toInternalMask(propagationMask)) + + override def setSignal(signal: Int) = + getLogicArray.setSignal(toInternalMask(propagationMask), signal) + + abstract override def updateAndPropagate(prev: CircuitPart, mode: Int) { + val rd = sideDiff(prev) + var uMask = 0 + for (r <- 0 until 4) if ((rd & 1 << r) != 0) { + val pMask = getLogicArray.propogationMask(toInternal(r)) + if (pMask > 0 && (pMask & uMask) != pMask) { + propagationMask = toAbsoluteMask(pMask) + super.updateAndPropagate(prev, mode) + uMask |= pMask + } + } + if (uMask == 0) ICPropagator.addNeighborChange(Point(x, y)) + propagationMask = 0xf + } + + override def propagateOther(mode: Int) { + val nonConn = ~(connMap | connMap >> 4 | connMap >> 8) & 0xf + notify(nonConn & propagationMask) + } + + def sideDiff(part: CircuitPart): Int = { + if (part.world == null) return 0xf + val here = Point(x, y) + val there = Point(part.x, part.y) + there - here match { + case Point(0, -1) => 1 << 0 + case Point(1, 0) => 1 << 1 + case Point(0, 1) => 1 << 2 + case Point(-1, 0) => 1 << 3 + case _ => + throw new RuntimeException( + s"Circuit array gate tried to propagate from $here to #$there" + ) + } + } + + override def calculateSignal: Int = { + val ipmask = toInternalMask(propagationMask) + if (getLogicArray.overrideSignal(ipmask)) + return getLogicArray.calculateSignal(ipmask) + + var s = 0 + ICPropagator.redwiresProvidePower = false + + def raise(sig: Int) { + if (sig > s) s = sig + } + + for (r <- 0 until 4) + if ((propagationMask & 1 << r) != 0) raise(calcSignal(r)) + ICPropagator.redwiresProvidePower = true + s + } + + abstract override def onChange() { + super.onChange() + ICPropagator.propagateTo(this, IWirePart.RISING) + } + + override def onSignalUpdate() { + world.network.markSave() + super.onChange() + getLogicArray.onSignalUpdate() + } + + override def resolveSignal(part: Any, r: Int) = part match { + case re: IRedwireICPart if re.diminishOnSide(r) => + re.getRedwireSignal(r) - 1 + case _ => super.resolveSignal(part, r) + } + + override def getRedwireSignal(r: Int) = { + val ir = toInternal(r) + val pmask = getLogicArray.propogationMask(ir) + if (pmask != 0) getLogicArray.getSignal(pmask) + else getLogicRS.getOutput(this, ir) + } + + override def canConnectRS(r: Int): Boolean = { + if (super.canConnectRS(r)) return true + getLogicArray.canConnectRedwire(this, toInternal(r)) + } + + override def rsOutputLevel(r: Int): Int = { + val ir = toInternal(r) + if ((getLogicArray.redwireMask(shape) & 1 << ir) != 0) + return if (ICPropagator.redwiresProvidePower) + getLogicArray.getSignal(getLogicArray.propogationMask(ir)) + else 0 + super.rsOutputLevel(r) + } + + override def diminishOnSide(r: Int) = + (getLogicArray.redwireMask(shape) & 1 << toInternal(r)) != 0 +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayICGateLogic.scala new file mode 100644 index 000000000..52aa1da9f --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TArrayICGateLogic.scala @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.circuitparts.wire.IRedwireICPart + +trait TArrayICGateLogic[T <: TArrayGateICPart] extends RedstoneICGateLogic[T] { + abstract override def canConnectTo(gate: T, part: CircuitPart, r: Int) = + part match { + case re: IRedwireICPart if canConnectRedwire(gate, r) => true + case _ => super.canConnectTo(gate, part, r) + } + + def canConnectRedwire(gate: T, r: Int): Boolean = + canConnectRedwire(gate.shape, r) + + def canConnectRedwire(shape: Int, r: Int): Boolean = + (redwireMask(shape) & 1 << r) != 0 + + def redwireMask(shape: Int): Int + + def propogationMask(r: Int): Int + + def getSignal(mask: Int): Int + + def setSignal(mask: Int, signal: Int) + + def overrideSignal(mask: Int) = false + + def calculateSignal(mask: Int) = 0 + + def canCross = false + + def onSignalUpdate() +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TClientNetCircuitPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TClientNetCircuitPart.scala new file mode 100644 index 000000000..eb97b5693 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TClientNetCircuitPart.scala @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import cpw.mods.fml.relauncher.{Side, SideOnly} + +trait TClientNetCircuitPart extends CircuitPart { + def readClientPacket(in: MCDataInput) + + @SideOnly(Side.CLIENT) + def sendClientPacket(writer: MCDataOutput => Unit = { _ => }) { + world.sendClientPacket(this, writer) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexGateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexGateICPart.scala new file mode 100644 index 000000000..003f3c957 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexGateICPart.scala @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import net.minecraft.nbt.NBTTagCompound + +trait TComplexGateICPart extends GateICPart { + def getLogicComplex = getLogic[TComplexICGateLogic[TComplexGateICPart]] + + def assertLogic() + + abstract override def save(tag: NBTTagCompound) { + super.save(tag) + getLogicComplex.save(tag) + } + + abstract override def load(tag: NBTTagCompound) { + super.load(tag) + assertLogic() + getLogicComplex.load(tag) + } + + abstract override def writeDesc(packet: MCDataOutput) { + super.writeDesc(packet) + getLogicComplex.writeDesc(packet) + } + + abstract override def readDesc(packet: MCDataInput) { + super.readDesc(packet) + assertLogic() + getLogicComplex.readDesc(packet) + } + + abstract override def read(packet: MCDataInput, key: Int) = key match { + case k if k > 10 => + assertLogic() // this may be a net dump part + getLogicComplex.read(packet, k) + case _ => super.read(packet, key) + } + + abstract override def preparePlacement( + rotation: Int, + configuration: Int, + meta: Int + ) { + super.preparePlacement(rotation, configuration, meta) + assertLogic() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexICGateLogic.scala new file mode 100644 index 000000000..852a19403 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TComplexICGateLogic.scala @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import net.minecraft.nbt.NBTTagCompound + +trait TComplexICGateLogic[T <: TComplexGateICPart] extends ICGateLogic[T] { + def save(tag: NBTTagCompound) {} + + def load(tag: NBTTagCompound) {} + + def readDesc(packet: MCDataInput) {} + + def writeDesc(packet: MCDataOutput) {} + + /** Allocated keys > 10 + */ + def read(packet: MCDataInput, key: Int) {} +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TConnectableICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TConnectableICPart.scala new file mode 100644 index 000000000..b9c154bae --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TConnectableICPart.scala @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +trait TConnectableICPart extends CircuitPart with TICAcquisitions { + var connMap: Byte = 0 + + def maskConnects(r: Int) = (connMap & 1 << r) != 0 + + def discover(r: Int) = getStraight(r) match { + case c: TConnectableICPart => + canConnectPart(c, r) && c.connect(this, rotFromStraight(r)) + case c => discoverOverride(r, c) + } + + def discoverOverride(r: Int, part: CircuitPart) = false + + def connect(part: CircuitPart, r: Int) = { + if (canConnectPart(part, r)) { + val oldConn = connMap + connMap = (connMap | 1 << r).toByte + if (oldConn != connMap) onMaskChanged() + true + } else false + } + + def updateConns() = { + var newConn = 0 + for (r <- 0 until 4) if (discover(r)) newConn |= 1 << r + if (newConn != connMap) { + connMap = newConn.toByte + onMaskChanged() + true + } else false + } + + def canConnectPart(part: CircuitPart, r: Int): Boolean + + def onMaskChanged() {} +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TErrorCircuitPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TErrorCircuitPart.scala new file mode 100644 index 000000000..12e73b7b2 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TErrorCircuitPart.scala @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +trait TErrorCircuitPart extends CircuitPart { + def postErrors: (String, Int) // (message, colour) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TExtraStateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TExtraStateLogic.scala new file mode 100644 index 000000000..ca2853843 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TExtraStateLogic.scala @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import net.minecraft.nbt.NBTTagCompound + +trait TExtraStateLogic extends SequentialICGateLogic { + private var lState2: Byte = 0 + + def state2 = lState2 & 0xff + + def setState2(state: Int) { + lState2 = state.toByte + } + + def clientState2 = false + + abstract override def save(tag: NBTTagCompound) { + super.save(tag) + tag.setByte("state2", lState2) + } + + abstract override def load(tag: NBTTagCompound) { + super.load(tag) + lState2 = tag.getByte("state2") + } + + abstract override def writeDesc(packet: MCDataOutput) { + super.writeDesc(packet) + if (clientState2) packet.writeByte(lState2) + } + + abstract override def readDesc(packet: MCDataInput) { + super.readDesc(packet) + if (clientState2) lState2 = packet.readByte() + } + + abstract override def read(packet: MCDataInput, key: Int) = key match { + case 11 => lState2 = packet.readByte() + case _ => super.read(packet, key) + } + + def sendState2Update() { + gate.writeStreamOf(11).writeByte(lState2) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICAcquisitions.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICAcquisitions.scala new file mode 100644 index 000000000..e9a7641aa --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICAcquisitions.scala @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.core.vec.Point + +trait TICAcquisitions extends CircuitPart { + def getStraight(r: Int) = world.getPart(posOfStraight(r)) + + def posOfStraight(r: Int) = Point(x, y).offset(r) + + def rotFromStraight(r: Int) = (r + 2) % 4 + + def notifyToDir(r: Int) { + world.notifyNeighbor(posOfStraight(r)) + } + + def notify(mask: Int) { + world.notifyNeighbors(x, y, mask) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICBundledAcquisitions.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICBundledAcquisitions.scala new file mode 100644 index 000000000..9e0669cf5 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICBundledAcquisitions.scala @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +trait TICBundledAcquisitions extends TICAcquisitions { + def calcArray(r: Int): Array[Byte] = + resolveArray(getStraight(r), rotFromStraight(r)) + + def resolveArray(part: Any, r: Int): Array[Byte] +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICOrient.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICOrient.scala new file mode 100644 index 000000000..c0b5d0cf6 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICOrient.scala @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import codechicken.lib.vec.{Rotation, Vector3} + +trait TICOrient extends CircuitPart { + var orientation: Byte = 0 + + def rotation = orientation & 0x3 + + def setRotation(r: Int) { + orientation = (orientation & 0xfc | r).toByte + } + + def rotationT = + Rotation.quarterRotations(rotation).at(new Vector3(0.5, 0, 0.5)) + + // internal r from absRot + def toInternal(absRot: Int) = (absRot + 4 - rotation) % 4 + + // absRot from internal r + def toAbsolute(r: Int) = (r + rotation) % 4 + + def toInternalMask(mask: Int) = TICOrient.shiftMask(mask, toInternal(0)) + + def toAbsoluteMask(mask: Int) = TICOrient.shiftMask(mask, toAbsolute(0)) +} + +object TICOrient { + def shiftMask(mask: Int, r: Int) = + (mask & ~0xf) | (mask << r | mask >> 4 - r) & 0xf + + def flipMaskZ(mask: Int) = mask & 5 | mask << 2 & 8 | mask >> 2 & 2 +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICRSAcquisitions.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICRSAcquisitions.scala new file mode 100644 index 000000000..fd82e77e5 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TICRSAcquisitions.scala @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +trait TICRSAcquisitions extends TICAcquisitions with TPoweredCircuitPart { + def calcSignal(r: Int): Int = + resolveSignal(getStraight(r), rotFromStraight(r)) + + def resolveSignal(part: Any, r: Int): Int +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPoweredCircuitPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPoweredCircuitPart.scala new file mode 100644 index 000000000..5b3aea5e2 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPoweredCircuitPart.scala @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +trait TPoweredCircuitPart { + def rsOutputLevel(r: Int): Int + + def canConnectRS(r: Int): Boolean +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPropagatingICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPropagatingICPart.scala new file mode 100644 index 000000000..4a64936fd --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TPropagatingICPart.scala @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.core.vec.Point +import IWireICPart.FORCED +import mrtjp.projectred.fabrication.ICPropagator + +trait TPropagatingICPart + extends CircuitPart + with TConnectableICPart + with IWireICPart { + var propagationMask = 0xf + + def propagate(prev: CircuitPart, mode: Int) { + if (mode != FORCED) ICPropagator.addPartChange(this) + for (r <- 0 until 4) + if ((propagationMask & 1 << r) != 0) + if (maskConnects(r)) + propagateExternal(getStraight(r), posOfStraight(r), prev, mode) + + propagateOther(mode) + } + + def propagateOther(mode: Int) {} + + def propagateExternal( + to: CircuitPart, + at: Point, + from: CircuitPart, + mode: Int + ) { + if (to != null) { + if (to == from) return + if (propagateTo(to, mode)) return + } + ICPropagator.addNeighborChange(at) + } + + def propagateTo(part: CircuitPart, mode: Int) = part match { + case w: IWireICPart => + ICPropagator.propagateTo(w, this, mode) + true + case _ => false + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TRSPropagatingICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TRSPropagatingICPart.scala new file mode 100644 index 000000000..a384e1327 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TRSPropagatingICPart.scala @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import mrtjp.projectred.fabrication.ICPropagator +import IWireICPart._ + +trait TRSPropagatingICPart extends TPropagatingICPart { + def calculateSignal: Int + + def getSignal: Int + + def setSignal(signal: Int) + + override def updateAndPropagate(prev: CircuitPart, mode: Int) { + if (mode == DROPPING && getSignal == 0) return + val newSignal = calculateSignal + if (newSignal < getSignal) { + if (newSignal > 0) ICPropagator.propagateAnalogDrop(this) + setSignal(0) + propagate(prev, DROPPING) + } else if (newSignal > getSignal) { + setSignal(newSignal) + if (mode == DROPPING) propagate(null, RISING) + else propagate(prev, RISING) + } else if (mode == DROPPING) propagateTo(prev, RISING) + else if (mode == FORCE) propagate(prev, FORCED) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TSimpleRSICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TSimpleRSICGateLogic.scala new file mode 100644 index 000000000..f62acd62f --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/TSimpleRSICGateLogic.scala @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts + +import cpw.mods.fml.relauncher.{Side, SideOnly} + +trait TSimpleRSICGateLogic[T <: RedstoneGateICPart] + extends RedstoneICGateLogic[T] { + def getDelay(shape: Int) = 0 + + def feedbackMask(shape: Int) = 0 + + def calcOutput(gate: T, input: Int) = 0 + + override def onChange(gate: T) { + val iMask = inputMask(gate.shape) + val oMask = outputMask(gate.shape) + val fMask = feedbackMask(gate.shape) + val oldInput = gate.state & 0xf + val newInput = getInput(gate, iMask | fMask) + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + } + + val newOutput = calcOutput(gate, gate.state & iMask) & oMask + if (newOutput != (gate.state >> 4)) gate.scheduleTick(getDelay(gate.shape)) + } + + override def scheduledTick(gate: T) { + val iMask = inputMask(gate.shape) + val oMask = outputMask(gate.shape) + val oldOutput = gate.state >> 4 + val newOutput = calcOutput(gate, gate.state & iMask) & oMask + if (oldOutput != newOutput) { + gate.setState(gate.state & 0xf | newOutput << 4) + gate.onOutputChange(oMask) + } + onChange(gate) + } + + override def setup(gate: T) { + val iMask = inputMask(gate.shape) + val oMask = outputMask(gate.shape) + val output = calcOutput(gate, getInput(gate, iMask)) & oMask + if (output != 0) { + gate.setState(output << 4) + gate.onOutputChange( + output + ) // use output for change mask because nothing is going low + } + } + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: T, detailLevel: Int) = { + val s = Seq.newBuilder[String] + if (detailLevel > 2) + s += "I: " + rolloverInput(gate) += "O: " + rolloverOutput(gate) + super.getRolloverData(gate, detailLevel) ++ s.result() + } + def rolloverInput(gate: T) = "0x" + Integer.toHexString(gate.state & 0xf) + def rolloverOutput(gate: T) = "0x" + Integer.toHexString(gate.state >> 4) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/BufferCell.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/BufferCell.scala new file mode 100644 index 000000000..472596073 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/BufferCell.scala @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.cells + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + ArrayGateICLogicCrossing, + ArrayGateICPart, + ICGateRenderer +} + +class BufferCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { + override def powerUp = (gate.state & 2) == 0 +} + +class RenderBufferCell extends ICGateRenderer[ArrayGateICPart] { + val wires = generateWireModels("BUFFCELL", 2) + val torches = + Seq(new RedstoneTorchModel(11, 13), new RedstoneTorchModel(8, 8)) + val top = new CellTopWireModel + val bottom = new InvertCellBottomWireModel + + override val coreModels = + Seq(new BaseComponentModel("BUFFCELL")) ++ wires ++ Seq( + bottom + ) ++ torches ++ Seq(new CellStandModel, top) + + override def prepareStatic(configuration: Int): Unit = { + bottom.signal = 0 + top.signal = 0 + wires(0).on = false + wires(1).on = true + torches(0).on = true + torches(1).on = false + } + + override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { + val logic = gate.getLogic[BufferCell] + bottom.signal = logic.signal1 + top.signal = logic.signal2 + torches(0).on = logic.signal1 == 0 + torches(1).on = logic.signal1 != 0 + wires(0).on = logic.signal1 != 0 + wires(1).on = logic.signal1 == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/InvertCell.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/InvertCell.scala new file mode 100644 index 000000000..a6c0daf08 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/InvertCell.scala @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.cells + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + ArrayGateICLogicCrossing, + ArrayGateICPart, + ICGateRenderer +} + +class InvertCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { + override def powerUp = (gate.state & 2) != 0 +} + +class RenderInvertCell extends ICGateRenderer[ArrayGateICPart] { + val wires = generateWireModels("INVCELL", 1) + val torch = new RedstoneTorchModel(8, 8) + val top = new CellTopWireModel + val bottom = new InvertCellBottomWireModel + + override val coreModels = Seq( + new BaseComponentModel("INVCELL") + ) ++ wires ++ Seq(bottom, torch, new CellStandModel, top) + + override def prepareStatic(configuration: Int): Unit = { + bottom.signal = 0 + top.signal = 255.toByte + wires(0).on = false + torch.on = true + } + + override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { + val logic = gate.getLogic[InvertCell] + bottom.signal = logic.signal1 + top.signal = logic.signal2 + wires(0).on = logic.signal1 != 0 + torch.on = logic.signal1 == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/NullCell.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/NullCell.scala new file mode 100644 index 000000000..325867403 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/cells/NullCell.scala @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.cells + +import mrtjp.projectred.fabrication.circuitparts.{ + ArrayGateICLogicCrossing, + ArrayGateICPart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + CellStandModel, + CellTopWireModel, + NullCellBottomWireModel +} + +class NullCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { + override def powerUp = false +} + +class RenderNullCell extends ICGateRenderer[ArrayGateICPart] { + val top = new CellTopWireModel + val bottom = new NullCellBottomWireModel + + override val coreModels = + Seq(new BaseComponentModel("NULLCELL"), bottom, new CellStandModel, top) + + override def prepareStatic(configuration: Int): Unit = { + bottom.signal = 0 + top.signal = 0 + } + + override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { + bottom.signal = gate.getLogic[NullCell].signal1 + top.signal = gate.getLogic[NullCell].signal2 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/AnalogIO.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/AnalogIO.scala new file mode 100644 index 000000000..b23c20f05 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/AnalogIO.scala @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import mrtjp.projectred.fabrication.ICComponentStore.signalColour + +class AnalogIOICGateLogic(gate: IOGateICPart) + extends IOICGateLogic(gate) + with TFreqIOICGateLogic + with TRSIOICGateLogic { + override def getConnMode(gate: IOGateICPart) = TIOCircuitPart.Analog + + override def getFreqName = "0x" + Integer.toHexString(freq) + + override def toggleWorldInput() { + val newInput = (gate.world.iostate(gate.rotation) & 1 << freq) ^ 1 << freq + gate.world.setInput(gate.rotation, if (newInput == 0) 1 else newInput) + } +} + +class RenderAnalogIO extends RenderIO { + override def invColour = signalColour(0.toByte) + override def dynColour(gate: IOGateICPart) = signalColour( + (gate.getLogic[AnalogIOICGateLogic].freq * 17).toByte + ) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/BundledIO.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/BundledIO.scala new file mode 100644 index 000000000..141cd5278 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/BundledIO.scala @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import mrtjp.core.color.Colors + +class BundledIOICGateLogic(gate: IOGateICPart) + extends IOICGateLogic(gate) + with TFreqIOICGateLogic { + override def getConnMode(gate: IOGateICPart) = TIOCircuitPart.Bundled + + override def getFreqName = Colors(freq).name.toLowerCase + + override def toggleWorldInput() { + gate.world.setInput( + gate.rotation, + (gate.world.iostate(gate.rotation) & 0xffff) ^ 1 << freq + ) + } +} + +class RenderBundledIO extends RenderIO { + override def invColour = Colors(0).rgba + override def dynColour(gate: IOGateICPart) = Colors( + gate.getLogic[AnalogIOICGateLogic].freq + ).rgba +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOGateICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOGateICPart.scala new file mode 100644 index 000000000..3afc58fad --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOGateICPart.scala @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import codechicken.lib.data.MCDataInput +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPartDefs, + RedstoneGateICPart, + TComplexGateICPart +} +import mrtjp.projectred.fabrication.gui.nodes.configuration.{ + ConfigurationAnalogIO, + ConfigurationBundledIO, + ConfigurationSimpleIO +} +import mrtjp.projectred.fabrication.gui.nodes.{ConfigurationNode, TConfigurable} + +class IOGateICPart + extends RedstoneGateICPart + with TIOCircuitPart + with TComplexGateICPart + with TConfigurable { + private var logic: IOICGateLogic = null + + override def getLogic[T] = logic.asInstanceOf[T] + + def getLogicIO = getLogic[IOICGateLogic] + + override def assertLogic() { + if (logic == null) logic = IOICGateLogic.create(this, subID) + } + + override def readClientPacket(in: MCDataInput, key: Int) = key match { + case 5 => + getLogicIO match { + case f: TFreqIOICGateLogic => + f.freq = in.readByte() + f.sendFreqUpdate() + f.gate.onChange() + case _ => + } + case 6 => + getLogicIO match { + case f: IOICGateLogic => + f.gate.setShape(in.readByte()) + this.sendShapeUpdate() + f.gate.onChange() + case _ => + } + case _ => super.readClientPacket(in, key) + } + + def sendFrequency(color: Int): Unit = { + sendClientPacket(_.writeByte(5).writeByte(color)) + } + + override def getPartType = CircuitPartDefs.IOGate + + override def onExtInputChanged(r: Int) { + if (r == rotation) getLogicIO.extInputChange(this) + } + + override def onExtOutputChanged(r: Int) { + if (r == rotation) getLogicIO.extOutputChange(this) + } + + override def getIOSide = rotation + + override def getIOMode = getLogicIO.getIOMode(this) + + override def getConnMode = getLogicIO.getConnMode(this) + + override def getRedstoneInput(r: Int): Int = { + if (r == 0) getLogicIO.resolveInputFromWorld // r is to outside world + else super.getRedstoneInput(r) + } + + override def onOutputChange(mask: Int) { + super.onOutputChange(mask) + if ((mask & 1) != 0) { + val oldOutput = world.iostate(rotation) >>> 16 + getLogicIO.setWorldOutput((state & 0x10) != 0) + val newOutput = world.iostate(rotation) >>> 16 + if (oldOutput != newOutput) world.onOutputChanged(1 << rotation) + } + } + + override def createConfigurationNode: ConfigurationNode = { + getLogicIO match { + case _: BundledIOICGateLogic => + new ConfigurationBundledIO(this) + case _: SimpleIOICGateLogic => + new ConfigurationSimpleIO(this) + case _: AnalogIOICGateLogic => + new ConfigurationAnalogIO(this) + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOICGateLogic.scala new file mode 100644 index 000000000..ae6e1c9c5 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/IOICGateLogic.scala @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateDefinition, + RedstoneICGateLogic, + TComplexICGateLogic, + TICOrient +} + +object IOICGateLogic { + def create(gate: IOGateICPart, subID: Int) = subID match { + case ICGateDefinition.IOSimple.ordinal => new SimpleIOICGateLogic(gate) + case ICGateDefinition.IOAnalog.ordinal => new AnalogIOICGateLogic(gate) + case ICGateDefinition.IOBundled.ordinal => new BundledIOICGateLogic(gate) + case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) + } + + def cycleShape(shape: Int): Int = { + (shape + 1) % 3 + } +} + +abstract class IOICGateLogic(val gate: IOGateICPart) + extends RedstoneICGateLogic[IOGateICPart] + with TComplexICGateLogic[IOGateICPart] { + + import TIOCircuitPart._ + + override def inputMask(shape: Int) = shape match { + case 0 => 1 + case 1 => 4 + case 2 => 5 + } + + override def outputMask(shape: Int) = shape match { + case 0 => 4 + case 1 => 1 + case 2 => 5 + } + + override def cycleShape(gate: IOGateICPart): Boolean = { + gate.setShape(IOICGateLogic.cycleShape(gate.shape)) + true + } + + def extInputChange(gate: IOGateICPart) { + gate.onChange() + } + + def extOutputChange(gate: IOGateICPart) {} + + def getIOMode(gate: IOGateICPart): Int = gate.shape match { + case 0 => Input + case 1 => Output + case 2 => InOut + } + + def getConnMode(gate: IOGateICPart): Int + + def resolveInputFromWorld: Int + + def resolveOutputToWorld: Int + + def setWorldOutput(state: Boolean) + + def toggleWorldInput() + + override def onChange(gate: IOGateICPart) { + val oldInput = gate.state & 0xf + val newInput = getInput(gate, ~(gate.state >> 4) & inputMask(gate.shape)) + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + gate.scheduleTick(0) + } + } + + override def scheduledTick(gate: IOGateICPart) { + val oldOutput = gate.state >> 4 + val newOutput = + TICOrient.shiftMask(gate.state & 0xf, 2) & outputMask(gate.shape) + if (oldOutput != newOutput) { + gate.setState(gate.state & 0xf | newOutput << 4) + gate.onOutputChange(oldOutput ^ newOutput) + } + onChange(gate) + } + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: IOGateICPart, detailLevel: Int) = { + val s = Seq.newBuilder[String] + if (detailLevel >= 2) { + val f = getFreqName + if (f.nonEmpty) s += "freq: " + f + s += "mode: " + (gate.shape match { + case 0 => "I" + case 1 => "O" + case 2 => "IO" + }) + } + if (detailLevel >= 3) { + s += "I: " + (if (resolveInputFromWorld != 0) "high" else "low") + s += "O: " + (if (resolveOutputToWorld != 0) "high" else "low") + } + super.getRolloverData(gate, detailLevel) ++ s.result() + } + + def getFreqName = "" + + override def activate(gate: IOGateICPart) { + toggleWorldInput() + gate.world.onInputChanged(1 << gate.rotation) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/RenderIO.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/RenderIO.scala new file mode 100644 index 000000000..e195052f7 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/RenderIO.scala @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.ICGateRenderer +import mrtjp.projectred.fabrication.{ArrowModel, BaseComponentModel, IOSigModel} + +abstract class RenderIO extends ICGateRenderer[IOGateICPart] { + val wires = generateWireModels("IOSIMP", 1) + val iosig = new IOSigModel + val arrow = new ArrowModel + + override val coreModels = + Seq(new BaseComponentModel("IOSIMP")) ++ wires :+ iosig :+ arrow + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + iosig.on = false + iosig.colour = invColour + arrow.arrowDirection = configuration + } + + override def prepareDynamic(gate: IOGateICPart, frame: Float) { + wires(0).on = (gate.state & 0x44) != 0 + iosig.on = wires(0).on + iosig.colour = dynColour(gate) + arrow.arrowDirection = gate.shape + } + + def invColour: Int + + def dynColour(gate: IOGateICPart): Int +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/SimpleIO.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/SimpleIO.scala new file mode 100644 index 000000000..f027ca104 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/SimpleIO.scala @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import mrtjp.projectred.fabrication.ICComponentStore.signalColour + +class SimpleIOICGateLogic(gate: IOGateICPart) + extends IOICGateLogic(gate) + with TRSIOICGateLogic { + override def getConnMode(gate: IOGateICPart) = TIOCircuitPart.Simple + + override def resolveInputFromWorld = + if ((gate.world.iostate(gate.rotation) & 0xfffe) != 0) 255 + else 0 + + override def resolveOutputToWorld = + if (((gate.world.iostate(gate.rotation) >> 16) & 0xfffe) != 0) 255 else 0 + + override def setWorldOutput(state: Boolean) { + gate.world.setOutput(gate.rotation, if (state) 0x8000 else 1) + } + + override def toggleWorldInput() { + gate.world.setInput( + gate.rotation, + if ((gate.world.iostate(gate.rotation) & 0x8000) != 0) 1 else 0x8000 + ) + } +} + +class RenderSimpleIO extends RenderIO { + override def invColour = signalColour(0.toByte) + override def dynColour(gate: IOGateICPart) = signalColour( + (if (iosig.on) 255 else 0).toByte + ) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TFreqIOICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TFreqIOICGateLogic.scala new file mode 100644 index 000000000..bff3b5e8f --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TFreqIOICGateLogic.scala @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import net.minecraft.nbt.NBTTagCompound + +trait TFreqIOICGateLogic extends IOICGateLogic { + var freq = 0 + + override def save(tag: NBTTagCompound) { + super.save(tag) + tag.setByte("freq", freq.toByte) + } + + override def load(tag: NBTTagCompound) { + super.load(tag) + freq = tag.getByte("freq") + } + + override def writeDesc(out: MCDataOutput) { + super.writeDesc(out) + out.writeByte(freq) + } + + override def readDesc(in: MCDataInput) { + super.readDesc(in) + freq = in.readUByte() + } + + override def read(in: MCDataInput, key: Int) = key match { + case 12 => freq = in.readUByte() + case _ => super.read(in, key) + } + + def sendFreqUpdate() { + gate.writeStreamOf(12).writeByte(freq) + } + + override def resolveInputFromWorld = + if ((gate.world.iostate(gate.rotation) & 1 << freq) != 0) 255 + else 0 + + override def resolveOutputToWorld = + if ((gate.world.iostate(gate.rotation) >>> 16 & 1 << freq) != 0) 255 + else 0 + + override def setWorldOutput(state: Boolean) { + val s = + ((gate.world.iostate(gate.rotation) >>> 16) & ~(1 << freq)) | (if (state) + 1 + else + 0) << freq + gate.world.setOutput(gate.rotation, s) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TIOCircuitPart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TIOCircuitPart.scala new file mode 100644 index 000000000..fe05033aa --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TIOCircuitPart.scala @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +object TIOCircuitPart { + val Closed = 0 + val Input = 1 + val Output = 2 + val InOut = 3 + + val NoConn = 0 + val Simple = 1 + val Analog = 2 + val Bundled = 3 +} + +trait TIOCircuitPart { + def onExtInputChanged(r: Int) + + def onExtOutputChanged(r: Int) + + def getIOSide: Int + + def getIOMode: Int + + def getConnMode: Int +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TRSIOICGateLogic.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TRSIOICGateLogic.scala new file mode 100644 index 000000000..422f72504 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/io/TRSIOICGateLogic.scala @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.io + +trait TRSIOICGateLogic extends IOICGateLogic { + override def setup(gate: IOGateICPart) { + if ((gate.world.iostate(gate.rotation) & 0xffff) == 0) { + gate.world.setInput(gate.rotation, 1) + gate.world.onInputChanged(1 << gate.rotation) + } + } + + override def extInputChange(gate: IOGateICPart) { + if ((gate.world.iostate(gate.rotation) & 0xffff) == 0) { + gate.world.setInput(gate.rotation, 1) + gate.world.onInputChanged(1 << gate.rotation) + } + super.extInputChange(gate) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/SRLatch.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/SRLatch.scala new file mode 100644 index 000000000..d9ce7055a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/SRLatch.scala @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.latches + +import mrtjp.projectred.core.TFaceOrient.{flipMaskZ, shiftMask} +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic, + TExtraStateLogic +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object SRLatch { + def cycleShape(shape: Int): Int = { + (shape + 1) % 4 + } +} + +class SRLatch(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with TExtraStateLogic { + override def outputMask(shape: Int) = if ((shape >> 1) == 0) 0xf else 5 + override def inputMask(shape: Int) = 0xa + + override def cycleShape(gate: SequentialGateICPart) = { + gate.setShape(SRLatch.cycleShape(gate.shape)) + setState2(flipMaskZ(state2)) + gate.setState(flipMaskZ(gate.state)) + gate.onOutputChange(0xf) + gate.scheduleTick(0) + true + } + + override def setup(gate: SequentialGateICPart) { + setState2(2) + gate.setState(0x30) + } + + override def onChange(gate: SequentialGateICPart) { + val stateInput = state2 + + val oldInput = gate.state & 0xf + val newInput = getInput(gate, 0xa) + val oldOutput = gate.state >> 4 + + if (newInput != oldInput) + if ( + stateInput != 0xa && newInput != 0 && newInput != stateInput + ) // state needs changing + { + gate.setState(newInput) + setState2(newInput) + gate.onOutputChange(oldOutput) // always going low + gate.scheduleTick(0) + } else { + gate.setState(oldOutput << 4 | newInput) + gate.onInputChange() + } + } + + override def scheduledTick(gate: SequentialGateICPart) { + val oldOutput = gate.state >> 4 + val newOutput = calcOutput(gate) + + if (oldOutput != newOutput) { + gate.setState(gate.state & 0xf | newOutput << 4) + gate.onOutputChange(outputMask(gate.shape)) + } + onChange(gate) + } + + def calcOutput(gate: SequentialGateICPart): Int = { + var input = gate.state & 0xf + var stateInput = state2 + + if ((gate.shape & 1) != 0) // reverse + { + input = flipMaskZ(input) + stateInput = flipMaskZ(stateInput) + } + + if (stateInput == 0xa) // disabled + { + if (input == 0xa) { + gate.scheduleTick(0) + return 0 + } + + stateInput = + if (input == 0) + if (gate.world.network.getWorld.rand.nextBoolean()) 2 else 8 + else input + + setState2( + if ((gate.shape & 1) != 0) flipMaskZ(stateInput) else stateInput + ) + } + + var output = shiftMask(stateInput, 1) + if ((gate.shape & 2) == 0) output |= stateInput + if ((gate.shape & 1) != 0) output = flipMaskZ(output) // reverse + output + } +} + +class RenderSRLatch extends ICGateRenderer[SequentialGateICPart] { + val wires1 = generateWireModels("RSLATCH", 2) + val wires2 = generateWireModels("RSLATCH2", 4) + val torches1 = + Seq(new RedstoneTorchModel(8, 3), new RedstoneTorchModel(8, 13)) + val torches2 = + Seq(new RedstoneTorchModel(9.5, 3), new RedstoneTorchModel(6.5, 13)) + val base1 = new BaseComponentModel("RSLATCH") + val base2 = new BaseComponentModel("RSLATCH2") + + val m1 = Seq(base1) ++ wires1 ++ torches1 + val m2 = Seq(base2) ++ wires2 ++ torches2 + + var shape = 0 + + override val coreModels = Seq() + + override def switchModels = if (shape == 0) m1 else m2 + + override def prepareStatic(configuration: Int): Unit = { + reflect = (configuration & 1) != 0 + shape = configuration >> 1 + var state = Seq(96, 48, 64, 16)(configuration) + if (reflect) state = flipMaskZ(state >> 4) << 4 | flipMaskZ(state) + if (shape == 0) { + wires1(0).on = (state & 0x88) != 0 + wires1(1).on = (state & 0x22) != 0 + torches1(0).on = (state & 0x10) != 0 + torches1(1).on = (state & 0x40) != 0 + } else { + wires2(1).on = (state & 2) != 0 + wires2(3).on = (state & 8) != 0 + torches2(0).on = (state & 0x10) != 0 + torches2(1).on = (state & 0x40) != 0 + wires2(0).on = torches2(1).on + wires2(2).on = torches2(0).on + } + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + reflect = (gate.shape & 1) != 0 + shape = gate.shape >> 1 + var state = gate.state + if (reflect) state = flipMaskZ(state >> 4) << 4 | flipMaskZ(state) + if (shape == 0) { + wires1(0).on = (state & 0x88) != 0 + wires1(1).on = (state & 0x22) != 0 + torches1(0).on = (state & 0x10) != 0 + torches1(1).on = (state & 0x40) != 0 + } else { + wires2(1).on = (state & 2) != 0 + wires2(3).on = (state & 8) != 0 + torches2(0).on = (state & 0x10) != 0 + torches2(1).on = (state & 0x40) != 0 + wires2(0).on = torches2(1).on + wires2(2).on = torches2(0).on + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/ToggleLatch.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/ToggleLatch.scala new file mode 100644 index 000000000..69ad4b9e8 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/ToggleLatch.scala @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.latches + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic, + TExtraStateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + LeverModel, + RedstoneTorchModel +} + +class ToggleLatch(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with TExtraStateLogic { + override def outputMask(shape: Int) = 5 + override def inputMask(shape: Int) = 0xa + + override def clientState2 = true + + override def setup(gate: SequentialGateICPart) { + gate.setState(0x10) + gate.sendStateUpdate() + } + + override def onChange(gate: SequentialGateICPart) { + val oldInput = gate.state & 0xf + val newInput = getInput(gate, 0xa) + val high = newInput & ~oldInput + + if (high == 2 || high == 8) toggle(gate) + + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + } + } + + override def scheduledTick(gate: SequentialGateICPart) { + val oldOutput = gate.state >> 4 + val newOutput = if (state2 == 0) 1 else 4 + if (oldOutput != newOutput) { + gate.setState(newOutput << 4 | gate.state & 0xf) + gate.onOutputChange(5) + } + onChange(gate) + } + + override def activate(gate: SequentialGateICPart) { + toggle(gate) + } + + def toggle(gate: SequentialGateICPart) { + setState2(state2 ^ 1) + gate.scheduleTick(0) + } +} + +class RenderToggleLatch extends ICGateRenderer[SequentialGateICPart] { + val wires = generateWireModels("TOGLATCH", 2) + val torches = Seq(new RedstoneTorchModel(4, 4), new RedstoneTorchModel(4, 12)) + val lever = new LeverModel(11, 8) + + override val coreModels = + Seq(new BaseComponentModel("TOGLATCH")) ++ wires ++ torches :+ lever + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(1).on = false + torches(0).on = true + torches(1).on = false + lever.on = true + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + wires(0).on = (gate.state & 8) != 0 + wires(1).on = (gate.state & 2) != 0 + torches(0).on = (gate.state & 0x10) != 0 + torches(1).on = (gate.state & 0x40) != 0 + lever.on = (gate.state & 0x10) != 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/TransparentLatch.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/TransparentLatch.scala new file mode 100644 index 000000000..caccb6c4b --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/latches/TransparentLatch.scala @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.latches + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object TransparentLatch extends ComboICGateLogic { + override def outputMask(shape: Int) = if (shape == 0) 3 else 9 + override def inputMask(shape: Int) = if (shape == 0) 0xc else 6 + + override def cycleShape(shape: Int) = shape ^ 1 + + override def calcOutput(gate: ComboICGatePart, input: Int) = { + if ((input & 4) == 0) gate.state >> 4 + else if ((input & 0xa) == 0) 0 + else 0xf + } +} + +class RenderTransparentLatch extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("TRANSLATCH", 5) + val torches = Seq( + new RedstoneTorchModel(4, 12.5), + new RedstoneTorchModel(4, 8), + new RedstoneTorchModel(8, 8), + new RedstoneTorchModel(8, 2), + new RedstoneTorchModel(14, 8) + ) + + override val coreModels = + Seq(new BaseComponentModel("TRANSLATCH")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + reflect = configuration == 1 + wires(0).on = true + wires(1).on = false + wires(2).on = true + wires(3).on = false + wires(4).on = false + torches(0).on = true + torches(1).on = false + torches(2).on = true + torches(3).on = false + torches(4).on = false + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + reflect = gate.shape == 1 + val on = (gate.state & 0x10) != 0 + wires(0).on = !on + wires(1).on = (gate.state & 4) != 0 + wires(2).on = (gate.state & 4) == 0 + wires(3).on = on + wires(4).on = (gate.state & 0xa) != 0 + torches(0).on = wires(2).on + torches(1).on = !wires(2).on && !wires(4).on + torches(2).on = !wires(1).on && !wires(3).on + torches(3).on = on + torches(4).on = on + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Counter.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Counter.scala new file mode 100644 index 000000000..21c61d2dc --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Counter.scala @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.misc + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.math.MathHelper +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.core.TFaceOrient.flipMaskZ +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + GateICPart, + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + PointerModel, + RedstoneTorchModel +} +import net.minecraft.nbt.NBTTagCompound + +trait ICounterGuiLogic { + def getCounterMax: Int + def setCounterMax(gate: GateICPart, i: Int) + + def getCounterIncr: Int + def setCounterIncr(gate: GateICPart, i: Int) + + def getCounterDecr: Int + def setCounterDecr(gate: GateICPart, i: Int) + + def getCounterValue: Int + def setCounterValue(gate: GateICPart, i: Int) +} + +object Counter { + def cycleShape(shape: Int): Int = { + if (shape == 1) 0 else 1 + } +} + +class Counter(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with ICounterGuiLogic { + var value = 0 + var max = 10 + var incr = 1 + var decr = 1 + + override def outputMask(shape: Int) = 5 + override def inputMask(shape: Int) = 10 + + override def save(tag: NBTTagCompound) { + tag.setInteger("val", value) + tag.setInteger("max", max) + tag.setInteger("inc", incr) + tag.setInteger("dec", decr) + } + + override def load(tag: NBTTagCompound) { + value = tag.getInteger("val") + max = tag.getInteger("max") + incr = tag.getInteger("inc") + decr = tag.getInteger("dec") + } + + override def writeDesc(packet: MCDataOutput) { + packet.writeInt(value).writeInt(max).writeInt(incr).writeInt(decr) + } + + override def readDesc(packet: MCDataInput) { + value = packet.readInt() + max = packet.readInt() + incr = packet.readInt() + decr = packet.readInt() + } + + override def read(packet: MCDataInput, key: Int) = key match { + case 11 => value = packet.readInt() + case 12 => max = packet.readInt() + case 13 => incr = packet.readInt() + case 14 => decr = packet.readInt() + case _ => + } + + def sendValueUpdate() { gate.writeStreamOf(11).writeInt(value) } + def sendMaxUpdate() { gate.writeStreamOf(12).writeInt(max) } + def sendIncrUpdate() { gate.writeStreamOf(13).writeInt(incr) } + def sendDecrUpdate() { gate.writeStreamOf(14).writeInt(decr) } + + override def getCounterValue = value + override def getCounterMax = max + override def getCounterIncr = incr + override def getCounterDecr = decr + + override def setCounterValue(gate: GateICPart, i: Int) { + val oldVal = value + value = Math.min(max, Math.max(0, i)) + if (value != oldVal) + sendValueUpdate() + } + + override def setCounterMax(gate: GateICPart, i: Int) { + val oldMax = max + max = Math.min(32767, Math.max(1, i)) + if (max != oldMax) { + sendMaxUpdate() + val oldVal = value + value = Math.min(value, Math.max(0, i)) + if (value != oldVal) { + sendValueUpdate() + gate.scheduleTick(2) + } + } + } + + override def setCounterIncr(gate: GateICPart, i: Int) { + val oldIncr = incr + incr = Math.min(max, Math.max(1, i)) + if (incr != oldIncr) + sendIncrUpdate() + } + + override def setCounterDecr(gate: GateICPart, i: Int) { + val oldDecr = decr + decr = Math.min(max, Math.max(1, i)) + if (decr != oldDecr) + sendDecrUpdate() + } + + def onChange(gate: SequentialGateICPart) { + val oldInput = gate.state & 0xf + var newInput = getInput(gate, 0xa) + if (gate.shape == 1) newInput = flipMaskZ(newInput) + val high = newInput & ~oldInput + + if ((high & 2) != 0) setCounterValue(gate, value + incr) + if ((high & 8) != 0) setCounterValue(gate, value - decr) + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + gate.scheduleTick(2) + } + } + + override def cycleShape(gate: SequentialGateICPart) = { + gate.setShape(Counter.cycleShape(gate.shape)) + true + } + + def scheduledTick(gate: SequentialGateICPart) { + val oldOutput = gate.state + var newOutput = 0 + if (value == max) newOutput = 1 + else if (value == 0) newOutput = 4 + if (newOutput != oldOutput) gate.setState(gate.state & 0xf | newOutput << 4) + if (newOutput != oldOutput) gate.onOutputChange(5) + } + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + if (detailLevel > 1) { + data += "state: " + getCounterValue + if (detailLevel > 2) { + data += "max: " + getCounterMax + data += "incr: " + getCounterIncr + data += "decr: " + getCounterDecr + } + } + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} + +class RenderCounter extends ICGateRenderer[SequentialGateICPart] { + val wires = generateWireModels("COUNT", 2) + val torches = Seq( + new RedstoneTorchModel(11, 8), + new RedstoneTorchModel(8, 3), + new RedstoneTorchModel(8, 13) + ) + val pointer = new PointerModel(11, 8, 1.2d) + + torches(0).on = true + + override val coreModels = + Seq(new BaseComponentModel("COUNT")) ++ wires ++ Seq(pointer) ++ torches + + override def prepareStatic(configuration: Int): Unit = { + reflect = false + wires(0).on = false + wires(1).on = false + torches(1).on = false + torches(2).on = true + pointer.angle = 220 * MathHelper.torad + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + reflect = gate.shape == 1 + wires(0).on = (gate.state & 8) != 0 + wires(1).on = (gate.state & 2) != 0 + torches(1).on = (gate.state & 0x10) != 0 + torches(2).on = (gate.state & 0x40) != 0 + + val max = gate.getLogic[Counter].max + val value = gate.getLogic[Counter].value + pointer.angle = + (value / max.toDouble * (340 - 220) + 210) * MathHelper.torad + if (gate.shape == 1) reflect = true + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/DecRandomizer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/DecRandomizer.scala new file mode 100644 index 000000000..94f2d4b06 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/DecRandomizer.scala @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.misc + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + RedChipModel, + RedstoneTorchModel, + YellowChipModel +} + +import java.util.Random + +object DecRandomizer extends ComboICGateLogic { + val rand = new Random + + override def cycleShape(shape: Int) = shape ^ 1 + + override def outputMask(shape: Int) = if (shape == 0) 11 else 9 + override def inputMask(shape: Int) = 4 + override def feedbackMask(shape: Int) = 2 + + override def getDelay(shape: Int) = 2 + + override def calcOutput(gate: ComboICGatePart, input: Int) = { + if (input == 0) if ((gate.state >> 4) == 0) 1 else gate.state >> 4 + else Seq(1, 8, 2)(rand.nextInt((~gate.shape | 2) & 3)) + } + + override def onChange(gate: ComboICGatePart) { + super.onChange(gate) + if ((gate.state & 4) != 0) gate.scheduleTick(2) + } +} + +class RenderDecRandomizer extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("DECRAND", 6) + val chips = Seq( + new YellowChipModel(5, 13), + new YellowChipModel(11, 13), + new RedChipModel(5.5, 8) + ) + val torches = Seq( + new RedstoneTorchModel(8, 2.5), + new RedstoneTorchModel(14, 8), + new RedstoneTorchModel(2, 8), + new RedstoneTorchModel(9, 8) + ) + + override val coreModels = + Seq(new BaseComponentModel("DECRAND")) ++ wires ++ chips ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(4).on = true + wires(5).on = true + wires(0).disabled = configuration != 0 + wires(3).disabled = configuration != 0 + torches(0).on = true + torches(1).on = false + torches(2).on = false + torches(3).on = false + chips(0).on = false + chips(1).on = true + chips(2).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + val state = gate.state + wires(0).on = (state >> 4) == 2 + wires(1).on = (state >> 4) == 8 + wires(2).on = (state & 4) != 0 + wires(3).on = (state & 4) != 0 + wires(4).on = (state >> 4) == 1 || (state >> 4) == 2 + wires(5).on = (state >> 4) == 1 + wires(0).disabled = gate.shape != 0 + wires(3).disabled = gate.shape != 0 + torches(0).on = (state >> 4) == 1 + torches(1).on = (state >> 4) == 2 + torches(2).on = (state >> 4) == 8 + torches(3).on = !wires(4).on + chips(0).on = (state >> 4) == 2 + chips(1).on = (state >> 4) == 1 || (state >> 4) == 2 + chips(2).on = true + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Randomizer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Randomizer.scala new file mode 100644 index 000000000..845448d6c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Randomizer.scala @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.misc + +import mrtjp.projectred.core.TFaceOrient +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, YellowChipModel} + +import java.util.Random + +object Randomizer extends ComboICGateLogic { + val rand = new Random + + override def outputMask(shape: Int) = + ~((shape & 1) << 1 | (shape & 2) >> 1 | (shape & 4) << 1) & 0xb + override def inputMask(shape: Int) = 4 + override def feedbackMask(shape: Int) = outputMask(shape) + + override def deadSides = 3 + + override def getDelay(shape: Int) = 2 + + override def calcOutput(gate: ComboICGatePart, input: Int) = { + if (input == 0) gate.state >> 4 + else + outputMask(gate.shape) & TFaceOrient.shiftMask(rand.nextInt(8), 3) + } + + override def onChange(gate: ComboICGatePart) { + super.onChange(gate) + if ((gate.state & 4) != 0) gate.scheduleTick(2) + } +} + +class RenderRandomizer extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("RAND", 7) + val chips = Seq( + new YellowChipModel(8, 5.5), + new YellowChipModel(11.5, 11.5), + new YellowChipModel(4.5, 11.5) + ) + + override val coreModels = + Seq(new BaseComponentModel("RAND")) ++ wires ++ chips + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(4).on = false + wires(5).on = false + wires(6).on = false + wires(1).disabled = (configuration & 1) != 0 + wires(0).disabled = (configuration & 2) != 0 + wires(3).disabled = (configuration & 4) != 0 + wires(5).disabled = wires(1).disabled + wires(4).disabled = wires(0).disabled + wires(6).disabled = wires(3).disabled + chips(0).on = false + chips(1).on = false + chips(2).on = false + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(2).on = (gate.state & 4) != 0 + wires(0).on = (gate.state & 0x11) != 0 + wires(1).on = (gate.state & 0x22) != 0 + wires(3).on = (gate.state & 0x88) != 0 + wires(4).on = wires(2).on + wires(5).on = wires(2).on + wires(6).on = wires(2).on + wires(1).disabled = (gate.shape & 1) != 0 + wires(0).disabled = (gate.shape & 2) != 0 + wires(3).disabled = (gate.shape & 4) != 0 + wires(5).disabled = wires(1).disabled + wires(4).disabled = wires(0).disabled + wires(6).disabled = wires(3).disabled + chips(0).on = (gate.state & 0x10) != 0 + chips(1).on = (gate.state & 0x20) != 0 + chips(2).on = (gate.state & 0x80) != 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Synchronizer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Synchronizer.scala new file mode 100644 index 000000000..4c3b5adbf --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/misc/Synchronizer.scala @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.misc + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic, + TExtraStateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + RedChipModel, + RedstoneTorchModel +} + +class Synchronizer(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with TExtraStateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 14 + + override def onChange(gate: SequentialGateICPart) { + val oldInput = gate.state & 0xf + val newInput = getInput(gate, 14) + val high = newInput & ~oldInput + if (oldInput != newInput) { + val oldValue = state2 + + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + if ((newInput & 4) != 0) setState2(0) + else { + if ((high & 2) != 0) setState2(state2 | 1) // right + if ((high & 8) != 0) setState2(state2 | 2) // left + } + if (right && left) gate.scheduleTick(0) + + if (state2 != oldValue) sendState2Update() + } + } + + override def scheduledTick(gate: SequentialGateICPart) { + val oldValue = state2 + if (!pulsing && right && left) { + gate.setState(gate.state | 1 << 4) + gate.onOutputChange(1) + setState2(state2 | 4) // pulsing + gate.scheduleTick(2) + } else if (pulsing) { + gate.setState(gate.state & ~0x10) + gate.onOutputChange(1) + setState2(0) // off + } + if (state2 != oldValue) sendState2Update() + } + + def right = (state2 & 1) != 0 + def left = (state2 & 2) != 0 + def pulsing = (state2 & 4) != 0 + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + if (detailLevel > 1) { + data += "0: " + (if (right) "high" else "low") + data += "1: " + (if (left) "high" else "low") + } + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} + +class RenderSynchronizer extends ICGateRenderer[SequentialGateICPart] { + val wires = generateWireModels("SYNC", 6) + val torch = new RedstoneTorchModel(8, 3) + val chips = Seq(new RedChipModel(4.5, 9), new RedChipModel(11.5, 9)) + + override val coreModels = + Seq(new BaseComponentModel("SYNC")) ++ wires ++ chips ++ Seq(torch) + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = true + wires(2).on = false + wires(3).on = false + wires(4).on = false + wires(5).on = false + chips(0).on = false + chips(1).on = false + torch.on = false + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + val logic = gate.getLogic[Synchronizer] + wires(0).on = !logic.left + wires(1).on = !logic.right + wires(2).on = (gate.state & 4) != 0 + wires(3).on = logic.left && logic.right + wires(4).on = (gate.state & 8) != 0 + wires(5).on = (gate.state & 2) != 0 + chips(0).on = logic.left + chips(1).on = logic.right + torch.on = (gate.state & 0x10) != 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/AND.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/AND.scala new file mode 100644 index 000000000..8cd432712 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/AND.scala @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object AND extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = ~shape << 1 & 0xe + + override def deadSides = 3 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input == inputMask(gate.shape)) 1 else 0 +} + +class RenderAND extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("AND", 4) + val torches = Seq( + new RedstoneTorchModel(4, 8), + new RedstoneTorchModel(12, 8), + new RedstoneTorchModel(8, 8), + new RedstoneTorchModel(8, 2) + ) + + override val coreModels = + Seq(new BaseComponentModel("AND")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(3).disabled = (configuration & 1) != 0 + wires(1).disabled = (configuration & 2) != 0 + wires(2).disabled = (configuration & 4) != 0 + torches(2).on = !wires(1).on && !wires(1).disabled + torches(0).on = !wires(2).on && !wires(2).disabled + torches(1).on = !wires(3).on && !wires(3).disabled + torches(3).on = false + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x11) == 0 + wires(3).on = (gate.state & 2) != 0 + wires(1).on = (gate.state & 4) != 0 + wires(2).on = (gate.state & 8) != 0 + wires(3).disabled = (gate.shape & 1) != 0 + wires(1).disabled = (gate.shape & 2) != 0 + wires(2).disabled = (gate.shape & 4) != 0 + torches(2).on = !wires(1).on && !wires(1).disabled + torches(0).on = !wires(2).on && !wires(2).disabled + torches(1).on = !wires(3).on && !wires(3).disabled + torches(3).on = !wires(0).on + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Buffer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Buffer.scala new file mode 100644 index 000000000..80b06e8c7 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Buffer.scala @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object Buffer extends ComboICGateLogic { + override def outputMask(shape: Int) = + ~((shape & 1) << 1 | (shape & 2) << 2) & 0xb + override def inputMask(shape: Int) = 4 + override def feedbackMask(shape: Int) = outputMask(shape) + + override def deadSides = 2 + override def maxDeadSides = 2 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input != 0) 0xb else 0 +} + +class RenderBuffer extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("BUFFER", 4) + val torches = + Seq(new RedstoneTorchModel(8, 3.5), new RedstoneTorchModel(8, 9)) + + override val coreModels = + Seq(new BaseComponentModel("BUFFER")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(1).disabled = (configuration & 1) != 0 + wires(3).disabled = (configuration & 2) != 0 + torches(0).on = false + torches(1).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 4) == 0 + wires(1).on = (gate.state & 0x22) != 0 + wires(2).on = (gate.state & 0x44) != 0 + wires(3).on = (gate.state & 0x88) != 0 + wires(1).disabled = (gate.shape & 1) != 0 + wires(3).disabled = (gate.shape & 2) != 0 + torches(0).on = (gate.state & 4) != 0 + torches(1).on = (gate.state & 4) == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Multiplexer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Multiplexer.scala new file mode 100644 index 000000000..0b600f66c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/Multiplexer.scala @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object Multiplexer extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 0xe + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if ((input & 1 << 2) != 0) (input >> 3) & 1 else (input >> 1) & 1 +} + +object Pulse extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 4 + + override def calcOutput(gate: ComboICGatePart, input: Int) = 0 + + override def onChange(gate: ComboICGatePart) = { + val oldInput = gate.state & 0xf + val newInput = getInput(gate, 4) + + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + if (newInput != 0 && (gate.state & 0xf0) == 0) { + gate.setState(gate.state & 0xf | 0x10) + gate.scheduleTick(2) + gate.onOutputChange(1) + } + } + } +} + +class RenderMultiplexer extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("MULTIPLEXER", 6) + val torches = Seq( + new RedstoneTorchModel(8, 2), + new RedstoneTorchModel(9, 10.5), + new RedstoneTorchModel(4.5, 8), + new RedstoneTorchModel(11.5, 8) + ) + + override val coreModels = + Seq(new BaseComponentModel("MULTIPLEXER")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(1).on = true + wires(2).on = true + wires(3).on = false + wires(4).on = false + wires(5).on = false + torches(0).on = false + torches(1).on = true + torches(2).on = false + torches(3).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(2).on = (gate.state & 4) == 0 + wires(3).on = (gate.state & 4) != 0 + wires(4).on = (gate.state & 8) != 0 + wires(5).on = (gate.state & 2) != 0 + torches(0).on = (gate.state & 0x10) != 0 + torches(1).on = !wires(3).on + torches(2).on = (gate.state & 8) == 0 && wires(3).on + torches(3).on = (gate.state & 4) == 0 && !wires(5).on + wires(0).on = torches(2).on + wires(1).on = torches(1).on + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NAND.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NAND.scala new file mode 100644 index 000000000..5ca8d24d1 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NAND.scala @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object NAND extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = ~shape << 1 & 0xe + + override def deadSides = 3 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input == inputMask(gate.shape)) 0 else 1 +} + +class RenderNAND extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("NAND", 4) + val torches = Seq( + new RedstoneTorchModel(4, 8), + new RedstoneTorchModel(12, 8), + new RedstoneTorchModel(8, 8) + ) + + override val coreModels = + Seq(new BaseComponentModel("NAND")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(3).disabled = (configuration & 1) != 0 + wires(1).disabled = (configuration & 2) != 0 + wires(2).disabled = (configuration & 4) != 0 + torches(0).on = !wires(2).on && !wires(2).disabled + torches(1).on = !wires(3).on && !wires(3).disabled + torches(2).on = !wires(1).on && !wires(1).disabled + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x11) != 0 + wires(3).on = (gate.state & 2) != 0 + wires(1).on = (gate.state & 4) != 0 + wires(2).on = (gate.state & 8) != 0 + wires(3).disabled = (gate.shape & 1) != 0 + wires(1).disabled = (gate.shape & 2) != 0 + wires(2).disabled = (gate.shape & 4) != 0 + torches(0).on = !wires(2).on && !wires(2).disabled + torches(1).on = !wires(3).on && !wires(3).disabled + torches(2).on = !wires(1).on && !wires(1).disabled + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOR.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOR.scala new file mode 100644 index 000000000..b7ff9ee57 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOR.scala @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object NOR extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = ~shape << 1 & 0xe + override def feedbackMask(shape: Int) = 1 + + override def deadSides = 3 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input == 0) 1 else 0 +} + +class RenderNOR extends ICGateRenderer[ComboICGatePart] { + var wires = generateWireModels("NOR", 4) + var torch = new RedstoneTorchModel(8, 9) + + override val coreModels = Seq(new BaseComponentModel("NOR")) ++ wires :+ torch + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(1).disabled = (configuration & 1) != 0 + wires(2).disabled = (configuration & 2) != 0 + wires(3).disabled = (configuration & 4) != 0 + torch.on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x11) != 0 + wires(1).on = (gate.state & 2) != 0 + wires(2).on = (gate.state & 4) != 0 + wires(3).on = (gate.state & 8) != 0 + wires(1).disabled = (gate.shape & 1) != 0 + wires(2).disabled = (gate.shape & 2) != 0 + wires(3).disabled = (gate.shape & 4) != 0 + torch.on = (gate.state & 0xe) == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOT.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOT.scala new file mode 100644 index 000000000..fcdbec146 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/NOT.scala @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object NOT extends ComboICGateLogic { + override def outputMask(shape: Int) = + ~((shape & 1) << 1 | (shape & 2) >> 1 | (shape & 4) << 1) & 0xb + override def inputMask(shape: Int) = 4 + override def feedbackMask(shape: Int) = outputMask(shape) + + override def deadSides = 3 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input == 0) 0xb else 0 +} + +class RenderNOT extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("NOT", 4) + val torch = new RedstoneTorchModel(8, 8) + + override val coreModels = Seq(new BaseComponentModel("NOT")) ++ wires :+ torch + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = true + wires(2).on = false + wires(3).on = true + wires(0).disabled = (configuration & 2) != 0 + wires(1).disabled = (configuration & 1) != 0 + wires(3).disabled = (configuration & 4) != 0 + torch.on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x11) != 0 + wires(1).on = (gate.state & 0x22) != 0 + wires(2).on = (gate.state & 4) != 0 + wires(3).on = (gate.state & 0x88) != 0 + wires(0).disabled = (gate.shape & 2) != 0 + wires(1).disabled = (gate.shape & 1) != 0 + wires(3).disabled = (gate.shape & 4) != 0 + torch.on = (gate.state & 0xf0) != 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/OR.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/OR.scala new file mode 100644 index 000000000..f2c978148 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/OR.scala @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object OR extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = ~shape << 1 & 0xe + + override def deadSides = 3 + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input != 0) 1 else 0 +} + +class RenderOR extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("OR", 4) + val torches = + Seq(new RedstoneTorchModel(8, 9), new RedstoneTorchModel(8, 2.5)) + + override val coreModels = + Seq(new BaseComponentModel("OR")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(1).disabled = (configuration & 1) != 0 + wires(2).disabled = (configuration & 2) != 0 + wires(3).disabled = (configuration & 4) != 0 + torches(0).on = true + torches(1).on = false + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x10) == 0 + wires(1).on = (gate.state & 2) != 0 + wires(2).on = (gate.state & 4) != 0 + wires(3).on = (gate.state & 8) != 0 + wires(1).disabled = (gate.shape & 1) != 0 + wires(2).disabled = (gate.shape & 2) != 0 + wires(3).disabled = (gate.shape & 4) != 0 + torches(0).on = (gate.state & 0xe) == 0 + torches(1).on = !wires(0).on + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XNOR.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XNOR.scala new file mode 100644 index 000000000..4f7765d97 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XNOR.scala @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object XNOR extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 10 + + override def calcOutput(gate: ComboICGatePart, input: Int) = { + val side1 = (input & 1 << 1) != 0 + val side2 = (input & 1 << 3) != 0 + if (side1 == side2) 1 else 0 + } +} + +class RenderXNOR extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("XNOR", 5) + val torches = Seq( + new RedstoneTorchModel(8, 2), + new RedstoneTorchModel(4.5, 8), + new RedstoneTorchModel(11.5, 8), + new RedstoneTorchModel(8, 12) + ) + + override val coreModels = + Seq(new BaseComponentModel("XNOR")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(3).on = false + wires(2).on = false + wires(1).on = false + torches(0).on = true + torches(1).on = false + torches(2).on = false + torches(3).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 2) != 0 && (gate.state & 8) == 0 + wires(1).on = (gate.state & 8) != 0 && (gate.state & 2) == 0 + wires(2).on = (gate.state & 8) != 0 + wires(3).on = (gate.state & 2) != 0 + wires(4).on = !wires(3).on && !wires(2).on + torches(0).on = (gate.state & 0x11) != 0 + torches(1).on = !wires(4).on && (gate.state & 8) == 0 + torches(2).on = !wires(4).on && (gate.state & 2) == 0 + torches(3).on = (gate.state & 2) == 0 && (gate.state & 8) == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XOR.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XOR.scala new file mode 100644 index 000000000..8962df195 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/primitives/XOR.scala @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.primitives + +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} + +object XOR extends ComboICGateLogic { + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 10 + + override def calcOutput(gate: ComboICGatePart, input: Int) = { + val side1 = (input & 1 << 1) != 0 + val side2 = (input & 1 << 3) != 0 + if (side1 != side2) 1 else 0 + } +} + +class RenderXOR extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("XOR", 4) + val torches = Seq( + new RedstoneTorchModel(4.5, 8), + new RedstoneTorchModel(11.5, 8), + new RedstoneTorchModel(8, 12) + ) + + override val coreModels = + Seq(new BaseComponentModel("XOR")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(3).on = false + wires(2).on = false + wires(1).on = true + torches(0).on = false + torches(1).on = false + torches(2).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x11) != 0 + wires(3).on = (gate.state & 2) != 0 + wires(2).on = (gate.state & 8) != 0 + wires(1).on = !wires(3).on && !wires(2).on + torches(0).on = !wires(2).on && !wires(1).on + torches(1).on = !wires(3).on && !wires(1).on + torches(2).on = wires(1).on + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Pulse.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Pulse.scala new file mode 100644 index 000000000..509beee6a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Pulse.scala @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.timing + +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +class RenderPulse extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("PULSE", 3) + val torches = Seq( + new RedstoneTorchModel(4, 9.5), + new RedstoneTorchModel(11, 9.5), + new RedstoneTorchModel(8, 3.5) + ) + + override val coreModels = + Seq(new BaseComponentModel("PULSE")) ++ wires ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + wires(2).on = false + torches(0).on = true + torches(1).on = false + torches(2).on = false + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 4) == 0 + wires(1).on = (gate.state & 4) != 0 + wires(2).on = (gate.state & 0x14) == 4 + torches(0).on = wires(0).on + torches(1).on = wires(1).on + torches(2).on = (gate.state & 0x10) != 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Repeater.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Repeater.scala new file mode 100644 index 000000000..b9ce81d83 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Repeater.scala @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.timing + +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ComboICGateLogic, + ComboICGatePart, + ICGateRenderer +} +import mrtjp.projectred.fabrication.{BaseComponentModel, RedstoneTorchModel} + +object Repeater extends ComboICGateLogic { + val delays = Array(2, 4, 6, 8, 16, 32, 64, 128, 256) + + override def outputMask(shape: Int) = 1 + override def inputMask(shape: Int) = 4 + + override def getDelay(shape: Int) = delays(shape) + + override def cycleShape(shape: Int) = (shape + 1) % delays.length + + override def calcOutput(gate: ComboICGatePart, input: Int) = + if (input == 0) 0 else 1 + + override def onChange(gate: ComboICGatePart) { + if (gate.schedTime < 0) super.onChange(gate) + } + + override def activate(gate: ComboICGatePart) { + gate.configure() + } + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: ComboICGatePart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + if (detailLevel > 1) data += "delay: " + delays(gate.shape) + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} + +class RenderRepeater extends ICGateRenderer[ComboICGatePart] { + val wires = generateWireModels("REPEATER", 2) + val endTorch = new RedstoneTorchModel(8, 2) + val varTorches = Seq( + new RedstoneTorchModel(12.5, 12), + new RedstoneTorchModel(12.5, 11), + new RedstoneTorchModel(12.5, 10), + new RedstoneTorchModel(12.5, 9), + new RedstoneTorchModel(12.5, 8), + new RedstoneTorchModel(12.5, 7), + new RedstoneTorchModel(12.5, 6), + new RedstoneTorchModel(12.5, 5), + new RedstoneTorchModel(12.5, 4) + ) + + var shape = 0 + + override val coreModels = + Seq(new BaseComponentModel("REPEATER")) ++ wires :+ endTorch + + override def switchModels = Seq(varTorches(shape)) + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = true + wires(1).on = false + endTorch.on = false + shape = configuration + varTorches(configuration).on = true + } + + override def prepareDynamic(gate: ComboICGatePart, frame: Float) { + wires(0).on = (gate.state & 0x10) == 0 + wires(1).on = (gate.state & 4) != 0 + endTorch.on = (gate.state & 0x10) != 0 + shape = gate.shape % 8 + varTorches(shape).on = (gate.state & 4) == 0 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Sequencer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Sequencer.scala new file mode 100644 index 000000000..e09027384 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Sequencer.scala @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.timing + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.math.MathHelper +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.core.Configurator +import mrtjp.projectred.core.TFaceOrient.flipMaskZ +import mrtjp.projectred.fabrication.circuitparts.{ + GateICPart, + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + PointerModel, + RedstoneTorchModel +} +import net.minecraft.nbt.NBTTagCompound + +object Sequencer { + def cycleShape(shape: Int): Int = { + shape ^ 1 + } +} + +class Sequencer(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with ITimerGuiLogic { + var pointer_max = 40 + var saveTime = -1L + + override def outputMask(shape: Int) = 0xf + + override def onChange(gate: SequentialGateICPart) {} + override def scheduledTick(gate: SequentialGateICPart) {} + + override def getTimerMax = pointer_max + override def setTimerMax(gate: GateICPart, time: Int) { + var t = time + val minTime = math.max(4, Configurator.minTimerTicks) + if (t < minTime) t = minTime + if (t != pointer_max) { + pointer_max = t + sendPointerMaxUpdate() + } + } + + override def save(tag: NBTTagCompound) { + tag.setInteger("pmax", pointer_max) + tag.setLong("tsave", getWorldTime) + } + override def load(tag: NBTTagCompound) { + pointer_max = tag.getInteger("pmax") + saveTime = tag.getLong("tsave") + } + + override def writeDesc(packet: MCDataOutput) { packet.writeInt(pointer_max) } + override def readDesc(packet: MCDataInput) { pointer_max = packet.readInt() } + + override def read(packet: MCDataInput, key: Int) = key match { + case 12 => pointer_max = packet.readInt() + case _ => + } + + def sendPointerMaxUpdate() { gate.writeStreamOf(12).writeInt(pointer_max) } + + def getWorldTime = + if (gate.world.network != null) gate.world.network.getWorld.getWorldTime + else saveTime + + override def onTick(gate: SequentialGateICPart) { + if (!gate.world.network.isRemote) { + val oldOut = gate.state >> 4 + var out = 1 << getWorldTime % (pointer_max * 4) / pointer_max + if (gate.shape == 1) out = flipMaskZ(out) + if (oldOut != out) { + gate.setState(out << 4) + gate.onOutputChange(0xf) + } + } + } + + override def cycleShape(gate: SequentialGateICPart) = { + gate.setShape(Sequencer.cycleShape(gate.shape)) + true + } + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + if (detailLevel > 1) + data += "interval: " + "%.2f".format(getTimerMax * 0.05) + "s" + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} + +class RenderSequencer extends ICGateRenderer[SequentialGateICPart] { + val torches = Seq( + new RedstoneTorchModel(8, 8), + new RedstoneTorchModel(8, 3), + new RedstoneTorchModel(13, 8), + new RedstoneTorchModel(8, 13), + new RedstoneTorchModel(3, 8) + ) + val pointer = new PointerModel(8, 8) + + torches(0).on = true + + override val coreModels = + Seq(new BaseComponentModel("SEQUENCER"), pointer) ++ torches + + override def prepareStatic(configuration: Int): Unit = { + torches(1).on = true + torches(2).on = false + torches(3).on = false + torches(4).on = false + + pointer.angle = 0 + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + torches(1).on = (gate.state & 0x10) != 0 + torches(2).on = (gate.state & 0x20) != 0 + torches(3).on = (gate.state & 0x40) != 0 + torches(4).on = (gate.state & 0x80) != 0 + + val max = gate.getLogic[Sequencer].pointer_max * 4 + pointer.angle = (gate + .getLogic[Sequencer] + .getWorldTime % max + frame) / max * 2 * MathHelper.pi + if (gate.shape == 1) pointer.angle *= -1 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/StateCell.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/StateCell.scala new file mode 100644 index 000000000..d23d60fb3 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/StateCell.scala @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.timing + +import codechicken.lib.math.MathHelper +import mrtjp.projectred.core.TFaceOrient.flipMaskZ +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic, + TExtraStateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + PointerModel, + RedChipModel, + RedstoneTorchModel +} + +object StateCell { + def cycleShape(shape: Int): Int = { + (shape + 1) % 2 + } +} + +class StateCell(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with TTimerGateLogic + with TExtraStateLogic { + override def outputMask(shape: Int) = { + var output = 9 + if (shape == 1) output = flipMaskZ(output) + output + } + + override def inputMask(shape: Int) = { + var input = 6 + if (shape == 1) input = flipMaskZ(input) + input + } + + override def cycleShape(gate: SequentialGateICPart) = { + gate.setShape(StateCell.cycleShape(gate.shape)) + true + } + + override def onChange(gate: SequentialGateICPart) { + val oldInput = gate.state & 0xf + var newInput = getInput(gate, 0xe) + if (oldInput != newInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + + if (gate.shape == 1) newInput = flipMaskZ(newInput) + if ((newInput & 4) != 0 && state2 == 0) { + setState2(1) + sendState2Update() + gate.scheduleTick(0) + } + + if (state2 != 0) + if ((newInput & 6) != 0) resetPointer() + else startPointer() + } + } + + override def pointerTick() { + resetPointer() + if (!gate.world.network.isRemote) { + setState2(0) + sendState2Update() + gate.setState(0x10 | gate.state & 0xf) + gate.onOutputChange(outputMask(gate.shape)) + gate.scheduleTick(2) + } + } + + override def scheduledTick(gate: SequentialGateICPart) { + var output = 0 + if (state2 != 0) output = 8 + if (gate.shape == 1) output = flipMaskZ(output) + + gate.setState(output << 4 | gate.state & 0xf) + gate.onOutputChange(outputMask(gate.shape)) + } +} + +class RenderStateCell extends ICGateRenderer[SequentialGateICPart] { + val wires = generateWireModels("STATECELL", 5) + val torches = + Seq(new RedstoneTorchModel(10, 3.5), new RedstoneTorchModel(13, 8)) + val chip = new RedChipModel(6.5, 10) + val pointer = new PointerModel(13, 8) + + override val coreModels = Seq( + new BaseComponentModel("STATECELL") + ) ++ wires ++ Seq(chip, pointer) ++ torches + + override def prepareStatic(configuration: Int): Unit = { + reflect = false + wires(0).on = false + wires(1).on = false + wires(2).on = false + wires(3).on = false + wires(4).on = false + torches(0).on = false + torches(1).on = true + chip.on = false + pointer.angle = -MathHelper.pi / 2 + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + reflect = gate.shape == 1 + val logic = gate.getLogic[StateCell] + var state = gate.state + if (reflect) state = flipMaskZ(state >> 4) << 4 | flipMaskZ(state) + + wires(0).on = (state & 0x10) != 0 + wires(1).on = (state & 4) != 0 + wires(2).on = logic.state2 == 0 || (state & 4) != 0 + wires(3).on = (state & 0x88) != 0 + wires(4).on = (state & 2) != 0 + torches(0).on = (state & 0x10) != 0 + torches(1).on = logic.pointer_start >= 0 + chip.on = logic.state2 != 0 + + reflect = gate.shape == 1 + pointer.angle = + gate.getLogic[StateCell].interpPointer(frame) - MathHelper.pi / 2 + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Timer.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Timer.scala new file mode 100644 index 000000000..804ddaf66 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/timing/Timer.scala @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.timing + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.math.MathHelper +import codechicken.multipart.handler.MultipartSaveLoad +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.core.Configurator +import mrtjp.projectred.fabrication.ICComponentStore.generateWireModels +import mrtjp.projectred.fabrication.circuitparts.{ + GateICPart, + ICGateRenderer, + SequentialGateICPart, + SequentialICGateLogic +} +import mrtjp.projectred.fabrication.{ + BaseComponentModel, + PointerModel, + RedstoneTorchModel +} +import net.minecraft.nbt.NBTTagCompound + +trait ITimerGuiLogic { + def getTimerMax: Int + def setTimerMax(gate: GateICPart, t: Int) +} + +class Timer(gate: SequentialGateICPart) + extends SequentialICGateLogic(gate) + with TTimerGateLogic { + override def outputMask(shape: Int) = 0xb + override def inputMask(shape: Int) = 0xe + + override def setup(gate: SequentialGateICPart) { startPointer() } + + override def scheduledTick(gate: SequentialGateICPart) { + gate.setState(gate.state & 0xf) + gate.onOutputChange(0xb) + onChange(gate) + } + + override def onChange(gate: SequentialGateICPart) { + val oldInput = gate.state & 0xf + val newInput = getInput(gate, 0xe) + + if (newInput != oldInput) { + gate.setState(gate.state & 0xf0 | newInput) + gate.onInputChange() + } + + if (gate.schedTime < 0) + if (newInput > 0) resetPointer() else startPointer() + } + + override def pointerTick() { + resetPointer() + if (!gate.world.network.isRemote) { + gate.scheduleTick(2) + gate.setState(0xb0 | gate.state & 0xf) + gate.onOutputChange(0xb) + } + } +} + +trait TTimerGateLogic extends SequentialICGateLogic with ITimerGuiLogic { + var pointer_max = 38 + var pointer_start = -1L + var saveTime = -1L // used for blueprint in-hand rendering + + abstract override def save(tag: NBTTagCompound) { + super.save(tag) + tag.setInteger("pmax", pointer_max) + tag.setLong( + "pelapsed", + if (pointer_start < 0) pointer_start else getTotalTime - pointer_start + ) + tag.setLong("tsave", getTotalTime) + } + + abstract override def load(tag: NBTTagCompound) { + super.load(tag) + pointer_max = tag.getInteger("pmax") + pointer_start = tag.getLong("pelapsed") + saveTime = tag.getLong("tsave") + if (pointer_start >= 0) pointer_start = getTotalTime - pointer_start + } + + abstract override def writeDesc(packet: MCDataOutput) { + super.writeDesc(packet) + packet.writeInt(pointer_max) + packet.writeLong(pointer_start) + } + + abstract override def readDesc(packet: MCDataInput) { + super.readDesc(packet) + pointer_max = packet.readInt() + pointer_start = packet.readLong() + } + + abstract override def read(packet: MCDataInput, key: Int) = key match { + case 12 => pointer_max = packet.readInt() + case 13 => + pointer_start = packet.readInt() + if (pointer_start >= 0) pointer_start = getTotalTime - pointer_start + case _ => super.read(packet, key) + } + + def getTotalTime = // client-side safe version of getTotalWorldTime (workaround for no client world) + { + if (gate.world.network == null) + saveTime // ic was loaded directly from stack, possibly for in-hand render + else if (gate.world.network.getWorld == null) + MultipartSaveLoad.loadingWorld.getTotalWorldTime // ic is being loaded with a workbench tile or gate + else + gate.world.network.getWorld.getTotalWorldTime // normal access during operation + } + + def pointerValue = + if (pointer_start < 0) 0 else (getTotalTime - pointer_start).toInt + + def sendPointerMaxUpdate() { gate.writeStreamOf(12).writeInt(pointer_max) } + def sendPointerUpdate() { + gate.writeStreamOf(13).writeInt(if (pointer_start < 0) -1 else pointerValue) + } + + override def getTimerMax = pointer_max + 2 + override def setTimerMax(gate: GateICPart, time: Int) { + var t = time + val minTime = math.max(4, Configurator.minTimerTicks) + if (t < minTime) t = minTime + if (t != pointer_max) { + pointer_max = t - 2 + sendPointerMaxUpdate() + } + } + + override def onTick(gate: SequentialGateICPart) { + if (pointer_start >= 0) + if (getTotalTime >= pointer_start + pointer_max) pointerTick() + else if (pointer_start > getTotalTime) + pointer_start = getTotalTime + } + + def pointerTick() + + def resetPointer() { + if (pointer_start >= 0) { + pointer_start = -1 + gate.world.network.markSave() + if (!gate.world.network.isRemote) sendPointerUpdate() + } + } + + def startPointer() { + if (pointer_start < 0) { + pointer_start = getTotalTime + gate.world.network.markSave() + if (!gate.world.network.isRemote) sendPointerUpdate() + } + } + + def interpPointer(f: Float) = + if (pointer_start < 0) 0f else (pointerValue + f) / pointer_max + + @SideOnly(Side.CLIENT) + override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { + val data = Seq.newBuilder[String] + if (detailLevel > 1) + data += "interval: " + "%.2f".format(getTimerMax * 0.05) + "s" + super.getRolloverData(gate, detailLevel) ++ data.result() + } +} + +class RenderTimer extends ICGateRenderer[SequentialGateICPart] { + val wires = generateWireModels("TIME", 3) + val torches = Seq(new RedstoneTorchModel(8, 3), new RedstoneTorchModel(8, 8)) + val pointer = new PointerModel(8, 8) + + override val coreModels = + Seq(new BaseComponentModel("TIME")) ++ wires ++ Seq(pointer) ++ torches + + override def prepareStatic(configuration: Int): Unit = { + wires(0).on = false + wires(1).on = false + wires(2).on = false + torches(0).on = false + pointer.angle = 0 + } + + override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { + torches(0).on = (gate.state & 0x10) != 0 + wires(0).on = (gate.state & 0x88) != 0 + wires(1).on = (gate.state & 0x22) != 0 + wires(2).on = (gate.state & 4) != 0 + val ang = + gate.getLogic[TTimerGateLogic].interpPointer(frame) * MathHelper.pi * 2 + pointer.angle = ang + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/AlloyWire.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/AlloyWire.scala new file mode 100644 index 000000000..9b45e886a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/AlloyWire.scala @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.wire + +import codechicken.lib.render.ColourMultiplier +import codechicken.lib.render.uv.IconTransformation +import codechicken.lib.vec.Transformation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication.circuitparts.CircuitPartDefs +import mrtjp.projectred.fabrication.operations.CircuitOpDefs + +class AlloyWireICPart extends RedwireICPart { + override def getPartType = CircuitPartDefs.AlloyWire + + @SideOnly(Side.CLIENT) + override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { + RenderICAlloyWire.prepairDynamic(this) + RenderICAlloyWire.render(t, ortho) + } + + @SideOnly(Side.CLIENT) + override def getPartName = "item.projectred.transmission.wire|0.name" + + @SideOnly(Side.CLIENT) + override def getCircuitOperation = CircuitOpDefs.AlloyWire.getOp +} + +object RenderICAlloyWire { + var connMap: Byte = 0 + var signal: Byte = 0 + + def prepairInv() { + connMap = 0xf + signal = 0xff.toByte + } + + def prepairDynamic(part: AlloyWireICPart) { + connMap = part.connMap + signal = part.signal + } + + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)).render( + t, + new IconTransformation(redwireIcons(connMap & 0xff)), + ColourMultiplier.instance((signal & 0xff) / 2 + 60 << 24 | 0xff) + ) + finishRender() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/wirepartbundled.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/BundledCable.scala similarity index 80% rename from src/main/scala/mrtjp/projectred/fabrication/wirepartbundled.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/BundledCable.scala index ed25f73c8..44ed5be52 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/wirepartbundled.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/BundledCable.scala @@ -3,14 +3,29 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.ColourMultiplier +import codechicken.lib.render.uv.IconTransformation import codechicken.lib.vec.Transformation import cpw.mods.fml.relauncher.{Side, SideOnly} import mrtjp.core.color.Colors -import mrtjp.projectred.fabrication.IWireICPart._ -import mrtjp.projectred.transmission.BundledCommons._ +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication.circuitparts.IWireICPart._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + CircuitPartDefs, + IWireICPart, + TICBundledAcquisitions +} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs +import mrtjp.projectred.transmission.BundledCommons.{ + packDigital, + raiseSignal, + unpackDigital +} import net.minecraft.nbt.NBTTagCompound trait IBundledCableICPart extends IWireICPart with IICBundledEmitter { @@ -77,6 +92,7 @@ class BundledCableICPart } protected var propagatingMask = 0xffff + override def updateAndPropagate(prev: CircuitPart, mode: Int) { import mrtjp.projectred.transmission.BundledCommons._ val mask = getUpdateMask(prev, mode) @@ -133,6 +149,7 @@ class BundledCableICPart } private val tmpSignal = new Array[Byte](16) + private def tmpSignalClear() { for (i <- 0 until 16) tmpSignal(i) = 0.toByte } @@ -173,11 +190,11 @@ class BundledCableICPart } @SideOnly(Side.CLIENT) - override def getPartName = (if (colour != -1) Colors(colour & 0xff).name + " " - else "") + "Bundled cable" + override def getPartName = + "item.projectred.transmission.wire|" + colour + ".name" @SideOnly(Side.CLIENT) - override def getPickOp = CircuitOpDefs + override def getCircuitOperation = CircuitOpDefs .values(CircuitOpDefs.NeutralBundledCable.ordinal + colour + 1) .getOp @@ -194,3 +211,31 @@ class BundledCableICPart super.getRolloverData(detailLevel) ++ data.result() } } + +object RenderICBundledCable { + var connMap: Byte = 0 + var colour: Byte = 0 + + def prepairInv(c: Int) { + connMap = 0xf + colour = c.toByte + } + + def prepairDynamic(part: BundledCableICPart) { + connMap = part.connMap + colour = part.colour + } + + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)) + .render(t, new IconTransformation(bundledwireIcons(connMap & 0xff))) + if (colour != -1) + faceModels(dynamicIdx(0, ortho)).render( + t, + new IconTransformation(bundledColourIcon), + ColourMultiplier.instance(Colors(colour & 0xff).rgba) + ) + finishRender() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/buttonpart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Button.scala similarity index 75% rename from src/main/scala/mrtjp/projectred/fabrication/buttonpart.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Button.scala index f15d0c3c5..13f8f902b 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/buttonpart.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Button.scala @@ -3,18 +3,29 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.uv.IconTransformation import codechicken.lib.vec.Transformation import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + CircuitPartDefs, + TPoweredCircuitPart, + TClientNetCircuitPart, + TICAcquisitions +} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumChatFormatting class ButtonICPart extends CircuitPart with TICAcquisitions - with IPoweredCircuitPart + with TPoweredCircuitPart with TClientNetCircuitPart { var on = false var sched = -1L @@ -101,7 +112,7 @@ class ButtonICPart override def getPartName = "Button" @SideOnly(Side.CLIENT) - override def getPickOp = CircuitOpDefs.Button.getOp + override def getCircuitOperation = CircuitOpDefs.Button.getOp @SideOnly(Side.CLIENT) override def getRolloverData(detailLevel: Int) = { @@ -122,14 +133,23 @@ class ButtonICPart } } -class CircuitOpButton extends SimplePlacementOp { - override def doPartRender(t: Transformation) { - RenderICButton.prepairInv() - RenderICButton.render(t, true) +object RenderICButton { + var on = false + + def prepairInv() { + on = false } - override def createPart = CircuitPartDefs.Button.createPart + def prepairDynamic(part: ButtonICPart) { + on = part.on + } - @SideOnly(Side.CLIENT) - override def getOpName = "Button" + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)).render( + t, + new IconTransformation(if (on) buttonOnIcon else buttonOffIcon) + ) + finishRender() + } } diff --git a/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/InsulatedWire.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/InsulatedWire.scala new file mode 100644 index 000000000..130dd70c4 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/InsulatedWire.scala @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.circuitparts.wire + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.ColourMultiplier +import codechicken.lib.render.uv.IconTransformation +import codechicken.lib.vec.Transformation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.color.Colors +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication.circuitparts.{CircuitPart, CircuitPartDefs} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs +import net.minecraft.nbt.NBTTagCompound + +trait IInsulatedRedwireICPart extends IRedwireICPart { + def getInsulatedColour: Int +} + +class InsulatedWireICPart extends RedwireICPart with IInsulatedRedwireICPart { + var colour: Byte = 0 + + override def save(tag: NBTTagCompound) { + super.save(tag) + tag.setByte("colour", colour) + } + + override def load(tag: NBTTagCompound) { + super.load(tag) + colour = tag.getByte("colour") + } + + override def writeDesc(out: MCDataOutput) { + super.writeDesc(out) + out.writeByte(colour) + } + + override def readDesc(in: MCDataInput) { + super.readDesc(in) + colour = in.readByte() + } + + override def getPartType = CircuitPartDefs.InsulatedWire + + override def resolveSignal(part: Any, r: Int) = part match { + case b: IBundledCableICPart => (b.getBundledSignal.apply(colour) & 0xff) - 1 + case _ => super.resolveSignal(part, r) + } + + override def canConnectPart(part: CircuitPart, r: Int) = part match { + case b: IBundledCableICPart => true + case iw: InsulatedWireICPart => iw.colour == colour + case _ => super.canConnectPart(part, r) + } + + override def getInsulatedColour = colour + + @SideOnly(Side.CLIENT) + override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { + RenderICInsulatedWire.prepairDynamic(this) + RenderICInsulatedWire.render(t, ortho) + } + + @SideOnly(Side.CLIENT) + override def getPartName = Colors(colour & 0xff).name + " Insulated wire" + + @SideOnly(Side.CLIENT) + override def getCircuitOperation = + CircuitOpDefs + .values(CircuitOpDefs.WhiteInsulatedWire.ordinal + colour) + .getOp +} + +object RenderICInsulatedWire { + var connMap: Byte = 0 + var signal: Byte = 0 + var colour: Byte = 0 + + def prepairInv(c: Int) { + connMap = 0xf + signal = 255.toByte + colour = c.toByte + } + + def prepairDynamic(part: InsulatedWireICPart) { + connMap = part.connMap + signal = part.signal + colour = part.colour + } + + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)).render( + t, + new IconTransformation(redwireIcons(connMap & 0xff)), + ColourMultiplier.instance((signal & 0xff) / 2 + 60 << 24 | 0xff) + ) + faceModels(dynamicIdx(0, ortho)).render( + t, + new IconTransformation(insulatedwireIcons(connMap & 0xff)), + ColourMultiplier.instance(Colors(colour & 0xff).rgba) + ) + finishRender() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/leverpart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Lever.scala similarity index 69% rename from src/main/scala/mrtjp/projectred/fabrication/leverpart.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Lever.scala index 084f1e6ca..e755e06cc 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/leverpart.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Lever.scala @@ -3,18 +3,29 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire -import codechicken.lib.data.{MCDataOutput, MCDataInput} +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.uv.IconTransformation import codechicken.lib.vec.Transformation import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + CircuitPartDefs, + TPoweredCircuitPart, + TClientNetCircuitPart, + TICAcquisitions +} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.EnumChatFormatting class LeverICPart extends CircuitPart with TICAcquisitions - with IPoweredCircuitPart + with TPoweredCircuitPart with TClientNetCircuitPart { var on = false @@ -75,7 +86,7 @@ class LeverICPart override def getPartName = "Lever" @SideOnly(Side.CLIENT) - override def getPickOp = CircuitOpDefs.Lever.getOp + override def getCircuitOperation = CircuitOpDefs.Lever.getOp @SideOnly(Side.CLIENT) override def getRolloverData(detailLevel: Int) = { @@ -96,14 +107,21 @@ class LeverICPart } } -class CircuitOpLever extends SimplePlacementOp { - override def doPartRender(t: Transformation) { - RenderICLever.prepairInv() - RenderICLever.render(t, true) +object RenderICLever { + var on = false + + def prepairInv() { + on = false } - override def createPart = CircuitPartDefs.Lever.createPart + def prepairDynamic(part: LeverICPart) { + on = part.on + } - @SideOnly(Side.CLIENT) - override def getOpName = "Lever" + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)) + .render(t, new IconTransformation(if (on) leverOnIcon else leverOffIcon)) + finishRender() + } } diff --git a/src/main/scala/mrtjp/projectred/fabrication/torchpart.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/RedstoneTorch.scala similarity index 53% rename from src/main/scala/mrtjp/projectred/fabrication/torchpart.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/RedstoneTorch.scala index 7dd1a1a0b..796650bc7 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/torchpart.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/RedstoneTorch.scala @@ -3,15 +3,25 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire +import codechicken.lib.render.uv.IconTransformation import codechicken.lib.vec.Transformation import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + CircuitPartDefs, + TPoweredCircuitPart, + TICAcquisitions +} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs class TorchICPart extends CircuitPart with TICAcquisitions - with IPoweredCircuitPart { + with TPoweredCircuitPart { override def getPartType = CircuitPartDefs.Torch override def onAdded() { @@ -29,7 +39,7 @@ class TorchICPart override def getPartName = "Torch" @SideOnly(Side.CLIENT) - override def getPickOp = CircuitOpDefs.Torch.getOp + override def getCircuitOperation = CircuitOpDefs.Torch.getOp @SideOnly(Side.CLIENT) override def renderDynamic( @@ -41,11 +51,11 @@ class TorchICPart } } -class CircuitOpTorch extends SimplePlacementOp { - override def doPartRender(t: Transformation) = RenderICTorch.render(t, true) - - override def createPart = CircuitPartDefs.Torch.createPart - - @SideOnly(Side.CLIENT) - override def getOpName = "Torch" +object RenderICTorch { + def render(t: Transformation, ortho: Boolean) { + prepairRender() + faceModels(dynamicIdx(0, ortho)) + .render(t, new IconTransformation(torchOnIcon)) + finishRender() + } } diff --git a/src/main/scala/mrtjp/projectred/fabrication/wirepartrs.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Redwire.scala similarity index 50% rename from src/main/scala/mrtjp/projectred/fabrication/wirepartrs.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Redwire.scala index d2bb7dbbf..99da04134 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/wirepartrs.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Redwire.scala @@ -3,23 +3,18 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.vec.Transformation import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.color.Colors -import net.minecraft.nbt.NBTTagCompound - -trait IRedwireICPart extends IWireICPart with IICRedwireEmitter - -trait IICRedwireEmitter { - def getRedwireSignal(r: Int): Int -} - -trait IInsulatedRedwireICPart extends IRedwireICPart { - def getInsulatedColour: Int +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + TPoweredCircuitPart, + TICRSAcquisitions, + TRSPropagatingICPart } +import net.minecraft.nbt.NBTTagCompound abstract class RedwireICPart extends WireICPart @@ -59,7 +54,7 @@ abstract class RedwireICPart } override def discoverOverride(r: Int, part: CircuitPart) = part match { - case pow: IPoweredCircuitPart => pow.canConnectRS(rotFromStraight(r)) + case pow: TPoweredCircuitPart => pow.canConnectRS(rotFromStraight(r)) case _ => super.discoverOverride(r, part) } @@ -68,7 +63,10 @@ abstract class RedwireICPart override def getRedwireSignal(r: Int) = getSignal override def getSignal = signal & 0xff - override def setSignal(sig: Int) { signal = sig.toByte } + + override def setSignal(sig: Int) { + signal = sig.toByte + } override def rsOutputLevel(r: Int) = if (ICPropagator.redwiresProvidePower && maskConnects(r)) @@ -77,21 +75,25 @@ abstract class RedwireICPart override def canConnectPart(part: CircuitPart, r: Int) = part match { case re: IICRedwireEmitter => true - case pc: IPoweredCircuitPart => true + case pc: TPoweredCircuitPart => true case _ => false } override def resolveSignal(part: Any, r: Int) = part match { case t: IRedwireICPart if t.diminishOnSide(r) => t.getRedwireSignal(r) - 1 case t: IICRedwireEmitter => t.getRedwireSignal(r) - case t: IPoweredCircuitPart => t.rsOutputLevel(r) + case t: TPoweredCircuitPart => t.rsOutputLevel(r) case _ => 0 } override def calculateSignal = { var s = 0 ICPropagator.redwiresProvidePower = false - def raise(sig: Int) { if (sig > s) s = sig } + + def raise(sig: Int) { + if (sig > s) s = sig + } + for (r <- 0 until 4) if (maskConnects(r)) raise(calcSignal(r)) ICPropagator.redwiresProvidePower = true s @@ -110,73 +112,3 @@ abstract class RedwireICPart super.getRolloverData(detailLevel) ++ data.result() } } - -class AlloyWireICPart extends RedwireICPart { - override def getPartType = CircuitPartDefs.AlloyWire - - @SideOnly(Side.CLIENT) - override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { - RenderICAlloyWire.prepairDynamic(this) - RenderICAlloyWire.render(t, ortho) - } - - @SideOnly(Side.CLIENT) - override def getPartName = "Alloy wire" - - @SideOnly(Side.CLIENT) - override def getPickOp = CircuitOpDefs.AlloyWire.getOp -} - -class InsulatedWireICPart extends RedwireICPart with IInsulatedRedwireICPart { - var colour: Byte = 0 - - override def save(tag: NBTTagCompound) { - super.save(tag) - tag.setByte("colour", colour) - } - - override def load(tag: NBTTagCompound) { - super.load(tag) - colour = tag.getByte("colour") - } - - override def writeDesc(out: MCDataOutput) { - super.writeDesc(out) - out.writeByte(colour) - } - - override def readDesc(in: MCDataInput) { - super.readDesc(in) - colour = in.readByte() - } - - override def getPartType = CircuitPartDefs.InsulatedWire - - override def resolveSignal(part: Any, r: Int) = part match { - case b: IBundledCableICPart => (b.getBundledSignal.apply(colour) & 0xff) - 1 - case _ => super.resolveSignal(part, r) - } - - override def canConnectPart(part: CircuitPart, r: Int) = part match { - case b: IBundledCableICPart => true - case iw: InsulatedWireICPart => iw.colour == colour - case _ => super.canConnectPart(part, r) - } - - override def getInsulatedColour = colour - - @SideOnly(Side.CLIENT) - override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { - RenderICInsulatedWire.prepairDynamic(this) - RenderICInsulatedWire.render(t, ortho) - } - - @SideOnly(Side.CLIENT) - override def getPartName = Colors(colour & 0xff).name + " Insulated wire" - - @SideOnly(Side.CLIENT) - override def getPickOp = - CircuitOpDefs - .values(CircuitOpDefs.WhiteInsulatedWire.ordinal + colour) - .getOp -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/wirepartabstracts.scala b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Wire.scala similarity index 79% rename from src/main/scala/mrtjp/projectred/fabrication/wirepartabstracts.scala rename to src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Wire.scala index 1c7e3525f..3d7d53146 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/wirepartabstracts.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/circuitparts/wire/Wire.scala @@ -3,18 +3,32 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.circuitparts.wire import codechicken.lib.data.{MCDataInput, MCDataOutput} import mrtjp.core.color.Colors -import mrtjp.projectred.fabrication.IWireICPart._ +import mrtjp.projectred.fabrication.circuitparts.IWireICPart._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + TErrorCircuitPart, + IWireICPart, + TConnectableICPart, + TPropagatingICPart +} import net.minecraft.nbt.NBTTagCompound +trait IRedwireICPart extends IWireICPart with IICRedwireEmitter + +trait IICRedwireEmitter { + def getRedwireSignal(r: Int): Int +} + abstract class WireICPart extends CircuitPart with TConnectableICPart with TPropagatingICPart - with IErrorCircuitPart { + with TErrorCircuitPart { override def save(tag: NBTTagCompound) { tag.setByte("connMap", connMap) } diff --git a/src/main/scala/mrtjp/projectred/fabrication/components.scala b/src/main/scala/mrtjp/projectred/fabrication/components.scala index 9c919bc67..81c5ab0bc 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/components.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/components.scala @@ -16,7 +16,8 @@ import codechicken.lib.render.{ } import codechicken.lib.vec._ import mrtjp.core.color.Colors -import mrtjp.core.vec.Size +import mrtjp.core.vec.{Size, Vec2} +import mrtjp.projectred.fabrication.circuitparts.ICGateRenderer import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.util.IIcon @@ -45,6 +46,10 @@ object ICComponentStore { val bundledwireIcons = new Array[IIcon](16) var bundledColourIcon: IIcon = null + var arrowIn: IIcon = null + var arrowOut: IIcon = null + var arrowInOut: IIcon = null + var ioBorder: IIcon = null var ioSig: IIcon = null var tLeverOnIcon: IIcon = null @@ -82,12 +87,16 @@ object ICComponentStore { buttonOffIcon = register("button_off") buttonOnIcon = register("button_on") - RenderICGate.registerIcons(reg) + ICGateRenderer.registerIcons(reg) for (m <- WireModel.wireModels) m.icon = register("surface/" + m.iconPath) for (m <- BaseComponentModel.baseModels) m.icon = register("surface/" + m.iconPath + "/base") + arrowIn = register("in") + arrowOut = register("out") + arrowInOut = register("inout") + ioBorder = register("io_freq") ioSig = register("io_sig") tLeverOffIcon = register("small_lever_off") @@ -132,6 +141,22 @@ object ICComponentStore { 0 ) + def orthoPartT(position: Vec2, scale: Double): TransformationList = { + new TransformationList( + new Scale( + RenderCircuit.BASE_SCALE * scale, + 1, + -RenderCircuit.BASE_SCALE * scale + ), + new Translation( + position.dx * RenderCircuit.BASE_SCALE * scale, + 0, + -position.dy * RenderCircuit.BASE_SCALE * scale + ), + new Rotation(1.571, 1, 0, 0) + ) + } + def orthoPartT( x: Double, y: Double, @@ -263,6 +288,28 @@ class IOSigModel extends ICComponentModel { } } +class ArrowModel extends ICComponentModel { + // 0: in, 1: out, 2: inout + var arrowDirection: Int = 0 + + override def renderModel( + t: Transformation, + orient: Int, + ortho: Boolean + ): Unit = { + val m = faceModels(dynamicIdx(orient, ortho)) + val t0 = dynamicT(orient) `with` t + m.render( + t0, + arrowDirection match { + case 0 => new IconTransformation(arrowIn) + case 1 => new IconTransformation(arrowOut) + case 2 => new IconTransformation(arrowInOut) + } + ) + } +} + class LeverModel(x: Double, z: Double) extends OnOffModel(new Vector3(x, 0, z)) { override def getIcons = Seq(tLeverOffIcon, tLeverOnIcon) diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepart.scala b/src/main/scala/mrtjp/projectred/fabrication/gatepart.scala deleted file mode 100644 index ddaa333c9..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepart.scala +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.vec.Transformation -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.util.Enum -import mrtjp.projectred.integration.GateDefinition.GateDef -import net.minecraft.nbt.NBTTagCompound - -abstract class GateICPart - extends CircuitPart - with TConnectableICPart - with TICOrient - with IGuiCircuitPart { - private var gateSubID: Byte = 0 - private var gateShape: Byte = 0 - - var schedTime = 0L - var schedDigital = false - - def getLogic[T]: T - def getLogicPrimitive = getLogic[ICGateLogic[GateICPart]] - - def subID = gateSubID & 0xff - - def shape = gateShape & 0xff - def setShape(s: Int) { gateShape = s.toByte } - - def preparePlacement(rot: Int, meta: Int) { - gateSubID = meta.toByte - setRotation(rot) - } - - override def save(tag: NBTTagCompound) { - tag.setByte("orient", orientation) - tag.setByte("subID", gateSubID) - tag.setByte("shape", gateShape) - tag.setByte("connMap", connMap) - tag.setLong("schedTime", schedTime) - } - - override def load(tag: NBTTagCompound) { - orientation = tag.getByte("orient") - gateSubID = tag.getByte("subID") - gateShape = tag.getByte("shape") - connMap = tag.getByte("connMap") - schedTime = tag.getLong("schedTime") - } - - override def writeDesc(out: MCDataOutput) { - out.writeByte(orientation) - out.writeByte(gateSubID) - out.writeByte(gateShape) - } - - override def readDesc(in: MCDataInput) { - orientation = in.readByte() - gateSubID = in.readByte() - gateShape = in.readByte() - } - - override def read(in: MCDataInput, key: Int) = key match { - case 1 => orientation = in.readByte() - case 2 => gateShape = in.readByte() - case _ => super.read(in, key) - } - - override def readClientPacket(in: MCDataInput) { - readClientPacket(in, in.readUByte()) - } - - def readClientPacket(in: MCDataInput, key: Int) = key match { - case 0 => rotate() - case 1 => configure() - case 2 => getLogicPrimitive.activate(this) - case _ => - } - - override def canConnectPart(part: CircuitPart, r: Int) = - getLogicPrimitive.canConnectTo(this, part, toInternal(r)) - - override def scheduledTick() { - getLogicPrimitive.scheduledTick(this) - } - - override def scheduleTick(ticks: Int) { - if (ticks == 0) scheduleDigitalTick() - else if (schedTime < 0) - schedTime = world.network.getWorld.getTotalWorldTime + ticks - } - - def processScheduled() { - if ( - schedTime >= 0 && world.network.getWorld.getTotalWorldTime >= schedTime - ) { - schedTime = -1 - scheduledTick() - } - } - - def scheduleDigitalTick() { - schedDigital = true - } - - var iter = 0 - def processScheduledDigital() { - while (schedDigital && iter < 3) // recursion control - { - schedDigital = false - iter += 1 - scheduledTick() - } - } - - def onChange() { - processScheduled() - getLogicPrimitive.onChange(this) - processScheduledDigital() - } - - override def update() { - if (!world.network.isRemote) { - processScheduled() - iter = 0 - processScheduledDigital() - } - getLogicPrimitive.onTick(this) - } - - override def onNeighborChanged() { - if (!world.network.isRemote) { - updateConns() - onChange() - } - } - - override def onAdded() { - super.onAdded() - if (!world.network.isRemote) { - getLogicPrimitive.setup(this) - updateConns() - onChange() - } - } - - override def onRemoved() { - super.onRemoved() - if (!world.network.isRemote) notify(0xf) - } - - def configure() { - if (getLogicPrimitive.cycleShape(this)) { - updateConns() - world.network.markSave() - sendShapeUpdate() - notify(0xf) - onChange() - } - } - - def rotate() { - setRotation((rotation + 1) % 4) - updateConns() - world.network.markSave() - sendOrientUpdate() - notify(0xf) - onChange() - } - - def sendShapeUpdate() { - writeStreamOf(2).writeByte(gateShape) - } - - def sendOrientUpdate() { - writeStreamOf(1).writeByte(orientation) - } - - @SideOnly(Side.CLIENT) - override def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) { - RenderICGate.renderDynamic(this, t, ortho, frame) - } - - @SideOnly(Side.CLIENT) - override def getPartName = ICGateDefinition(subID).name - - @SideOnly(Side.CLIENT) - override def getRolloverData(detailLevel: Int) = { - val s = Seq.newBuilder[String] - import net.minecraft.util.EnumChatFormatting._ - s ++= getLogicPrimitive.getRolloverData(this, detailLevel) - super.getRolloverData(detailLevel) ++ s.result().map(GRAY + _) - } - - @SideOnly(Side.CLIENT) - override def createGui = getLogicPrimitive.createGui(this) - - @SideOnly(Side.CLIENT) - override def onClicked() { - sendClientPacket(_.writeByte(2)) - } - - @SideOnly(Side.CLIENT) - override def getPickOp = - CircuitOpDefs.values(CircuitOpDefs.SimpleIO.ordinal + subID).getOp -} - -abstract class ICGateLogic[T <: GateICPart] { - def canConnectTo(gate: T, part: CircuitPart, r: Int): Boolean - - def cycleShape(gate: T) = false - - def onChange(gate: T) - - def scheduledTick(gate: T) - - def onTick(gate: T) {} - - def setup(gate: T) {} - - def activate(gate: T) {} - - @SideOnly(Side.CLIENT) - def getRolloverData(gate: T, detailLevel: Int): Seq[String] = Seq.empty - - @SideOnly(Side.CLIENT) - def createGui(gate: T): CircuitGui = new ICGateGui(gate) -} - -trait TComplexGateICPart extends GateICPart { - def getLogicComplex = getLogic[TComplexICGateLogic[TComplexGateICPart]] - - def assertLogic() - - abstract override def save(tag: NBTTagCompound) { - super.save(tag) - getLogicComplex.save(tag) - } - - abstract override def load(tag: NBTTagCompound) { - super.load(tag) - assertLogic() - getLogicComplex.load(tag) - } - - abstract override def writeDesc(packet: MCDataOutput) { - super.writeDesc(packet) - getLogicComplex.writeDesc(packet) - } - - abstract override def readDesc(packet: MCDataInput) { - super.readDesc(packet) - assertLogic() - getLogicComplex.readDesc(packet) - } - - abstract override def read(packet: MCDataInput, key: Int) = key match { - case k if k > 10 => - assertLogic() // this may be a net dump part - getLogicComplex.read(packet, k) - case _ => super.read(packet, key) - } - - abstract override def preparePlacement(rot: Int, meta: Int) { - super.preparePlacement(rot, meta) - assertLogic() - } -} - -trait TComplexICGateLogic[T <: TComplexGateICPart] extends ICGateLogic[T] { - def save(tag: NBTTagCompound) {} - def load(tag: NBTTagCompound) {} - - def readDesc(packet: MCDataInput) {} - def writeDesc(packet: MCDataOutput) {} - - /** Allocated keys > 10 - */ - def read(packet: MCDataInput, key: Int) {} -} - -object ICGateDefinition extends Enum { - type EnumVal = ICGateDef - - import mrtjp.projectred.integration.{GateDefinition => gd} - - val IOSimple = ICGateDef("Simple IO", CircuitPartDefs.IOGate.id) - val IOAnalog = ICGateDef("Analog IO", CircuitPartDefs.IOGate.id) - val IOBundled = ICGateDef("Bundled IO", CircuitPartDefs.IOGate.id) - - val OR = ICGateDef("OR gate", CircuitPartDefs.SimpleGate.id, gd.OR) - val NOR = ICGateDef("NOR gate", CircuitPartDefs.SimpleGate.id, gd.NOR) - val NOT = ICGateDef("NOT gate", CircuitPartDefs.SimpleGate.id, gd.NOT) - val AND = ICGateDef("AND gate", CircuitPartDefs.SimpleGate.id, gd.AND) - val NAND = ICGateDef("NAND gate", CircuitPartDefs.SimpleGate.id, gd.NAND) - val XOR = ICGateDef("XOR gate", CircuitPartDefs.SimpleGate.id, gd.XOR) - val XNOR = ICGateDef("XNOR gate", CircuitPartDefs.SimpleGate.id, gd.XNOR) - val Buffer = - ICGateDef("Buffer gate", CircuitPartDefs.SimpleGate.id, gd.Buffer) - val Multiplexer = - ICGateDef("Multiplexer", CircuitPartDefs.SimpleGate.id, gd.Multiplexer) - val Pulse = ICGateDef("Pulse Former", CircuitPartDefs.SimpleGate.id, gd.Pulse) - val Repeater = - ICGateDef("Repeater", CircuitPartDefs.SimpleGate.id, gd.Repeater) - val Randomizer = - ICGateDef("Randomizer", CircuitPartDefs.SimpleGate.id, gd.Randomizer) - val SRLatch = - ICGateDef("SR Latch", CircuitPartDefs.ComplexGate.id, gd.SRLatch) - val ToggleLatch = - ICGateDef("Toggle Latch", CircuitPartDefs.ComplexGate.id, gd.ToggleLatch) - val TransparentLatch = ICGateDef( - "Transparent Latch", - CircuitPartDefs.SimpleGate.id, - gd.TransparentLatch - ) - val Timer = ICGateDef("Timer", CircuitPartDefs.ComplexGate.id, gd.Timer) - val Sequencer = - ICGateDef("Sequencer", CircuitPartDefs.ComplexGate.id, gd.Sequencer) - val Counter = ICGateDef("Counter", CircuitPartDefs.ComplexGate.id, gd.Counter) - val StateCell = - ICGateDef("State Cell", CircuitPartDefs.ComplexGate.id, gd.StateCell) - val Synchronizer = - ICGateDef("Synchronizer", CircuitPartDefs.ComplexGate.id, gd.Synchronizer) - val DecRandomizer = - ICGateDef("Dec Randomizer", CircuitPartDefs.SimpleGate.id, gd.DecRandomizer) - val NullCell = - ICGateDef("Null Cell", CircuitPartDefs.ArrayGate.id, gd.NullCell) - val InvertCell = - ICGateDef("Invert Cell", CircuitPartDefs.ArrayGate.id, gd.InvertCell) - val BufferCell = - ICGateDef("Buffer Cell", CircuitPartDefs.ArrayGate.id, gd.BufferCell) - - case class ICGateDef(unlocal: String, gateType: Int, intDef: GateDef = null) - extends Value { - override def name = unlocal - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepartarray.scala b/src/main/scala/mrtjp/projectred/fabrication/gatepartarray.scala deleted file mode 100644 index 424782f20..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepartarray.scala +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import cpw.mods.fml.relauncher.{SideOnly, Side} -import mrtjp.core.vec.Point -import mrtjp.projectred.transmission.IWirePart -import net.minecraft.nbt.NBTTagCompound - -trait TArrayGateICPart - extends RedstoneGateICPart - with IRedwireICPart - with TRSPropagatingICPart { - def getLogicArray = getLogic[TArrayICGateLogic[TArrayGateICPart]] - - override def getSignal = - getLogicArray.getSignal(toInternalMask(propagationMask)) - override def setSignal(signal: Int) = - getLogicArray.setSignal(toInternalMask(propagationMask), signal) - - abstract override def updateAndPropagate(prev: CircuitPart, mode: Int) { - val rd = sideDiff(prev) - var uMask = 0 - for (r <- 0 until 4) if ((rd & 1 << r) != 0) { - val pMask = getLogicArray.propogationMask(toInternal(r)) - if (pMask > 0 && (pMask & uMask) != pMask) { - propagationMask = toAbsoluteMask(pMask) - super.updateAndPropagate(prev, mode) - uMask |= pMask - } - } - if (uMask == 0) ICPropagator.addNeighborChange(Point(x, y)) - propagationMask = 0xf - } - - override def propagateOther(mode: Int) { - val nonConn = ~(connMap | connMap >> 4 | connMap >> 8) & 0xf - notify(nonConn & propagationMask) - } - - def sideDiff(part: CircuitPart): Int = { - if (part.world == null) return 0xf - val here = Point(x, y) - val there = Point(part.x, part.y) - there - here match { - case Point(0, -1) => 1 << 0 - case Point(1, 0) => 1 << 1 - case Point(0, 1) => 1 << 2 - case Point(-1, 0) => 1 << 3 - case _ => - throw new RuntimeException( - s"Circuit array gate tried to propagate from $here to #$there" - ) - } - } - - override def calculateSignal: Int = { - val ipmask = toInternalMask(propagationMask) - if (getLogicArray.overrideSignal(ipmask)) - return getLogicArray.calculateSignal(ipmask) - - var s = 0 - ICPropagator.redwiresProvidePower = false - def raise(sig: Int) { if (sig > s) s = sig } - for (r <- 0 until 4) - if ((propagationMask & 1 << r) != 0) raise(calcSignal(r)) - ICPropagator.redwiresProvidePower = true - s - } - - abstract override def onChange() { - super.onChange() - ICPropagator.propagateTo(this, IWirePart.RISING) - } - - override def onSignalUpdate() { - world.network.markSave() - super.onChange() - getLogicArray.onSignalUpdate() - } - - override def resolveSignal(part: Any, r: Int) = part match { - case re: IRedwireICPart if re.diminishOnSide(r) => - re.getRedwireSignal(r) - 1 - case _ => super.resolveSignal(part, r) - } - - override def getRedwireSignal(r: Int) = { - val ir = toInternal(r) - val pmask = getLogicArray.propogationMask(ir) - if (pmask != 0) getLogicArray.getSignal(pmask) - else getLogicRS.getOutput(this, ir) - } - - override def canConnectRS(r: Int): Boolean = { - if (super.canConnectRS(r)) return true - getLogicArray.canConnectRedwire(this, toInternal(r)) - } - - override def rsOutputLevel(r: Int): Int = { - val ir = toInternal(r) - if ((getLogicArray.redwireMask(shape) & 1 << ir) != 0) - return if (ICPropagator.redwiresProvidePower) - getLogicArray.getSignal(getLogicArray.propogationMask(ir)) - else 0 - super.rsOutputLevel(r) - } - - override def diminishOnSide(r: Int) = - (getLogicArray.redwireMask(shape) & 1 << toInternal(r)) != 0 -} - -trait TArrayICGateLogic[T <: TArrayGateICPart] extends RedstoneICGateLogic[T] { - abstract override def canConnectTo(gate: T, part: CircuitPart, r: Int) = - part match { - case re: IRedwireICPart if canConnectRedwire(gate, r) => true - case _ => super.canConnectTo(gate, part, r) - } - - def canConnectRedwire(gate: T, r: Int): Boolean = - canConnectRedwire(gate.shape, r) - def canConnectRedwire(shape: Int, r: Int): Boolean = - (redwireMask(shape) & 1 << r) != 0 - - def redwireMask(shape: Int): Int - - def propogationMask(r: Int): Int - - def getSignal(mask: Int): Int - def setSignal(mask: Int, signal: Int) - - def overrideSignal(mask: Int) = false - def calculateSignal(mask: Int) = 0 - - def canCross = false - - def onSignalUpdate() -} - -class ArrayGateICPart - extends RedstoneGateICPart - with TComplexGateICPart - with TArrayGateICPart { - private var logic: ArrayGateICLogic = null - - override def getLogic[T] = logic.asInstanceOf[T] - - override def assertLogic() { - if (logic == null) logic = ArrayGateICLogic.create(this, subID) - } - - override def getPartType = CircuitPartDefs.ArrayGate -} - -object ArrayGateICLogic { - import ICGateDefinition._ - def create(gate: ArrayGateICPart, subID: Int) = subID match { - case NullCell.ordinal => new NullCell(gate) - case InvertCell.ordinal => new InvertCell(gate) - case BufferCell.ordinal => new BufferCell(gate) - case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) - } -} - -abstract class ArrayGateICLogic(val gate: ArrayGateICPart) - extends RedstoneICGateLogic[ArrayGateICPart] - with TArrayICGateLogic[ArrayGateICPart] - with TComplexICGateLogic[ArrayGateICPart] - -abstract class ArrayGateICLogicCrossing(gate: ArrayGateICPart) - extends ArrayGateICLogic(gate) { - var signal1: Byte = 0 - var signal2: Byte = 0 - - override def redwireMask(shape: Int) = 0xf - override def propogationMask(r: Int) = if (r % 2 == 0) 0x5 else 0xa - override def inputMask(shape: Int) = 0xf - override def outputMask(shape: Int) = 0xf - - override def getSignal(mask: Int) = - (if (mask == 0x5) signal1 else signal2) & 0xff - override def setSignal(mask: Int, signal: Int) { - if (mask == 0x5) signal1 = signal.toByte else signal2 = signal.toByte - } - - override def save(tag: NBTTagCompound) { - super.save(tag) - tag.setByte("s1", signal1) - tag.setByte("s2", signal2) - } - - override def load(tag: NBTTagCompound) { - super.load(tag) - signal1 = tag.getByte("s1") - signal2 = tag.getByte("s2") - } - - override def writeDesc(packet: MCDataOutput) { - super.writeDesc(packet) - packet.writeByte(signal1) - packet.writeByte(signal2) - } - - override def readDesc(packet: MCDataInput) { - super.readDesc(packet) - signal1 = packet.readByte() - signal2 = packet.readByte() - } - - override def read(packet: MCDataInput, key: Int) = key match { - case 11 => - signal1 = packet.readByte() - signal2 = packet.readByte() - case _ => - } - - def sendSignalUpdate() { - gate.writeStreamOf(11).writeByte(signal1).writeByte(signal2) - } - - override def onChange(gate: ArrayGateICPart) { - val oldSignal = (gate.state & 1) != 0 - val newSignal = signal1 != 0 - - if (oldSignal != newSignal) { - gate.setState(gate.state & 2 | (if (newSignal) 1 else 0)) - gate.onInputChange() - gate.scheduleTick(0) - } - } - - override def scheduledTick(gate: ArrayGateICPart) { - val input = (gate.state & 1) != 0 - val oldOutput = (gate.state & 2) != 0 - val newOutput = !input - - if (oldOutput != newOutput) { - gate.setState(gate.state & 1 | (if (newOutput) 2 else 0)) - gate.onOutputChange(0) - gate.onChange() - } - } - - override def onSignalUpdate() { sendSignalUpdate() } - - override def overrideSignal(mask: Int) = if (mask == 0xa) powerUp else false - - override def calculateSignal(mask: Int) = 255 - - def powerUp: Boolean - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: ArrayGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - - if (detailLevel >= 3) { - data += "lower: 0x" + Integer.toHexString(signal1 & 0xff) - data += "upper: 0x" + Integer.toHexString(signal2 & 0xff) - } else if (detailLevel >= 2) { - data += "lower: " + (if (signal1 != 0) "high" else "low") - data += "upper: " + (if (signal2 != 0) "high" else "low") - } - - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} - -class NullCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { - override def powerUp = false -} - -class InvertCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { - override def powerUp = (gate.state & 2) != 0 -} - -class BufferCell(gate: ArrayGateICPart) extends ArrayGateICLogicCrossing(gate) { - override def powerUp = (gate.state & 2) == 0 -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepartcomb.scala b/src/main/scala/mrtjp/projectred/fabrication/gatepartcomb.scala deleted file mode 100644 index 58a5aca20..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepartcomb.scala +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import java.util.Random - -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.projectred.core.TFaceOrient - -class ComboGateICPart extends RedstoneGateICPart { - override def getLogic[T] = ComboICGateLogic.instances(subID).asInstanceOf[T] - def getLogicCombo = getLogic[ComboICGateLogic] - - override def getPartType = CircuitPartDefs.SimpleGate -} - -object ComboICGateLogic { - val advanceDead = Seq(1, 2, 4, 0, 5, 6, 3) - - val instances = new Array[ComboICGateLogic](ICGateDefinition.values.length) - initialize() - - def initialize() { - import mrtjp.projectred.fabrication.{ICGateDefinition => defs} - instances(defs.OR.ordinal) = OR - instances(defs.NOR.ordinal) = NOR - instances(defs.NOT.ordinal) = NOT - instances(defs.AND.ordinal) = AND - instances(defs.NAND.ordinal) = NAND - instances(defs.XOR.ordinal) = XOR - instances(defs.XNOR.ordinal) = XNOR - instances(defs.Buffer.ordinal) = Buffer - instances(defs.Multiplexer.ordinal) = Multiplexer - instances(defs.Pulse.ordinal) = Pulse - instances(defs.Repeater.ordinal) = Repeater - instances(defs.Randomizer.ordinal) = Randomizer - instances(defs.TransparentLatch.ordinal) = TransparentLatch - instances(defs.DecRandomizer.ordinal) = DecRandomizer - } -} - -trait TSimpleRSICGateLogic[T <: RedstoneGateICPart] - extends RedstoneICGateLogic[T] { - def getDelay(shape: Int) = 0 - - def feedbackMask(shape: Int) = 0 - - def calcOutput(gate: T, input: Int) = 0 - - override def onChange(gate: T) { - val iMask = inputMask(gate.shape) - val oMask = outputMask(gate.shape) - val fMask = feedbackMask(gate.shape) - val oldInput = gate.state & 0xf - val newInput = getInput(gate, iMask | fMask) - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - } - - val newOutput = calcOutput(gate, gate.state & iMask) & oMask - if (newOutput != (gate.state >> 4)) gate.scheduleTick(getDelay(gate.shape)) - } - - override def scheduledTick(gate: T) { - val iMask = inputMask(gate.shape) - val oMask = outputMask(gate.shape) - val oldOutput = gate.state >> 4 - val newOutput = calcOutput(gate, gate.state & iMask) & oMask - if (oldOutput != newOutput) { - gate.setState(gate.state & 0xf | newOutput << 4) - gate.onOutputChange(oMask) - } - onChange(gate) - } - - override def setup(gate: T) { - val iMask = inputMask(gate.shape) - val oMask = outputMask(gate.shape) - val output = calcOutput(gate, getInput(gate, iMask)) & oMask - if (output != 0) { - gate.setState(output << 4) - gate.onOutputChange( - output - ) // use output for change mask because nothing is going low - } - } - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: T, detailLevel: Int) = { - val s = Seq.newBuilder[String] - if (detailLevel > 2) - s += "I: " + rolloverInput(gate) += "O: " + rolloverOutput(gate) - super.getRolloverData(gate, detailLevel) ++ s.result() - } - def rolloverInput(gate: T) = "0x" + Integer.toHexString(gate.state & 0xf) - def rolloverOutput(gate: T) = "0x" + Integer.toHexString(gate.state >> 4) -} - -abstract class ComboICGateLogic - extends RedstoneICGateLogic[ComboGateICPart] - with TSimpleRSICGateLogic[ComboGateICPart] { - override def cycleShape(gate: ComboGateICPart) = { - val oldShape = gate.shape - val newShape = cycleShape(oldShape) - if (newShape != oldShape) { - gate.setShape(newShape) - true - } else false - } - - def cycleShape(shape: Int): Int = { - if (deadSides == 0) return shape - - var shape1 = shape - import java.lang.Integer.{bitCount, numberOfLeadingZeros => lead} - do shape1 = ComboICGateLogic.advanceDead(shape1) while (bitCount( - shape1 - ) > maxDeadSides || 32 - lead(shape1) > deadSides) - shape1 - } - - def deadSides = 0 - def maxDeadSides = deadSides - 1 -} - -object OR extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = ~shape << 1 & 0xe - - override def deadSides = 3 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input != 0) 1 else 0 -} - -object NOR extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = ~shape << 1 & 0xe - override def feedbackMask(shape: Int) = 1 - - override def deadSides = 3 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input == 0) 1 else 0 -} - -object NOT extends ComboICGateLogic { - override def outputMask(shape: Int) = - ~((shape & 1) << 1 | (shape & 2) >> 1 | (shape & 4) << 1) & 0xb - override def inputMask(shape: Int) = 4 - override def feedbackMask(shape: Int) = outputMask(shape) - - override def deadSides = 3 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input == 0) 0xb else 0 -} - -object AND extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = ~shape << 1 & 0xe - - override def deadSides = 3 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input == inputMask(gate.shape)) 1 else 0 -} - -object NAND extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = ~shape << 1 & 0xe - - override def deadSides = 3 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input == inputMask(gate.shape)) 0 else 1 -} - -object XOR extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 10 - - override def calcOutput(gate: ComboGateICPart, input: Int) = { - val side1 = (input & 1 << 1) != 0 - val side2 = (input & 1 << 3) != 0 - if (side1 != side2) 1 else 0 - } -} - -object XNOR extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 10 - - override def calcOutput(gate: ComboGateICPart, input: Int) = { - val side1 = (input & 1 << 1) != 0 - val side2 = (input & 1 << 3) != 0 - if (side1 == side2) 1 else 0 - } -} - -object Buffer extends ComboICGateLogic { - override def outputMask(shape: Int) = - ~((shape & 1) << 1 | (shape & 2) << 2) & 0xb - override def inputMask(shape: Int) = 4 - override def feedbackMask(shape: Int) = outputMask(shape) - - override def deadSides = 2 - override def maxDeadSides = 2 - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input != 0) 0xb else 0 -} - -object Multiplexer extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 0xe - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if ((input & 1 << 2) != 0) (input >> 3) & 1 else (input >> 1) & 1 -} - -object Pulse extends ComboICGateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 4 - - override def calcOutput(gate: ComboGateICPart, input: Int) = 0 - - override def onChange(gate: ComboGateICPart) = { - val oldInput = gate.state & 0xf - val newInput = getInput(gate, 4) - - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - if (newInput != 0 && (gate.state & 0xf0) == 0) { - gate.setState(gate.state & 0xf | 0x10) - gate.scheduleTick(2) - gate.onOutputChange(1) - } - } - } -} - -object Repeater extends ComboICGateLogic { - val delays = Array(2, 4, 6, 8, 16, 32, 64, 128, 256) - - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 4 - - override def getDelay(shape: Int) = delays(shape) - - override def cycleShape(shape: Int) = (shape + 1) % delays.length - - override def calcOutput(gate: ComboGateICPart, input: Int) = - if (input == 0) 0 else 1 - - override def onChange(gate: ComboGateICPart) { - if (gate.schedTime < 0) super.onChange(gate) - } - - override def activate(gate: ComboGateICPart) { - gate.configure() - } - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: ComboGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - if (detailLevel > 1) data += "delay: " + delays(gate.shape) - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} - -object Randomizer extends ComboICGateLogic { - val rand = new Random - - override def outputMask(shape: Int) = - ~((shape & 1) << 1 | (shape & 2) >> 1 | (shape & 4) << 1) & 0xb - override def inputMask(shape: Int) = 4 - override def feedbackMask(shape: Int) = outputMask(shape) - - override def deadSides = 3 - - override def getDelay(shape: Int) = 2 - - override def calcOutput(gate: ComboGateICPart, input: Int) = { - if (input == 0) gate.state >> 4 - else - outputMask(gate.shape) & TFaceOrient.shiftMask(rand.nextInt(8), 3) - } - - override def onChange(gate: ComboGateICPart) { - super.onChange(gate) - if ((gate.state & 4) != 0) gate.scheduleTick(2) - } -} - -object TransparentLatch extends ComboICGateLogic { - override def outputMask(shape: Int) = if (shape == 0) 3 else 9 - override def inputMask(shape: Int) = if (shape == 0) 0xc else 6 - - override def cycleShape(shape: Int) = shape ^ 1 - - override def calcOutput(gate: ComboGateICPart, input: Int) = { - if ((input & 4) == 0) gate.state >> 4 - else if ((input & 0xa) == 0) 0 - else 0xf - } -} - -object DecRandomizer extends ComboICGateLogic { - val rand = new Random - - override def cycleShape(shape: Int) = shape ^ 1 - - override def outputMask(shape: Int) = if (shape == 0) 11 else 9 - override def inputMask(shape: Int) = 4 - override def feedbackMask(shape: Int) = 2 - - override def getDelay(shape: Int) = 2 - - override def calcOutput(gate: ComboGateICPart, input: Int) = { - if (input == 0) if ((gate.state >> 4) == 0) 1 else gate.state >> 4 - else Seq(1, 8, 2)(rand.nextInt((~gate.shape | 2) & 3)) - } - - override def onChange(gate: ComboGateICPart) { - super.onChange(gate) - if ((gate.state & 4) != 0) gate.scheduleTick(2) - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepartio.scala b/src/main/scala/mrtjp/projectred/fabrication/gatepartio.scala deleted file mode 100644 index ba5583e29..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepartio.scala +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.color.Colors -import net.minecraft.nbt.NBTTagCompound - -trait IIOCircuitPart { - def onExtInputChanged(r: Int) - def onExtOutputChanged(r: Int) - - def getIOSide: Int - def getIOMode: Int - def getConnMode: Int -} - -object IIOCircuitPart { - val Closed = 0 - val Input = 1 - val Output = 2 - val InOut = 3 - - val NoConn = 0 - val Simple = 1 - val Analog = 2 - val Bundled = 3 -} - -class IOGateICPart - extends RedstoneGateICPart - with IIOCircuitPart - with TComplexGateICPart { - private var logic: IOICGateLogic = null - - override def getLogic[T] = logic.asInstanceOf[T] - def getLogicIO = getLogic[IOICGateLogic] - - override def assertLogic() { - if (logic == null) logic = IOICGateLogic.create(this, subID) - } - - override def readClientPacket(in: MCDataInput, key: Int) = key match { - case 5 => - getLogicIO match { - case f: TFreqIOICGateLogic => f.freqUp() - case _ => - } - case 6 => - getLogicIO match { - case f: TFreqIOICGateLogic => f.freqDown() - case _ => - } - case _ => super.readClientPacket(in, key) - } - - override def getPartType = CircuitPartDefs.IOGate - - override def onExtInputChanged(r: Int) { - if (r == rotation) getLogicIO.extInputChange(this) - } - override def onExtOutputChanged(r: Int) { - if (r == rotation) getLogicIO.extOutputChange(this) - } - override def getIOSide = rotation - override def getIOMode = getLogicIO.getIOMode(this) - override def getConnMode = getLogicIO.getConnMode(this) - - override def getRedstoneInput(r: Int): Int = { - if (r == 0) getLogicIO.resolveInputFromWorld // r is to outside world - else super.getRedstoneInput(r) - } - - override def onOutputChange(mask: Int) { - super.onOutputChange(mask) - if ((mask & 1) != 0) { - val oldOutput = world.iostate(rotation) >>> 16 - getLogicIO.setWorldOutput((state & 0x10) != 0) - val newOutput = world.iostate(rotation) >>> 16 - if (oldOutput != newOutput) world.onOutputChanged(1 << rotation) - } - } -} - -object IOICGateLogic { - import mrtjp.projectred.fabrication.{ICGateDefinition => defs} - - def create(gate: IOGateICPart, subID: Int) = subID match { - case defs.IOSimple.ordinal => new SimpleIOICGateLogic(gate) - case defs.IOAnalog.ordinal => new AnalogIOICGateLogic(gate) - case defs.IOBundled.ordinal => new BundledIOICGateLogic(gate) - case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) - } -} - -abstract class IOICGateLogic(val gate: IOGateICPart) - extends RedstoneICGateLogic[IOGateICPart] - with TComplexICGateLogic[IOGateICPart] { - import IIOCircuitPart._ - - override def inputMask(shape: Int) = shape match { - case 0 => 1 - case 1 => 4 - case 2 => 5 - } - override def outputMask(shape: Int) = shape match { - case 0 => 4 - case 1 => 1 - case 2 => 5 - } - - override def cycleShape(gate: IOGateICPart) = { - gate.setShape((gate.shape + 1) % 3) - true - } - - def extInputChange(gate: IOGateICPart) { gate.onChange() } - def extOutputChange(gate: IOGateICPart) {} - def getIOMode(gate: IOGateICPart): Int = gate.shape match { - case 0 => Input - case 1 => Output - case 2 => InOut - } - def getConnMode(gate: IOGateICPart): Int - - def resolveInputFromWorld: Int - def resolveOutputToWorld: Int - def setWorldOutput(state: Boolean) - def toggleWorldInput() - - override def onChange(gate: IOGateICPart) { - val oldInput = gate.state & 0xf - val newInput = getInput(gate, ~(gate.state >> 4) & inputMask(gate.shape)) - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - gate.scheduleTick(0) - } - } - - override def scheduledTick(gate: IOGateICPart) { - val oldOutput = gate.state >> 4 - val newOutput = - TICOrient.shiftMask(gate.state & 0xf, 2) & outputMask(gate.shape) - if (oldOutput != newOutput) { - gate.setState(gate.state & 0xf | newOutput << 4) - gate.onOutputChange(oldOutput ^ newOutput) - } - onChange(gate) - } - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: IOGateICPart, detailLevel: Int) = { - val s = Seq.newBuilder[String] - if (detailLevel >= 2) { - val f = getFreqName - if (f.nonEmpty) s += "freq: " + f - s += "mode: " + (gate.shape match { - case 0 => "I" - case 1 => "O" - case 2 => "IO" - }) - } - if (detailLevel >= 3) { - s += "I: " + (if (resolveInputFromWorld != 0) "high" else "low") - s += "O: " + (if (resolveOutputToWorld != 0) "high" else "low") - } - super.getRolloverData(gate, detailLevel) ++ s.result() - } - - def getFreqName = "" - - override def activate(gate: IOGateICPart) { - toggleWorldInput() - gate.world.onInputChanged(1 << gate.rotation) - } -} - -trait TRSIOICGateLogic extends IOICGateLogic { - override def setup(gate: IOGateICPart) { - if ((gate.world.iostate(gate.rotation) & 0xffff) == 0) { - gate.world.setInput(gate.rotation, 1) - gate.world.onInputChanged(1 << gate.rotation) - } - } - - override def extInputChange(gate: IOGateICPart) { - if ((gate.world.iostate(gate.rotation) & 0xffff) == 0) { - gate.world.setInput(gate.rotation, 1) - gate.world.onInputChanged(1 << gate.rotation) - } - super.extInputChange(gate) - } -} - -class SimpleIOICGateLogic(gate: IOGateICPart) - extends IOICGateLogic(gate) - with TRSIOICGateLogic { - override def getConnMode(gate: IOGateICPart) = IIOCircuitPart.Simple - - override def resolveInputFromWorld = - if ((gate.world.iostate(gate.rotation) & 0xfffe) != 0) 255 - else 0 - - override def resolveOutputToWorld = - if (((gate.world.iostate(gate.rotation) >> 16) & 0xfffe) != 0) 255 else 0 - - override def setWorldOutput(state: Boolean) { - gate.world.setOutput(gate.rotation, if (state) 0x8000 else 1) - } - - override def toggleWorldInput() { - gate.world.setInput( - gate.rotation, - if ((gate.world.iostate(gate.rotation) & 0x8000) != 0) 1 else 0x8000 - ) - } - - @SideOnly(Side.CLIENT) - override def createGui(gate: IOGateICPart): CircuitGui = new ICIOGateGui(gate) -} - -trait TFreqIOICGateLogic extends IOICGateLogic { - var freq = 0 - - override def save(tag: NBTTagCompound) { - super.save(tag) - tag.setByte("freq", freq.toByte) - } - - override def load(tag: NBTTagCompound) { - super.load(tag) - freq = tag.getByte("freq") - } - - override def writeDesc(out: MCDataOutput) { - super.writeDesc(out) - out.writeByte(freq) - } - - override def readDesc(in: MCDataInput) { - super.readDesc(in) - freq = in.readUByte() - } - - override def read(in: MCDataInput, key: Int) = key match { - case 12 => freq = in.readUByte() - case _ => super.read(in, key) - } - - def sendFreqUpdate() { - gate.writeStreamOf(12).writeByte(freq) - } - - def freqUp() { - if (freq < 15) { - freq += 1 - sendFreqUpdate() - gate.onChange() - } - } - - def freqDown() { - if (freq > 0) { - freq -= 1 - sendFreqUpdate() - gate.onChange() - } - } - - override def resolveInputFromWorld = - if ((gate.world.iostate(gate.rotation) & 1 << freq) != 0) 255 - else 0 - - override def resolveOutputToWorld = - if ((gate.world.iostate(gate.rotation) >>> 16 & 1 << freq) != 0) 255 - else 0 - - override def setWorldOutput(state: Boolean) { - val s = - ((gate.world.iostate(gate.rotation) >>> 16) & ~(1 << freq)) | (if (state) - 1 - else - 0) << freq - gate.world.setOutput(gate.rotation, s) - } - - @SideOnly(Side.CLIENT) - override def createGui(gate: IOGateICPart): CircuitGui = new ICIOFreqGateGui( - gate - ) -} - -class AnalogIOICGateLogic(gate: IOGateICPart) - extends IOICGateLogic(gate) - with TFreqIOICGateLogic - with TRSIOICGateLogic { - override def getConnMode(gate: IOGateICPart) = IIOCircuitPart.Analog - - override def getFreqName = "0x" + Integer.toHexString(freq) - - override def toggleWorldInput() { - val newInput = (gate.world.iostate(gate.rotation) & 1 << freq) ^ 1 << freq - gate.world.setInput(gate.rotation, if (newInput == 0) 1 else newInput) - } -} - -class BundledIOICGateLogic(gate: IOGateICPart) - extends IOICGateLogic(gate) - with TFreqIOICGateLogic { - override def getConnMode(gate: IOGateICPart) = IIOCircuitPart.Bundled - - override def getFreqName = Colors(freq).name.toLowerCase - - override def toggleWorldInput() { - gate.world.setInput( - gate.rotation, - (gate.world.iostate(gate.rotation) & 0xffff) ^ 1 << freq - ) - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gatepartseq.scala b/src/main/scala/mrtjp/projectred/fabrication/gatepartseq.scala deleted file mode 100644 index eac3ce4ef..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gatepartseq.scala +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.multipart.handler.MultipartSaveLoad -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.projectred.ProjectRedCore.log -import mrtjp.projectred.core.Configurator -import mrtjp.projectred.core.TFaceOrient._ -import net.minecraft.nbt.NBTTagCompound - -class SequentialGateICPart extends RedstoneGateICPart with TComplexGateICPart { - var logic: SequentialICGateLogic = null - - override def assertLogic() { - if (logic == null) logic = SequentialICGateLogic.create(this, subID) - } - - override def getLogic[T]: T = logic.asInstanceOf[T] - - override def getPartType = CircuitPartDefs.ComplexGate - - override def readClientPacket(in: MCDataInput, key: Int) = key match { - case 3 => - getLogicPrimitive match { - case t: ITimerGuiLogic => - t.setTimerMax(this, t.getTimerMax + in.readShort()) - case _ => - log.error( - "Server IC stream received client packet for incorrect gate type" - ) - } - case 4 => - getLogicPrimitive match { - case t: ICounterGuiLogic => - val actionID = in.readByte() - actionID match { - case 0 => t.setCounterMax(this, t.getCounterMax + in.readShort()) - case 1 => t.setCounterIncr(this, t.getCounterIncr + in.readShort()) - case 2 => t.setCounterDecr(this, t.getCounterDecr + in.readShort()) - case _ => - log.error( - "Server IC stream received client packet for incorrect gate type" - ) - } - case _ => - log.error( - "Server IC stream received client packet for incorrect gate type" - ) - } - case _ => super.readClientPacket(in, key) - } -} - -object SequentialICGateLogic { - import mrtjp.projectred.fabrication.{ICGateDefinition => defs} - - def create(gate: SequentialGateICPart, subID: Int) = subID match { - case defs.SRLatch.ordinal => new SRLatch(gate) - case defs.ToggleLatch.ordinal => new ToggleLatch(gate) - case defs.Timer.ordinal => new Timer(gate) - case defs.Sequencer.ordinal => new Sequencer(gate) - case defs.Counter.ordinal => new Counter(gate) - case defs.StateCell.ordinal => new StateCell(gate) - case defs.Synchronizer.ordinal => new Synchronizer(gate) - case _ => throw new IllegalArgumentException("Invalid gate subID: " + subID) - } -} - -abstract class SequentialICGateLogic(val gate: SequentialGateICPart) - extends RedstoneICGateLogic[SequentialGateICPart] - with TComplexICGateLogic[SequentialGateICPart] - -trait TExtraStateLogic extends SequentialICGateLogic { - private var lState2: Byte = 0 - - def state2 = lState2 & 0xff - def setState2(state: Int) { lState2 = state.toByte } - - def clientState2 = false - - abstract override def save(tag: NBTTagCompound) { - super.save(tag) - tag.setByte("state2", lState2) - } - - abstract override def load(tag: NBTTagCompound) { - super.load(tag) - lState2 = tag.getByte("state2") - } - - abstract override def writeDesc(packet: MCDataOutput) { - super.writeDesc(packet) - if (clientState2) packet.writeByte(lState2) - } - - abstract override def readDesc(packet: MCDataInput) { - super.readDesc(packet) - if (clientState2) lState2 = packet.readByte() - } - - abstract override def read(packet: MCDataInput, key: Int) = key match { - case 11 => lState2 = packet.readByte() - case _ => super.read(packet, key) - } - - def sendState2Update() { gate.writeStreamOf(11).writeByte(lState2) } -} - -class SRLatch(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with TExtraStateLogic { - override def outputMask(shape: Int) = if ((shape >> 1) == 0) 0xf else 5 - override def inputMask(shape: Int) = 0xa - - override def cycleShape(gate: SequentialGateICPart) = { - gate.setShape((gate.shape + 1) % 4) - setState2(flipMaskZ(state2)) - gate.setState(flipMaskZ(gate.state)) - gate.onOutputChange(0xf) - gate.scheduleTick(0) - true - } - - override def setup(gate: SequentialGateICPart) { - setState2(2) - gate.setState(0x30) - } - - override def onChange(gate: SequentialGateICPart) { - val stateInput = state2 - - val oldInput = gate.state & 0xf - val newInput = getInput(gate, 0xa) - val oldOutput = gate.state >> 4 - - if (newInput != oldInput) - if ( - stateInput != 0xa && newInput != 0 && newInput != stateInput - ) // state needs changing - { - gate.setState(newInput) - setState2(newInput) - gate.onOutputChange(oldOutput) // always going low - gate.scheduleTick(0) - } else { - gate.setState(oldOutput << 4 | newInput) - gate.onInputChange() - } - } - - override def scheduledTick(gate: SequentialGateICPart) { - val oldOutput = gate.state >> 4 - val newOutput = calcOutput(gate) - - if (oldOutput != newOutput) { - gate.setState(gate.state & 0xf | newOutput << 4) - gate.onOutputChange(outputMask(gate.shape)) - } - onChange(gate) - } - - def calcOutput(gate: SequentialGateICPart): Int = { - var input = gate.state & 0xf - var stateInput = state2 - - if ((gate.shape & 1) != 0) // reverse - { - input = flipMaskZ(input) - stateInput = flipMaskZ(stateInput) - } - - if (stateInput == 0xa) // disabled - { - if (input == 0xa) { - gate.scheduleTick(0) - return 0 - } - - stateInput = - if (input == 0) - if (gate.world.network.getWorld.rand.nextBoolean()) 2 else 8 - else input - - setState2( - if ((gate.shape & 1) != 0) flipMaskZ(stateInput) else stateInput - ) - } - - var output = shiftMask(stateInput, 1) - if ((gate.shape & 2) == 0) output |= stateInput - if ((gate.shape & 1) != 0) output = flipMaskZ(output) // reverse - output - } -} - -class ToggleLatch(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with TExtraStateLogic { - override def outputMask(shape: Int) = 5 - override def inputMask(shape: Int) = 0xa - - override def clientState2 = true - - override def setup(gate: SequentialGateICPart) { - gate.setState(0x10) - gate.sendStateUpdate() - } - - override def onChange(gate: SequentialGateICPart) { - val oldInput = gate.state & 0xf - val newInput = getInput(gate, 0xa) - val high = newInput & ~oldInput - - if (high == 2 || high == 8) toggle(gate) - - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - } - } - - override def scheduledTick(gate: SequentialGateICPart) { - val oldOutput = gate.state >> 4 - val newOutput = if (state2 == 0) 1 else 4 - if (oldOutput != newOutput) { - gate.setState(newOutput << 4 | gate.state & 0xf) - gate.onOutputChange(5) - } - onChange(gate) - } - - override def activate(gate: SequentialGateICPart) { - toggle(gate) - } - - def toggle(gate: SequentialGateICPart) { - setState2(state2 ^ 1) - gate.scheduleTick(0) - } -} - -trait ITimerGuiLogic { - def getTimerMax: Int - def setTimerMax(gate: GateICPart, t: Int) -} - -trait ICounterGuiLogic { - def getCounterMax: Int - def setCounterMax(gate: GateICPart, i: Int) - - def getCounterIncr: Int - def setCounterIncr(gate: GateICPart, i: Int) - - def getCounterDecr: Int - def setCounterDecr(gate: GateICPart, i: Int) - - def getCounterValue: Int - def setCounterValue(gate: GateICPart, i: Int) -} - -trait TTimerGateLogic extends SequentialICGateLogic with ITimerGuiLogic { - var pointer_max = 38 - var pointer_start = -1L - var saveTime = -1L // used for blueprint in-hand rendering - - abstract override def save(tag: NBTTagCompound) { - super.save(tag) - tag.setInteger("pmax", pointer_max) - tag.setLong( - "pelapsed", - if (pointer_start < 0) pointer_start else getTotalTime - pointer_start - ) - tag.setLong("tsave", getTotalTime) - } - - abstract override def load(tag: NBTTagCompound) { - super.load(tag) - pointer_max = tag.getInteger("pmax") - pointer_start = tag.getLong("pelapsed") - saveTime = tag.getLong("tsave") - if (pointer_start >= 0) pointer_start = getTotalTime - pointer_start - } - - abstract override def writeDesc(packet: MCDataOutput) { - super.writeDesc(packet) - packet.writeInt(pointer_max) - packet.writeLong(pointer_start) - } - - abstract override def readDesc(packet: MCDataInput) { - super.readDesc(packet) - pointer_max = packet.readInt() - pointer_start = packet.readLong() - } - - abstract override def read(packet: MCDataInput, key: Int) = key match { - case 12 => pointer_max = packet.readInt() - case 13 => - pointer_start = packet.readInt() - if (pointer_start >= 0) pointer_start = getTotalTime - pointer_start - case _ => super.read(packet, key) - } - - def getTotalTime = // client-side safe version of getTotalWorldTime (workaround for no client world) - { - if (gate.world.network == null) - saveTime // ic was loaded directly from stack, possibly for in-hand render - else if (gate.world.network.getWorld == null) - MultipartSaveLoad.loadingWorld.getTotalWorldTime // ic is being loaded with a workbench tile or gate - else - gate.world.network.getWorld.getTotalWorldTime // normal access during operation - } - - def pointerValue = - if (pointer_start < 0) 0 else (getTotalTime - pointer_start).toInt - - def sendPointerMaxUpdate() { gate.writeStreamOf(12).writeInt(pointer_max) } - def sendPointerUpdate() { - gate.writeStreamOf(13).writeInt(if (pointer_start < 0) -1 else pointerValue) - } - - override def getTimerMax = pointer_max + 2 - override def setTimerMax(gate: GateICPart, time: Int) { - var t = time - val minTime = math.max(4, Configurator.minTimerTicks) - if (t < minTime) t = minTime - if (t != pointer_max) { - pointer_max = t - 2 - sendPointerMaxUpdate() - } - } - - override def onTick(gate: SequentialGateICPart) { - if (pointer_start >= 0) - if (getTotalTime >= pointer_start + pointer_max) pointerTick() - else if (pointer_start > getTotalTime) - pointer_start = getTotalTime - } - - def pointerTick() - - def resetPointer() { - if (pointer_start >= 0) { - pointer_start = -1 - gate.world.network.markSave() - if (!gate.world.network.isRemote) sendPointerUpdate() - } - } - - def startPointer() { - if (pointer_start < 0) { - pointer_start = getTotalTime - gate.world.network.markSave() - if (!gate.world.network.isRemote) sendPointerUpdate() - } - } - - def interpPointer(f: Float) = - if (pointer_start < 0) 0f else (pointerValue + f) / pointer_max - - @SideOnly(Side.CLIENT) - override def createGui(gate: SequentialGateICPart): CircuitGui = - new ICTimerGateGui(gate) - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - if (detailLevel > 1) - data += "interval: " + "%.2f".format(getTimerMax * 0.05) + "s" - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} - -class Timer(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with TTimerGateLogic { - override def outputMask(shape: Int) = 0xb - override def inputMask(shape: Int) = 0xe - - override def setup(gate: SequentialGateICPart) { startPointer() } - - override def scheduledTick(gate: SequentialGateICPart) { - gate.setState(gate.state & 0xf) - gate.onOutputChange(0xb) - onChange(gate) - } - - override def onChange(gate: SequentialGateICPart) { - val oldInput = gate.state & 0xf - val newInput = getInput(gate, 0xe) - - if (newInput != oldInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - } - - if (gate.schedTime < 0) - if (newInput > 0) resetPointer() else startPointer() - } - - override def pointerTick() { - resetPointer() - if (!gate.world.network.isRemote) { - gate.scheduleTick(2) - gate.setState(0xb0 | gate.state & 0xf) - gate.onOutputChange(0xb) - } - } -} - -class Sequencer(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with ITimerGuiLogic { - var pointer_max = 40 - var saveTime = -1L - - override def outputMask(shape: Int) = 0xf - - override def onChange(gate: SequentialGateICPart) {} - override def scheduledTick(gate: SequentialGateICPart) {} - - override def getTimerMax = pointer_max - override def setTimerMax(gate: GateICPart, time: Int) { - var t = time - val minTime = math.max(4, Configurator.minTimerTicks) - if (t < minTime) t = minTime - if (t != pointer_max) { - pointer_max = t - sendPointerMaxUpdate() - } - } - - override def save(tag: NBTTagCompound) { - tag.setInteger("pmax", pointer_max) - tag.setLong("tsave", getWorldTime) - } - override def load(tag: NBTTagCompound) { - pointer_max = tag.getInteger("pmax") - saveTime = tag.getLong("tsave") - } - - override def writeDesc(packet: MCDataOutput) { packet.writeInt(pointer_max) } - override def readDesc(packet: MCDataInput) { pointer_max = packet.readInt() } - - override def read(packet: MCDataInput, key: Int) = key match { - case 12 => pointer_max = packet.readInt() - case _ => - } - - def sendPointerMaxUpdate() { gate.writeStreamOf(12).writeInt(pointer_max) } - - def getWorldTime = - if (gate.world.network != null) gate.world.network.getWorld.getWorldTime - else saveTime - - override def onTick(gate: SequentialGateICPart) { - if (!gate.world.network.isRemote) { - val oldOut = gate.state >> 4 - var out = 1 << getWorldTime % (pointer_max * 4) / pointer_max - if (gate.shape == 1) out = flipMaskZ(out) - if (oldOut != out) { - gate.setState(out << 4) - gate.onOutputChange(0xf) - } - } - } - - override def cycleShape(gate: SequentialGateICPart) = { - gate.setShape(gate.shape ^ 1) - true - } - - @SideOnly(Side.CLIENT) - override def createGui(gate: SequentialGateICPart): CircuitGui = - new ICTimerGateGui(gate) - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - if (detailLevel > 1) - data += "interval: " + "%.2f".format(getTimerMax * 0.05) + "s" - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} - -class Counter(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with ICounterGuiLogic { - var value = 0 - var max = 10 - var incr = 1 - var decr = 1 - - override def outputMask(shape: Int) = 5 - override def inputMask(shape: Int) = 10 - - override def save(tag: NBTTagCompound) { - tag.setInteger("val", value) - tag.setInteger("max", max) - tag.setInteger("inc", incr) - tag.setInteger("dec", decr) - } - - override def load(tag: NBTTagCompound) { - value = tag.getInteger("val") - max = tag.getInteger("max") - incr = tag.getInteger("inc") - decr = tag.getInteger("dec") - } - - override def writeDesc(packet: MCDataOutput) { - packet.writeInt(value).writeInt(max).writeInt(incr).writeInt(decr) - } - - override def readDesc(packet: MCDataInput) { - value = packet.readInt() - max = packet.readInt() - incr = packet.readInt() - decr = packet.readInt() - } - - override def read(packet: MCDataInput, key: Int) = key match { - case 11 => value = packet.readInt() - case 12 => max = packet.readInt() - case 13 => incr = packet.readInt() - case 14 => decr = packet.readInt() - case _ => - } - - def sendValueUpdate() { gate.writeStreamOf(11).writeInt(value) } - def sendMaxUpdate() { gate.writeStreamOf(12).writeInt(max) } - def sendIncrUpdate() { gate.writeStreamOf(13).writeInt(incr) } - def sendDecrUpdate() { gate.writeStreamOf(14).writeInt(decr) } - - override def getCounterValue = value - override def getCounterMax = max - override def getCounterIncr = incr - override def getCounterDecr = decr - - override def setCounterValue(gate: GateICPart, i: Int) { - val oldVal = value - value = Math.min(max, Math.max(0, i)) - if (value != oldVal) - sendValueUpdate() - } - - override def setCounterMax(gate: GateICPart, i: Int) { - val oldMax = max - max = Math.min(32767, Math.max(1, i)) - if (max != oldMax) { - sendMaxUpdate() - val oldVal = value - value = Math.min(value, Math.max(0, i)) - if (value != oldVal) { - sendValueUpdate() - gate.scheduleTick(2) - } - } - } - - override def setCounterIncr(gate: GateICPart, i: Int) { - val oldIncr = incr - incr = Math.min(max, Math.max(1, i)) - if (incr != oldIncr) - sendIncrUpdate() - } - - override def setCounterDecr(gate: GateICPart, i: Int) { - val oldDecr = decr - decr = Math.min(max, Math.max(1, i)) - if (decr != oldDecr) - sendDecrUpdate() - } - - def onChange(gate: SequentialGateICPart) { - val oldInput = gate.state & 0xf - var newInput = getInput(gate, 0xa) - if (gate.shape == 1) newInput = flipMaskZ(newInput) - val high = newInput & ~oldInput - - if ((high & 2) != 0) setCounterValue(gate, value + incr) - if ((high & 8) != 0) setCounterValue(gate, value - decr) - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - gate.scheduleTick(2) - } - } - - override def cycleShape(gate: SequentialGateICPart) = { - gate.setShape(if (gate.shape == 1) 0 else 1) - true - } - - def scheduledTick(gate: SequentialGateICPart) { - val oldOutput = gate.state - var newOutput = 0 - if (value == max) newOutput = 1 - else if (value == 0) newOutput = 4 - if (newOutput != oldOutput) gate.setState(gate.state & 0xf | newOutput << 4) - if (newOutput != oldOutput) gate.onOutputChange(5) - } - - @SideOnly(Side.CLIENT) - override def createGui(gate: SequentialGateICPart): CircuitGui = - new ICCounterGateGui(gate) - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - if (detailLevel > 1) { - data += "state: " + getCounterValue - if (detailLevel > 2) { - data += "max: " + getCounterMax - data += "incr: " + getCounterIncr - data += "decr: " + getCounterDecr - } - } - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} - -class StateCell(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with TTimerGateLogic - with TExtraStateLogic { - override def outputMask(shape: Int) = { - var output = 9 - if (shape == 1) output = flipMaskZ(output) - output - } - - override def inputMask(shape: Int) = { - var input = 6 - if (shape == 1) input = flipMaskZ(input) - input - } - - override def cycleShape(gate: SequentialGateICPart) = { - gate.setShape((gate.shape + 1) % 2) - true - } - - override def onChange(gate: SequentialGateICPart) { - val oldInput = gate.state & 0xf - var newInput = getInput(gate, 0xe) - if (oldInput != newInput) { - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - - if (gate.shape == 1) newInput = flipMaskZ(newInput) - if ((newInput & 4) != 0 && state2 == 0) { - setState2(1) - sendState2Update() - gate.scheduleTick(0) - } - - if (state2 != 0) - if ((newInput & 6) != 0) resetPointer() - else startPointer() - } - } - - override def pointerTick() { - resetPointer() - if (!gate.world.network.isRemote) { - setState2(0) - sendState2Update() - gate.setState(0x10 | gate.state & 0xf) - gate.onOutputChange(outputMask(gate.shape)) - gate.scheduleTick(2) - } - } - - override def scheduledTick(gate: SequentialGateICPart) { - var output = 0 - if (state2 != 0) output = 8 - if (gate.shape == 1) output = flipMaskZ(output) - - gate.setState(output << 4 | gate.state & 0xf) - gate.onOutputChange(outputMask(gate.shape)) - } -} - -class Synchronizer(gate: SequentialGateICPart) - extends SequentialICGateLogic(gate) - with TExtraStateLogic { - override def outputMask(shape: Int) = 1 - override def inputMask(shape: Int) = 14 - - override def onChange(gate: SequentialGateICPart) { - val oldInput = gate.state & 0xf - val newInput = getInput(gate, 14) - val high = newInput & ~oldInput - if (oldInput != newInput) { - val oldValue = state2 - - gate.setState(gate.state & 0xf0 | newInput) - gate.onInputChange() - if ((newInput & 4) != 0) setState2(0) - else { - if ((high & 2) != 0) setState2(state2 | 1) // right - if ((high & 8) != 0) setState2(state2 | 2) // left - } - if (right && left) gate.scheduleTick(0) - - if (state2 != oldValue) sendState2Update() - } - } - - override def scheduledTick(gate: SequentialGateICPart) { - val oldValue = state2 - if (!pulsing && right && left) { - gate.setState(gate.state | 1 << 4) - gate.onOutputChange(1) - setState2(state2 | 4) // pulsing - gate.scheduleTick(2) - } else if (pulsing) { - gate.setState(gate.state & ~0x10) - gate.onOutputChange(1) - setState2(0) // off - } - if (state2 != oldValue) sendState2Update() - } - - def right = (state2 & 1) != 0 - def left = (state2 & 2) != 0 - def pulsing = (state2 & 4) != 0 - - @SideOnly(Side.CLIENT) - override def getRolloverData(gate: SequentialGateICPart, detailLevel: Int) = { - val data = Seq.newBuilder[String] - if (detailLevel > 1) { - data += "0: " + (if (right) "high" else "low") - data += "1: " + (if (left) "high" else "low") - } - super.getRolloverData(gate, detailLevel) ++ data.result() - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gaterenders.scala b/src/main/scala/mrtjp/projectred/fabrication/gaterenders.scala deleted file mode 100644 index c7279f3d7..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/gaterenders.scala +++ /dev/null @@ -1,987 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.math.MathHelper -import codechicken.lib.render.CCRenderState -import codechicken.lib.vec.Transformation -import mrtjp.core.color.Colors -import mrtjp.projectred.core.TFaceOrient._ -import mrtjp.projectred.fabrication.ICComponentStore._ -import net.minecraft.client.renderer.texture.IIconRegister - -object RenderICGate { - var renderers = buildRenders() - - def buildRenders() = Seq[ICGateRenderer[_]]( - new RenderSimpleIO, - new RenderAnalogIO, - new RenderBundledIO, - new RenderOR, - new RenderNOR, - new RenderNOT, - new RenderAND, - new RenderNAND, - new RenderXOR, - new RenderXNOR, - new RenderBuffer, - new RenderMultiplexer, - new RenderPulse, - new RenderRepeater, - new RenderRandomizer, - new RenderSRLatch, - new RenderToggleLatch, - new RenderTransparentLatch, - new RenderTimer, - new RenderSequencer, - new RenderCounter, - new RenderStateCell, - new RenderSynchronizer, - new RenderDecRandomizer, - new RenderNullCell, - new RenderInvertCell, - new RenderBufferCell - ) - - def registerIcons(reg: IIconRegister) {} - - def renderDynamic( - gate: GateICPart, - t: Transformation, - ortho: Boolean, - frame: Float - ) { - val r = renderers(gate.subID).asInstanceOf[ICGateRenderer[GateICPart]] - r.prepareDynamic(gate, frame) - r.renderDynamic(gate.rotationT `with` t, ortho) - } - - def renderInv(t: Transformation, id: Int) { - val r = renderers(id) - r.prepareInv() - r.renderDynamic(t, true) - } -} - -abstract class ICGateRenderer[T <: GateICPart] { - var reflect = false - - def coreModels: Seq[ICComponentModel] - def switchModels = Seq[ICComponentModel]() - - def prepareInv() {} - def prepareDynamic(gate: T, frame: Float) {} - - def renderDynamic(t: Transformation, ortho: Boolean) { - renderModels(t, if (reflect) 1 else 0, ortho) - } - - def renderModels(t: Transformation, orient: Int, ortho: Boolean) { - prepairRender() - for (m <- coreModels ++ switchModels) m.renderModel(t, orient, ortho) - finishRender() - } -} - -abstract class RenderIO extends ICGateRenderer[IOGateICPart] { - val wires = generateWireModels("IOSIMP", 1) - val iosig = new IOSigModel - - override val coreModels = - Seq(new BaseComponentModel("IOSIMP")) ++ wires :+ iosig - - override def prepareInv() { - wires(0).on = false - iosig.on = false - iosig.colour = invColour - } - - override def prepareDynamic(gate: IOGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x44) != 0 - iosig.on = wires(0).on - iosig.colour = dynColour(gate) - } - - def invColour: Int - def dynColour(gate: IOGateICPart): Int -} - -class RenderSimpleIO extends RenderIO { - override def invColour = signalColour(0.toByte) - override def dynColour(gate: IOGateICPart) = signalColour( - (if (iosig.on) 255 else 0).toByte - ) -} - -class RenderAnalogIO extends RenderIO { - override def invColour = signalColour(0.toByte) - override def dynColour(gate: IOGateICPart) = signalColour( - (gate.getLogic[AnalogIOICGateLogic].freq * 17).toByte - ) -} - -class RenderBundledIO extends RenderIO { - override def invColour = Colors(0).rgba - override def dynColour(gate: IOGateICPart) = Colors( - gate.getLogic[AnalogIOICGateLogic].freq - ).rgba -} - -class RenderOR extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("OR", 4) - val torches = - Seq(new RedstoneTorchModel(8, 9), new RedstoneTorchModel(8, 2.5)) - - override val coreModels = - Seq(new BaseComponentModel("OR")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(1).disabled = false - wires(2).disabled = false - wires(3).disabled = false - torches(0).on = true - torches(1).on = false - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x10) == 0 - wires(1).on = (gate.state & 2) != 0 - wires(2).on = (gate.state & 4) != 0 - wires(3).on = (gate.state & 8) != 0 - wires(1).disabled = (gate.shape & 1) != 0 - wires(2).disabled = (gate.shape & 2) != 0 - wires(3).disabled = (gate.shape & 4) != 0 - torches(0).on = (gate.state & 0xe) == 0 - torches(1).on = !wires(0).on - } -} - -class RenderNOR extends ICGateRenderer[ComboGateICPart] { - var wires = generateWireModels("NOR", 4) - var torch = new RedstoneTorchModel(8, 9) - - override val coreModels = Seq(new BaseComponentModel("NOR")) ++ wires :+ torch - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(1).disabled = false - wires(2).disabled = false - wires(3).disabled = false - torch.on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x11) != 0 - wires(1).on = (gate.state & 2) != 0 - wires(2).on = (gate.state & 4) != 0 - wires(3).on = (gate.state & 8) != 0 - wires(1).disabled = (gate.shape & 1) != 0 - wires(2).disabled = (gate.shape & 2) != 0 - wires(3).disabled = (gate.shape & 4) != 0 - torch.on = (gate.state & 0xe) == 0 - } -} - -class RenderNOT extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("NOT", 4) - val torch = new RedstoneTorchModel(8, 8) - - override val coreModels = Seq(new BaseComponentModel("NOT")) ++ wires :+ torch - - override def prepareInv() { - wires(0).on = true - wires(1).on = true - wires(2).on = false - wires(3).on = true - wires(0).disabled = false - wires(1).disabled = false - wires(3).disabled = false - torch.on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x11) != 0 - wires(1).on = (gate.state & 0x22) != 0 - wires(2).on = (gate.state & 4) != 0 - wires(3).on = (gate.state & 0x88) != 0 - wires(0).disabled = (gate.shape & 2) != 0 - wires(1).disabled = (gate.shape & 1) != 0 - wires(3).disabled = (gate.shape & 4) != 0 - torch.on = (gate.state & 0xf0) != 0 - } -} - -class RenderAND extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("AND", 4) - val torches = Seq( - new RedstoneTorchModel(4, 8), - new RedstoneTorchModel(12, 8), - new RedstoneTorchModel(8, 8), - new RedstoneTorchModel(8, 2) - ) - - override val coreModels = - Seq(new BaseComponentModel("AND")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(1).disabled = false - wires(2).disabled = false - wires(3).disabled = false - torches(0).on = true - torches(1).on = true - torches(2).on = true - torches(3).on = false - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x11) == 0 - wires(3).on = (gate.state & 2) != 0 - wires(1).on = (gate.state & 4) != 0 - wires(2).on = (gate.state & 8) != 0 - wires(3).disabled = (gate.shape & 1) != 0 - wires(1).disabled = (gate.shape & 2) != 0 - wires(2).disabled = (gate.shape & 4) != 0 - torches(2).on = !wires(1).on && !wires(1).disabled - torches(0).on = !wires(2).on && !wires(2).disabled - torches(1).on = !wires(3).on && !wires(3).disabled - torches(3).on = !wires(0).on - } -} - -class RenderNAND extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("NAND", 4) - val torches = Seq( - new RedstoneTorchModel(4, 8), - new RedstoneTorchModel(12, 8), - new RedstoneTorchModel(8, 8) - ) - - override val coreModels = - Seq(new BaseComponentModel("NAND")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(1).disabled = false - wires(2).disabled = false - wires(3).disabled = false - torches(0).on = true - torches(1).on = true - torches(2).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x11) != 0 - wires(3).on = (gate.state & 2) != 0 - wires(1).on = (gate.state & 4) != 0 - wires(2).on = (gate.state & 8) != 0 - wires(3).disabled = (gate.shape & 1) != 0 - wires(1).disabled = (gate.shape & 2) != 0 - wires(2).disabled = (gate.shape & 4) != 0 - torches(0).on = !wires(2).on && !wires(2).disabled - torches(1).on = !wires(3).on && !wires(3).disabled - torches(2).on = !wires(1).on && !wires(1).disabled - } -} - -class RenderXOR extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("XOR", 4) - val torches = Seq( - new RedstoneTorchModel(4.5, 8), - new RedstoneTorchModel(11.5, 8), - new RedstoneTorchModel(8, 12) - ) - - override val coreModels = - Seq(new BaseComponentModel("XOR")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = false - wires(3).on = false - wires(2).on = false - wires(1).on = true - torches(0).on = false - torches(1).on = false - torches(2).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x11) != 0 - wires(3).on = (gate.state & 2) != 0 - wires(2).on = (gate.state & 8) != 0 - wires(1).on = !wires(3).on && !wires(2).on - torches(0).on = !wires(2).on && !wires(1).on - torches(1).on = !wires(3).on && !wires(1).on - torches(2).on = wires(1).on - } -} - -class RenderXNOR extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("XNOR", 5) - val torches = Seq( - new RedstoneTorchModel(8, 2), - new RedstoneTorchModel(4.5, 8), - new RedstoneTorchModel(11.5, 8), - new RedstoneTorchModel(8, 12) - ) - - override val coreModels = - Seq(new BaseComponentModel("XNOR")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = false - wires(3).on = false - wires(2).on = false - wires(1).on = false - torches(0).on = true - torches(1).on = false - torches(2).on = false - torches(3).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 2) != 0 && (gate.state & 8) == 0 - wires(1).on = (gate.state & 8) != 0 && (gate.state & 2) == 0 - wires(2).on = (gate.state & 8) != 0 - wires(3).on = (gate.state & 2) != 0 - wires(4).on = !wires(3).on && !wires(2).on - torches(0).on = (gate.state & 0x11) != 0 - torches(1).on = !wires(4).on && (gate.state & 8) == 0 - torches(2).on = !wires(4).on && (gate.state & 2) == 0 - torches(3).on = (gate.state & 2) == 0 && (gate.state & 8) == 0 - } -} - -class RenderBuffer extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("BUFFER", 4) - val torches = - Seq(new RedstoneTorchModel(8, 3.5), new RedstoneTorchModel(8, 9)) - - override val coreModels = - Seq(new BaseComponentModel("BUFFER")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(1).disabled = false - wires(3).disabled = false - torches(0).on = false - torches(1).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 4) == 0 - wires(1).on = (gate.state & 0x22) != 0 - wires(2).on = (gate.state & 0x44) != 0 - wires(3).on = (gate.state & 0x88) != 0 - wires(1).disabled = (gate.shape & 1) != 0 - wires(3).disabled = (gate.shape & 2) != 0 - torches(0).on = (gate.state & 4) != 0 - torches(1).on = (gate.state & 4) == 0 - } -} - -class RenderMultiplexer extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("MULTIPLEXER", 6) - val torches = Seq( - new RedstoneTorchModel(8, 2), - new RedstoneTorchModel(9, 10.5), - new RedstoneTorchModel(4.5, 8), - new RedstoneTorchModel(11.5, 8) - ) - - override val coreModels = - Seq(new BaseComponentModel("MULTIPLEXER")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = false - wires(1).on = true - wires(2).on = true - wires(3).on = false - wires(4).on = false - wires(5).on = false - torches(0).on = false - torches(1).on = true - torches(2).on = false - torches(3).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(2).on = (gate.state & 4) == 0 - wires(3).on = (gate.state & 4) != 0 - wires(4).on = (gate.state & 8) != 0 - wires(5).on = (gate.state & 2) != 0 - torches(0).on = (gate.state & 0x10) != 0 - torches(1).on = !wires(3).on - torches(2).on = (gate.state & 8) == 0 && wires(3).on - torches(3).on = (gate.state & 4) == 0 && !wires(5).on - wires(0).on = torches(2).on - wires(1).on = torches(1).on - } -} - -class RenderPulse extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("PULSE", 3) - val torches = Seq( - new RedstoneTorchModel(4, 9.5), - new RedstoneTorchModel(11, 9.5), - new RedstoneTorchModel(8, 3.5) - ) - - override val coreModels = - Seq(new BaseComponentModel("PULSE")) ++ wires ++ torches - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - wires(2).on = false - torches(0).on = true - torches(1).on = false - torches(2).on = false - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 4) == 0 - wires(1).on = (gate.state & 4) != 0 - wires(2).on = (gate.state & 0x14) == 4 - torches(0).on = wires(0).on - torches(1).on = wires(1).on - torches(2).on = (gate.state & 0x10) != 0 - } -} - -class RenderRepeater extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("REPEATER", 2) - val endTorch = new RedstoneTorchModel(8, 2) - val varTorches = Seq( - new RedstoneTorchModel(12.5, 12), - new RedstoneTorchModel(12.5, 11), - new RedstoneTorchModel(12.5, 10), - new RedstoneTorchModel(12.5, 9), - new RedstoneTorchModel(12.5, 8), - new RedstoneTorchModel(12.5, 7), - new RedstoneTorchModel(12.5, 6), - new RedstoneTorchModel(12.5, 5), - new RedstoneTorchModel(12.5, 4) - ) - - var shape = 0 - - override val coreModels = - Seq(new BaseComponentModel("REPEATER")) ++ wires :+ endTorch - - override def switchModels = Seq(varTorches(shape)) - - override def prepareInv() { - wires(0).on = true - wires(1).on = false - endTorch.on = false - shape = 0 - varTorches(0).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(0).on = (gate.state & 0x10) == 0 - wires(1).on = (gate.state & 4) != 0 - endTorch.on = (gate.state & 0x10) != 0 - shape = gate.shape - varTorches(shape).on = (gate.state & 4) == 0 - } -} - -class RenderRandomizer extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("RAND", 7) - val chips = Seq( - new YellowChipModel(8, 5.5), - new YellowChipModel(11.5, 11.5), - new YellowChipModel(4.5, 11.5) - ) - - override val coreModels = - Seq(new BaseComponentModel("RAND")) ++ wires ++ chips - - override def prepareInv() { - wires(0).on = false - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(4).on = false - wires(5).on = false - wires(6).on = false - wires(0).disabled = false - wires(1).disabled = false - wires(3).disabled = false - wires(4).disabled = false - wires(5).disabled = false - wires(6).disabled = false - chips(0).on = false - chips(1).on = false - chips(2).on = false - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - wires(2).on = (gate.state & 4) != 0 - wires(0).on = (gate.state & 0x11) != 0 - wires(1).on = (gate.state & 0x22) != 0 - wires(3).on = (gate.state & 0x88) != 0 - wires(4).on = wires(2).on - wires(5).on = wires(2).on - wires(6).on = wires(2).on - wires(1).disabled = (gate.shape & 1) != 0 - wires(0).disabled = (gate.shape & 2) != 0 - wires(3).disabled = (gate.shape & 4) != 0 - wires(5).disabled = wires(1).disabled - wires(4).disabled = wires(0).disabled - wires(6).disabled = wires(3).disabled - chips(0).on = (gate.state & 0x10) != 0 - chips(1).on = (gate.state & 0x20) != 0 - chips(2).on = (gate.state & 0x80) != 0 - } -} - -class RenderSRLatch extends ICGateRenderer[SequentialGateICPart] { - val wires1 = generateWireModels("RSLATCH", 2) - val wires2 = generateWireModels("RSLATCH2", 4) - val torches1 = - Seq(new RedstoneTorchModel(8, 3), new RedstoneTorchModel(8, 13)) - val torches2 = - Seq(new RedstoneTorchModel(9.5, 3), new RedstoneTorchModel(6.5, 13)) - val base1 = new BaseComponentModel("RSLATCH") - val base2 = new BaseComponentModel("RSLATCH2") - - val m1 = Seq(base1) ++ wires1 ++ torches1 - val m2 = Seq(base2) ++ wires2 ++ torches2 - - var shape = 0 - - override val coreModels = Seq() - override def switchModels = if (shape == 0) m1 else m2 - - override def prepareInv() { - reflect = false - shape = 0 - wires1(0).on = false - wires1(1).on = true - torches1(0).on = false - torches1(1).on = true - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - reflect = (gate.shape & 1) != 0 - shape = gate.shape >> 1 - var state = gate.state - if (reflect) state = flipMaskZ(state >> 4) << 4 | flipMaskZ(state) - if (shape == 0) { - wires1(0).on = (state & 0x88) != 0 - wires1(1).on = (state & 0x22) != 0 - torches1(0).on = (state & 0x10) != 0 - torches1(1).on = (state & 0x40) != 0 - } else { - wires2(1).on = (state & 2) != 0 - wires2(3).on = (state & 8) != 0 - torches2(0).on = (state & 0x10) != 0 - torches2(1).on = (state & 0x40) != 0 - wires2(0).on = torches2(1).on - wires2(2).on = torches2(0).on - } - } -} - -class RenderToggleLatch extends ICGateRenderer[SequentialGateICPart] { - val wires = generateWireModels("TOGLATCH", 2) - val torches = Seq(new RedstoneTorchModel(4, 4), new RedstoneTorchModel(4, 12)) - val lever = new LeverModel(11, 8) - - override val coreModels = - Seq(new BaseComponentModel("TOGLATCH")) ++ wires ++ torches :+ lever - - override def prepareInv() { - wires(0).on = false - wires(1).on = false - torches(0).on = true - torches(1).on = false - lever.on = true - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - wires(0).on = (gate.state & 8) != 0 - wires(1).on = (gate.state & 2) != 0 - torches(0).on = (gate.state & 0x10) != 0 - torches(1).on = (gate.state & 0x40) != 0 - lever.on = (gate.state & 0x10) != 0 - } -} - -class RenderTransparentLatch extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("TRANSLATCH", 5) - val torches = Seq( - new RedstoneTorchModel(4, 12.5), - new RedstoneTorchModel(4, 8), - new RedstoneTorchModel(8, 8), - new RedstoneTorchModel(8, 2), - new RedstoneTorchModel(14, 8) - ) - - override val coreModels = - Seq(new BaseComponentModel("TRANSLATCH")) ++ wires ++ torches - - override def prepareInv() { - reflect = false - wires(0).on = true - wires(1).on = false - wires(2).on = true - wires(3).on = false - wires(4).on = false - torches(0).on = true - torches(1).on = false - torches(2).on = true - torches(3).on = false - torches(4).on = false - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - reflect = gate.shape == 1 - val on = (gate.state & 0x10) != 0 - wires(0).on = !on - wires(1).on = (gate.state & 4) != 0 - wires(2).on = (gate.state & 4) == 0 - wires(3).on = on - wires(4).on = (gate.state & 0xa) != 0 - torches(0).on = wires(2).on - torches(1).on = !wires(2).on && !wires(4).on - torches(2).on = !wires(1).on && !wires(3).on - torches(3).on = on - torches(4).on = on - } -} - -class RenderTimer extends ICGateRenderer[SequentialGateICPart] { - val wires = generateWireModels("TIME", 3) - val torches = Seq(new RedstoneTorchModel(8, 3), new RedstoneTorchModel(8, 8)) - val pointer = new PointerModel(8, 8) - - override val coreModels = - Seq(new BaseComponentModel("TIME")) ++ wires ++ Seq(pointer) ++ torches - - override def prepareInv() { - wires(0).on = false - wires(1).on = false - wires(2).on = false - torches(0).on = false - pointer.angle = 0 - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - torches(0).on = (gate.state & 0x10) != 0 - wires(0).on = (gate.state & 0x88) != 0 - wires(1).on = (gate.state & 0x22) != 0 - wires(2).on = (gate.state & 4) != 0 - val ang = - gate.getLogic[TTimerGateLogic].interpPointer(frame) * MathHelper.pi * 2 - pointer.angle = ang - } -} - -class RenderSequencer extends ICGateRenderer[SequentialGateICPart] { - val torches = Seq( - new RedstoneTorchModel(8, 8), - new RedstoneTorchModel(8, 3), - new RedstoneTorchModel(13, 8), - new RedstoneTorchModel(8, 13), - new RedstoneTorchModel(3, 8) - ) - val pointer = new PointerModel(8, 8) - - torches(0).on = true - - override val coreModels = - Seq(new BaseComponentModel("SEQUENCER"), pointer) ++ torches - - override def prepareInv() { - torches(1).on = true - torches(2).on = false - torches(3).on = false - torches(4).on = false - - pointer.angle = 0 - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - torches(1).on = (gate.state & 0x10) != 0 - torches(2).on = (gate.state & 0x20) != 0 - torches(3).on = (gate.state & 0x40) != 0 - torches(4).on = (gate.state & 0x80) != 0 - - val max = gate.getLogic[Sequencer].pointer_max * 4 - pointer.angle = (gate - .getLogic[Sequencer] - .getWorldTime % max + frame) / max * 2 * MathHelper.pi - if (gate.shape == 1) pointer.angle *= -1 - } -} - -class RenderCounter extends ICGateRenderer[SequentialGateICPart] { - val wires = generateWireModels("COUNT", 2) - val torches = Seq( - new RedstoneTorchModel(11, 8), - new RedstoneTorchModel(8, 3), - new RedstoneTorchModel(8, 13) - ) - val pointer = new PointerModel(11, 8, 1.2d) - - torches(0).on = true - - override val coreModels = - Seq(new BaseComponentModel("COUNT")) ++ wires ++ Seq(pointer) ++ torches - - override def prepareInv() { - reflect = false - wires(0).on = false - wires(1).on = false - torches(1).on = false - torches(2).on = true - pointer.angle = 220 * MathHelper.torad - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - reflect = gate.shape == 1 - wires(0).on = (gate.state & 8) != 0 - wires(1).on = (gate.state & 2) != 0 - torches(1).on = (gate.state & 0x10) != 0 - torches(2).on = (gate.state & 0x40) != 0 - - val max = gate.getLogic[Counter].max - val value = gate.getLogic[Counter].value - pointer.angle = - (value / max.toDouble * (340 - 220) + 210) * MathHelper.torad - if (gate.shape == 1) reflect = true - } -} - -class RenderStateCell extends ICGateRenderer[SequentialGateICPart] { - val wires = generateWireModels("STATECELL", 5) - val torches = - Seq(new RedstoneTorchModel(10, 3.5), new RedstoneTorchModel(13, 8)) - val chip = new RedChipModel(6.5, 10) - val pointer = new PointerModel(13, 8) - - override val coreModels = Seq( - new BaseComponentModel("STATECELL") - ) ++ wires ++ Seq(chip, pointer) ++ torches - - override def prepareInv() { - reflect = false - wires(0).on = false - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(4).on = false - torches(0).on = false - torches(1).on = true - chip.on = false - pointer.angle = -MathHelper.pi / 2 - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - reflect = gate.shape == 1 - val logic = gate.getLogic[StateCell] - var state = gate.state - if (reflect) state = flipMaskZ(state >> 4) << 4 | flipMaskZ(state) - - wires(0).on = (state & 0x10) != 0 - wires(1).on = (state & 4) != 0 - wires(2).on = logic.state2 == 0 || (state & 4) != 0 - wires(3).on = (state & 0x88) != 0 - wires(4).on = (state & 2) != 0 - torches(0).on = (state & 0x10) != 0 - torches(1).on = logic.pointer_start >= 0 - chip.on = logic.state2 != 0 - - reflect = gate.shape == 1 - pointer.angle = - gate.getLogic[StateCell].interpPointer(frame) - MathHelper.pi / 2 - } -} - -class RenderSynchronizer extends ICGateRenderer[SequentialGateICPart] { - val wires = generateWireModels("SYNC", 6) - val torch = new RedstoneTorchModel(8, 3) - val chips = Seq(new RedChipModel(4.5, 9), new RedChipModel(11.5, 9)) - - override val coreModels = - Seq(new BaseComponentModel("SYNC")) ++ wires ++ chips ++ Seq(torch) - - override def prepareInv() { - wires(0).on = true - wires(1).on = true - wires(2).on = false - wires(3).on = false - wires(4).on = false - wires(5).on = false - chips(0).on = false - chips(1).on = false - torch.on = false - } - - override def prepareDynamic(gate: SequentialGateICPart, frame: Float) { - val logic = gate.getLogic[Synchronizer] - wires(0).on = !logic.left - wires(1).on = !logic.right - wires(2).on = (gate.state & 4) != 0 - wires(3).on = logic.left && logic.right - wires(4).on = (gate.state & 8) != 0 - wires(5).on = (gate.state & 2) != 0 - chips(0).on = logic.left - chips(1).on = logic.right - torch.on = (gate.state & 0x10) != 0 - } -} - -class RenderDecRandomizer extends ICGateRenderer[ComboGateICPart] { - val wires = generateWireModels("DECRAND", 6) - val chips = Seq( - new YellowChipModel(5, 13), - new YellowChipModel(11, 13), - new RedChipModel(5.5, 8) - ) - val torches = Seq( - new RedstoneTorchModel(8, 2.5), - new RedstoneTorchModel(14, 8), - new RedstoneTorchModel(2, 8), - new RedstoneTorchModel(9, 8) - ) - - override val coreModels = - Seq(new BaseComponentModel("DECRAND")) ++ wires ++ chips ++ torches - - override def prepareInv() { - wires(0).on = false - wires(1).on = false - wires(2).on = false - wires(3).on = false - wires(4).on = true - wires(5).on = true - wires(0).disabled = false - wires(3).disabled = false - torches(0).on = true - torches(1).on = false - torches(2).on = false - torches(3).on = false - chips(0).on = false - chips(1).on = true - chips(2).on = true - } - - override def prepareDynamic(gate: ComboGateICPart, frame: Float) { - val state = gate.state - wires(0).on = (state >> 4) == 2 - wires(1).on = (state >> 4) == 8 - wires(2).on = (state & 4) != 0 - wires(3).on = (state & 4) != 0 - wires(4).on = (state >> 4) == 1 || (state >> 4) == 2 - wires(5).on = (state >> 4) == 1 - wires(0).disabled = gate.shape != 0 - wires(3).disabled = gate.shape != 0 - torches(0).on = (state >> 4) == 1 - torches(1).on = (state >> 4) == 2 - torches(2).on = (state >> 4) == 8 - torches(3).on = !wires(4).on - chips(0).on = (state >> 4) == 2 - chips(1).on = (state >> 4) == 1 || (state >> 4) == 2 - chips(2).on = true - } -} - -class RenderNullCell extends ICGateRenderer[ArrayGateICPart] { - val top = new CellTopWireModel - val bottom = new NullCellBottomWireModel - - override val coreModels = - Seq(new BaseComponentModel("NULLCELL"), bottom, new CellStandModel, top) - - override def prepareInv() { - bottom.signal = 0 - top.signal = 0 - } - - override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { - bottom.signal = gate.getLogic[NullCell].signal1 - top.signal = gate.getLogic[NullCell].signal2 - } -} - -class RenderInvertCell extends ICGateRenderer[ArrayGateICPart] { - val wires = generateWireModels("INVCELL", 1) - val torch = new RedstoneTorchModel(8, 8) - val top = new CellTopWireModel - val bottom = new InvertCellBottomWireModel - - override val coreModels = Seq( - new BaseComponentModel("INVCELL") - ) ++ wires ++ Seq(bottom, torch, new CellStandModel, top) - - override def prepareInv() { - bottom.signal = 0 - top.signal = 255.toByte - wires(0).on = false - torch.on = true - } - - override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { - val logic = gate.getLogic[InvertCell] - bottom.signal = logic.signal1 - top.signal = logic.signal2 - wires(0).on = logic.signal1 != 0 - torch.on = logic.signal1 == 0 - } -} - -class RenderBufferCell extends ICGateRenderer[ArrayGateICPart] { - val wires = generateWireModels("BUFFCELL", 2) - val torches = - Seq(new RedstoneTorchModel(11, 13), new RedstoneTorchModel(8, 8)) - val top = new CellTopWireModel - val bottom = new InvertCellBottomWireModel - - override val coreModels = - Seq(new BaseComponentModel("BUFFCELL")) ++ wires ++ Seq( - bottom - ) ++ torches ++ Seq(new CellStandModel, top) - - override def prepareInv() { - bottom.signal = 0 - top.signal = 0 - wires(0).on = false - wires(1).on = true - torches(0).on = true - torches(1).on = false - } - - override def prepareDynamic(gate: ArrayGateICPart, frame: Float) { - val logic = gate.getLogic[BufferCell] - bottom.signal = logic.signal1 - top.signal = logic.signal2 - torches(0).on = logic.signal1 == 0 - torches(1).on = logic.signal1 != 0 - wires(0).on = logic.signal1 != 0 - wires(1).on = logic.signal1 == 0 - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/GuiICWorkbench.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/GuiICWorkbench.scala new file mode 100644 index 000000000..05d0d872c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/GuiICWorkbench.scala @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui + +import codechicken.lib.data.MCDataInput +import codechicken.lib.gui.GuiDraw +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.color.Colors +import mrtjp.core.gui._ +import mrtjp.core.vec.{Point, Size, Vec2} +import mrtjp.core.world.WorldLib +import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.gui.nodes._ +import mrtjp.projectred.fabrication.{FabricationProxy, TileICWorkbench} +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Gui +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.util.StatCollector +import org.lwjgl.input.Keyboard +import org.lwjgl.opengl.GL11 + +import java.math.MathContext + +class GuiICWorkbench(val tile: TileICWorkbench) extends NodeGui(330, 256) { + var pref: PrefboardNode = null + var configurationNode: TNode = null + + def translate(unlocalizedName: String): String = { + StatCollector.translateToLocal(unlocalizedName) + } + + override def onAddedToParent_Impl() { + val clip = new ClipNode + clip.position = Point(7, 18) + clip.size = Size(252, 197) + addChild(clip) + + val opPreview = new OpPreviewNode() + opPreview.position = Point(269, 18) + addChild(opPreview) + + val toolbar = new ToolbarNode( + tile.circuit, + op => { + opPreview.updatePreview(op) + pref.pickOp(op) + } + ) + toolbar.buildToolbar() + + pref = new PrefboardNode( + tile.circuit, + tile.hasBP, + node => { + if (configurationNode != null) { + configurationNode.removeFromParent() + configurationNode = null + } + configurationNode = node + if (configurationNode != null) { + configurationNode.position = Point(260, 17) + addChild(configurationNode) + } + }, + op => { + opPreview.updatePreview(op) + toolbar.selectOp(op) + } + ) + pref.zPosition = -0.01 // Must be below clip nodes + clip.addChild(pref) + if (tile.circuit.parts.nonEmpty) { + pref.scaleGuiToCircuit() + } else { + pref.offset = Vec2(0, 0) + pref.scale = 1.0d + } + + addChild(toolbar) + toolbar.position = + Point(size.width / 2 - toolbar.calculateAccumulatedFrame.width / 2, 235) + + val textboxICName = new SimpleTextboxNode() + textboxICName.position = Point(80, 4) + textboxICName.size = Size(115, 11) + textboxICName.text = tile.circuit.name + textboxICName.textChangedDelegate = { () => + tile.sendICNameToServer(textboxICName.text) + } + addChild(textboxICName) + + val dminus = new MCButtonNode + dminus.position = Point(269, 200) + dminus.size = Size(10, 10) + dminus.text = "-" + dminus.clickDelegate = { () => pref.decDetail() } + addChild(dminus) + + val dplus = new MCButtonNode + dplus.position = Point(309, 200) + dplus.size = Size(10, 10) + dplus.text = "+" + dplus.clickDelegate = { () => pref.incDetail() } + addChild(dplus) + + val sminus = new MCButtonNode + sminus.position = Point(268, 4) + sminus.size = Size(10, 10) + sminus.text = "-" + sminus.clickDelegate = { () => pref.decScale() } + addChild(sminus) + + val splus = new MCButtonNode + splus.position = Point(308, 4) + splus.size = Size(10, 10) + splus.text = "+" + splus.clickDelegate = { () => pref.incScale() } + addChild(splus) + + val resetView = new MCButtonNode + resetView.position = Point(200, 3) + resetView.size = Size(60, 12) + resetView.text = translate("gui.projectred.fabrication.reset_view") + resetView.clickDelegate = { () => + if (tile.hasBP && tile.circuit.parts.nonEmpty) { + pref.scaleGuiToCircuit() + } + } + addChild(resetView) + + val info = new InfoNode + info.position = Point(241, 18) + info.zPosition = 1 + addChild(info) + } + + override def keyPressed_Impl( + c: Char, + keycode: Int, + consumed: Boolean + ): Boolean = { + import Keyboard._ + if (!consumed) keycode match { + case KEY_W => + pref.offset += Vec2(0, -2 / pref.scale) + true + case KEY_A => + pref.offset += Vec2(-2 / pref.scale, 0) + true + case KEY_S => + pref.offset += Vec2(0, 2 / pref.scale) + true + case KEY_D => + pref.offset += Vec2(2 / pref.scale, 0) + true + case _ => + false + } + else false + } + + override def drawBack_Impl(mouse: Point, frame: Float) { + GL11.glColor4f(1, 1, 1, 1) + PRResources.guiPrototyper.bind() + Gui.func_146110_a(0, 0, 0, 0, size.width, size.height, 512, 512) + + GuiDraw.drawString( + translate("tile.projectred.integration.icblock|0.name"), + 8, + 6, + Colors.GREY.argb, + false + ) + + GuiDraw.drawStringC( + translate("gui.projectred.fabrication.detail"), + 273, + 190, + 42, + 14, + Colors.GREY.argb, + false + ) + GuiDraw.drawStringC( + pref.detailLevel.toString, + 279, + 200, + 30, + 10, + Colors.GREY.argb, + false + ) + + GuiDraw.drawStringC( + BigDecimal(pref.scale, new MathContext(2)).toString(), + 278, + 4, + 30, + 10, + Colors.GREY.argb, + false + ) + } +} + +object GuiICWorkbench extends TGuiBuilder { + override def getID = FabricationProxy.icWorkbenchGui + + @SideOnly(Side.CLIENT) + override def buildGui(player: EntityPlayer, data: MCDataInput) = { + WorldLib.getTileEntity( + Minecraft.getMinecraft.theWorld, + data.readCoord() + ) match { + case t: TileICWorkbench => + t.circuit.readDesc(data) + new GuiICWorkbench(t) + case _ => null + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/PrefboardRenderer.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/PrefboardRenderer.scala new file mode 100644 index 000000000..7615aa3c0 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/PrefboardRenderer.scala @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui + +import codechicken.lib.math.MathHelper +import codechicken.lib.render.CCRenderState +import codechicken.lib.render.uv.UVScale +import codechicken.lib.vec.{Rotation, Scale, TransformationList, Translation} +import mrtjp.core.vec.{Size, Vec2} +import mrtjp.projectred.fabrication.ICComponentStore.faceModels +import mrtjp.projectred.fabrication.RenderCircuit +import net.minecraft.client.Minecraft +import net.minecraft.util.ResourceLocation + +object PrefboardRenderer { + + def renderOrtho(size: Size, scale: Double, gridTranslation: Vec2) { + val offset = + gridTranslation - Vec2(gridTranslation.dx.toInt, gridTranslation.dy.toInt) + + val uv = new UVScale( + size.width / (RenderCircuit.BASE_SCALE * scale) + 2, + size.height / (RenderCircuit.BASE_SCALE * scale) + 2 + ) + val boardModel = faceModels.map(_.copy().apply(uv)) + + val state = CCRenderState.instance + state.resetInstance() + state.pullLightmapInstance() + state.setDynamicInstance() + + val t = new TransformationList( + new Scale( + size.width + 2 * RenderCircuit.BASE_SCALE * scale, + 1, + -(size.height + 2 * RenderCircuit.BASE_SCALE * scale) + ), + new Translation( + -(offset.dx + 1) * RenderCircuit.BASE_SCALE * scale, + 0, + (offset.dy + 1) * RenderCircuit.BASE_SCALE * scale + ), + new Rotation(0.5 * MathHelper.pi, 1, 0, 0) + ) + + val r = new ResourceLocation( + "projectred", + "textures/blocks/fabrication/prefboard.png" + ) + Minecraft.getMinecraft.getTextureManager.bindTexture(r) + + state.startDrawingInstance() + boardModel(1).render(t) + state.drawInstance() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ConfigurationNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ConfigurationNode.scala new file mode 100644 index 000000000..88751d98a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ConfigurationNode.scala @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.vec.Translation +import mrtjp.core.gui.TNode +import mrtjp.core.vec.Point +import mrtjp.projectred.fabrication.ICComponentStore +import mrtjp.projectred.fabrication.circuitparts.{ + GateICPart, + ICGateRenderer, + TClientNetCircuitPart +} +import net.minecraft.util.StatCollector + +trait TConfigurable extends TClientNetCircuitPart { + def createConfigurationNode: ConfigurationNode +} + +abstract class ConfigurationNode(gate: GateICPart) extends TNode { + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + val pos = position.add(8, 0) + ICGateRenderer.renderDynamic( + gate, + ICComponentStore.orthoGridT(50, 50) `with` + new Translation( + pos.x, + pos.y, + 0 + ), + true, + rframe + ) + } + + protected def translate(unlocalizedName: String): String = { + StatCollector.translateToLocal(unlocalizedName) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ICToolsetNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ICToolsetNode.scala new file mode 100644 index 000000000..d24ba2be7 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ICToolsetNode.scala @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.gui.{ButtonNode, IconButtonNode, TNode} +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.operations.CircuitOp +import net.minecraft.util.StatCollector + +import scala.collection.immutable.ListMap +import scala.collection.JavaConversions._ + +class ICToolsetNode(title: String, onSelect: CircuitOp => Unit) extends TNode { + var opSet = Seq.empty[CircuitOp] + var buttonSize = Size(16, 16) + var buttonGap = 1 + + private var focused = false + private var buttonOpMap = ListMap.empty[ButtonNode, CircuitOp] + + private var selectedButton: ButtonNode = null + private var groupButton: ButtonNode = null + private var groupButtonOperation: CircuitOp = null + + def setup() { + for (op <- opSet) { + val b = createButtonFor(op) + b.size = buttonSize + b.hidden = true + addChild(b) + buttonOpMap += b -> op + } + + val delta = opSet.size * (buttonSize.width + buttonGap) + val firstPoint = + Point(-delta / 2 + buttonSize.width / 2, -buttonSize.height - buttonGap) + for ((b, i) <- buttonOpMap.keys.zipWithIndex) + b.position = firstPoint.add(i * (buttonSize.width + buttonGap), 0) + + selectedButton = buttonOpMap.head._1 + groupButtonOperation = buttonOpMap.head._2 + + groupButton = new IconButtonNode { + override def drawButton(mouseover: Boolean) = { + groupButtonOperation.renderImageStatic( + position.x + 2, + position.y + 2, + size.width - 4, + size.height - 4 + ) + } + } + groupButton.size = buttonSize + groupButton.tooltipBuilder = { + _ += StatCollector.translateToLocal(buttonOpMap(selectedButton).getOpName) + } + groupButton.clickDelegate = { () => selectedButton.clickDelegate() } + addChild(groupButton) + } + + private def createButtonFor(op: CircuitOp) = { + val b = new IconButtonNode { + override def drawButton(mouseover: Boolean) { + op.renderImageStatic( + position.x + 2, + position.y + 2, + size.width - 4, + size.height - 4 + ) + } + } + b.tooltipBuilder = { + _ += StatCollector.translateToLocal(op.getOpName) + } + b.clickDelegate = { () => + { + onSelect(op) + buttonClicked(op, b) + } + } + b + } + + private def buttonClicked(op: CircuitOp, button: ButtonNode) { + setFocused() + // Hide all other toolsets + parent.children + .collect { + case t: ICToolsetNode if t != this => t + } + .foreach(toolsetNode => toolsetNode.setUnfocused()) + selectedButton.mouseoverLock = false + button.mouseoverLock = true + selectedButton = button + } + + def select(op: CircuitOp): Unit = { + for ((button, operation) <- buttonOpMap) { + if (op.id == operation.id) { + buttonClicked(op, button) + return + } + } + } + + def setFocused() { + if (!focused) { + if (buttonOpMap.size > 1) + for (b <- buttonOpMap.keys) + b.hidden = false + } + focused = true + groupButton.mouseoverLock = true + } + + def setUnfocused() { + if (focused) { + if (buttonOpMap.size > 1) + for (b <- buttonOpMap.keys) + b.hidden = true + } + focused = false + groupButton.mouseoverLock = false + } + + override def drawFront_Impl(mouse: Point, rframe: Float) { + if ( + title.nonEmpty && groupButton.rayTest(parent.convertPointTo(mouse, this)) + ) { + import net.minecraft.util.EnumChatFormatting._ + translateToScreen() + val Point(mx, my) = parent.convertPointToScreen(mouse) + GuiDraw.drawMultilineTip( + mx + 12, + my - 32, + Seq(AQUA.toString + ITALIC.toString + title) + ) + translateFromScreen() + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/InfoNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/InfoNode.scala new file mode 100644 index 000000000..c9829836e --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/InfoNode.scala @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.gui._ +import mrtjp.core.vec.{Point, Rect, Size} +import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.gui.GuiICWorkbench +import net.minecraft.client.gui.Gui + +class InfoNode extends TNode { + val size = Size(18, 18) + override def frame = Rect(position, size) + + private def getTile = parent.asInstanceOf[GuiICWorkbench].tile + + override def drawBack_Impl(mouse: Point, rframe: Float) { + PRResources.guiPrototyper.bind() + if (!getTile.hasBP) + Gui.func_146110_a( + position.x, + position.y, + 330, + 0, + size.width, + size.height, + 512, + 512 + ) + } + + override def drawFront_Impl(mouse: Point, rframe: Float) { + val text = + if (!getTile.hasBP) + "Lay down a blueprint on the workbench." + else "" + if (text.nonEmpty && rayTest(mouse)) { + translateToScreen() + val Point(mx, my) = parent.convertPointToScreen(mouse) + import scala.collection.JavaConversions._ + GuiDraw.drawMultilineTip(mx + 12, my - 12, Seq(text)) + translateFromScreen() + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/OpPreviewNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/OpPreviewNode.scala new file mode 100644 index 000000000..6cecc4ba2 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/OpPreviewNode.scala @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import mrtjp.core.gui.TNode +import mrtjp.core.vec.Point +import mrtjp.projectred.fabrication.operations.CircuitOp + +class OpPreviewNode extends TNode { + + var currentOp: CircuitOp = null + + def updatePreview(op: CircuitOp): Unit = { + currentOp = op + } + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + if (currentOp != null) { + currentOp.renderImage( + position.x, + position.y, + 50, + 50 + ) + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/PrefboardNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/PrefboardNode.scala new file mode 100644 index 000000000..854987a50 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/PrefboardNode.scala @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.gui.{ClipNode, TNode} +import mrtjp.core.vec.{Point, Rect, Vec2} +import mrtjp.projectred.fabrication.circuitparts.ICGateDefinition +import mrtjp.projectred.fabrication.circuitparts.io.IOICGateLogic +import mrtjp.projectred.fabrication.circuitparts.latches.{ + SRLatch, + TransparentLatch +} +import mrtjp.projectred.fabrication.circuitparts.misc.{ + Counter, + DecRandomizer, + Randomizer +} +import mrtjp.projectred.fabrication.circuitparts.primitives._ +import mrtjp.projectred.fabrication.circuitparts.timing.{ + Repeater, + Sequencer, + StateCell +} +import mrtjp.projectred.fabrication.operations._ +import mrtjp.projectred.fabrication.{IntegratedCircuit, RenderCircuit} +import net.minecraft.util.EnumChatFormatting +import org.lwjgl.input.{Keyboard, Mouse} + +import scala.collection.JavaConversions._ +import scala.collection.convert.WrapAsJava + +class PrefboardNode( + circuit: IntegratedCircuit, + hasBlueprint: Boolean, + setConfigNode: TNode => Unit, + onPick: CircuitOp => Unit +) extends TNode { + private var currentOp: CircuitOp = null + + /** 0 - off 1 - name only 2 - minor details 3 - all details + */ + var detailLevel = 1 + var scale = 1.0 + + var offset: Vec2 = Vec2(0, 0) + + override def frame = Rect( + position, + parent.frame.size + ) + + private var leftMouseDown = false + private var rightMouseDown = false + private var mouseStart = Point(0, 0) + + /** Converts coordinates in the gui to coordinates in the circuit (with + * rounding) + */ + private def toGridPoint(p: Vec2): Point = { + val circuitCoord = p / (RenderCircuit.BASE_SCALE * scale) + offset + Point( + math.floor(circuitCoord.dx).round.toInt, + math.floor(circuitCoord.dy).round.toInt + ) + } + + private def toGridPoint(p: Point): Point = { + val circuitCoord = p.vectorize / (RenderCircuit.BASE_SCALE * scale) + offset + Point( + math.floor(circuitCoord.dx).round.toInt, + math.floor(circuitCoord.dy).round.toInt + ) + } + + override def update_Impl() { + if (mcInst.theWorld.getTotalWorldTime % 20 == 0) + circuit.refreshErrors() + } + + override def drawBack_Impl(mouse: Point, rframe: Float) { + if (hasBlueprint) { + val f = frame + RenderCircuit.renderOrtho( + circuit, + parent.frame.size, + scale, + offset + ) + + if (currentOp != null) { + if (rayTest(mouse) && !leftMouseDown) { + // Render: Erase always, other stuff only if there are no already placed parts under the cursor + currentOp match { + case _: OpGate | _: OpWire | _: OpSimplePlacement => + if (circuit.getPart(toGridPoint(mouse.vectorize)) == null) + currentOp.renderHover( + toGridPoint(mouse).vectorize, + scale, + offset + ) + case _: OpAreaBase => + currentOp.renderHover(toGridPoint(mouse).vectorize, scale, offset) + } + } else if (leftMouseDown) { + currentOp.renderDrag( + mouseStart.vectorize, + toGridPoint(mouse).vectorize, + CircuitOp.partsBetweenPoints( + mouseStart.vectorize, + toGridPoint(mouse).vectorize, + circuit + ), + scale, + offset + ) + } + } + RenderCircuit.renderErrors(circuit, scale, offset) + } + } + + override def drawFront_Impl(mouse: Point, rframe: Float) { + if (!leftMouseDown && rayTest(mouse)) { + val point = toGridPoint(mouse.vectorize) + val part = circuit.getPart(point) + if (part != null) { + val data = part.getRolloverData(detailLevel) + if (data.nonEmpty) { + ClipNode.tempDisableScissoring() + translateToScreen() + val Point(mx, my) = parent.convertPointToScreen(mouse) + GuiDraw.drawMultilineTip( + mx + 12, + my - 12, + WrapAsJava.seqAsJavaList(data) + ) + if (circuit.errors.contains(point)) + GuiDraw.drawMultilineTip( + mx + 12, + my - 32, + Seq(EnumChatFormatting.RED.toString + circuit.errors(point)._1) + ) + translateFromScreen() + ClipNode.tempEnableScissoring() + } + } + } + } + + private var mousePosition = Point(0, 0) + override def mouseDragged_Impl( + p: Point, + button: Int, + time: Long, + consumed: Boolean + ): Boolean = { + if (!consumed && rayTest(p) && button == 0 && currentOp == null) { + if (time > 20) { + offset = + offset - (p - mousePosition).vectorize / (RenderCircuit.BASE_SCALE * scale) + } + mousePosition = p + true + } else { + mousePosition = p + false + } + } + + override def mouseClicked_Impl( + p: Point, + button: Int, + consumed: Boolean + ): Boolean = { + if (!consumed && rayTest(p)) button match { + case 0 => + leftMouseDown = true + mouseStart = toGridPoint(p.vectorize) + return true + case 1 => + rightMouseDown = true + val gridP = toGridPoint(p.vectorize) + circuit.getPart(gridP) match { + case gp: TConfigurable => + setConfigNode(gp.createConfigurationNode) + case _ => + } + return true + case _ if button == mcInst.gameSettings.keyBindPickBlock.getKeyCode => + doPickOp() + return true + case _ => + } + false + } + + override def mouseReleased_Impl(p: Point, button: Int, consumed: Boolean) = { + if (leftMouseDown) { + leftMouseDown = false + val mouseEnd = toGridPoint(p.vectorize) + val opUsed = currentOp != null && circuit.sendOpUse( + currentOp, + mouseStart, + mouseEnd + ) + if ( + currentOp == CircuitOpDefs.Cut.op || currentOp == CircuitOpDefs.Copy.op + ) { + pickOp(CircuitOpDefs.Paste.op) + onPick(CircuitOpDefs.Paste.op) + } + if (!opUsed && mouseStart == mouseEnd) { + val part = circuit.getPart(mouseEnd) + if (part != null) part.onClicked() + } + } + if (rightMouseDown) { + rightMouseDown = false + val mouseEnd = toGridPoint(p.vectorize) + if (mouseEnd == mouseStart) { + val part = circuit.getPart(mouseEnd) + if (part != null) part.onActivated() + } + } + false + } + + override def mouseScrolled_Impl(p: Point, dir: Int, consumed: Boolean) = { + if (!consumed && rayTest(p)) { + if (dir > 0) rescaleAt(p, math.min(scale * 1.25, 3.0)) + else if (dir < 0) rescaleAt(p, math.max(scale * 0.8, 0.5)) + true + } else false + } + + override def keyPressed_Impl(c: Char, keycode: Int, consumed: Boolean) = { + import Keyboard._ + if (!consumed) keycode match { + case KEY_ESCAPE if leftMouseDown => + leftMouseDown = false + true + case KEY_ESCAPE if currentOp != null => + currentOp = null + onPick(null) + true + case KEY_Q => + doPickOp() + true + case KEY_R if currentOp != null => + doRotate() + true + case KEY_C if currentOp != null => + doConfigure() + true + case KEY_C if Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) => + pickOp(CircuitOpDefs.Copy.op) + onPick(CircuitOpDefs.Copy.op) + true + case KEY_V if Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) => + pickOp(CircuitOpDefs.Paste.op) + onPick(CircuitOpDefs.Paste.op) + true + case KEY_X if Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) => + pickOp(CircuitOpDefs.Cut.op) + onPick(CircuitOpDefs.Cut.op) + true + case _ => false + } + else false + } + + def doRotate(): Unit = { + currentOp match { + case op: OpGate => + op.rotation += 1 + if (op.rotation == 4) op.rotation = 0 + case op: OpAreaBase => + op.rotateClipboard() + case _ => + } + } + + def doConfigure(): Unit = { + currentOp match { + case op: OpGate => + op.getID match { + case ICGateDefinition.OR.ordinal => + op.configuration = OR.cycleShape(op.configuration) + case ICGateDefinition.NOR.ordinal => + op.configuration = NOR.cycleShape(op.configuration) + case ICGateDefinition.NOT.ordinal => + op.configuration = NOT.cycleShape(op.configuration) + case ICGateDefinition.AND.ordinal => + op.configuration = AND.cycleShape(op.configuration) + case ICGateDefinition.NAND.ordinal => + op.configuration = NAND.cycleShape(op.configuration) + case ICGateDefinition.XOR.ordinal => + op.configuration = XOR.cycleShape(op.configuration) + case ICGateDefinition.XNOR.ordinal => + op.configuration = XNOR.cycleShape(op.configuration) + case ICGateDefinition.Buffer.ordinal => + op.configuration = Buffer.cycleShape(op.configuration) + case ICGateDefinition.Multiplexer.ordinal => + op.configuration = Multiplexer.cycleShape(op.configuration) + case ICGateDefinition.Pulse.ordinal => + op.configuration = Pulse.cycleShape(op.configuration) + case ICGateDefinition.Repeater.ordinal => + op.configuration = Repeater.cycleShape(op.configuration) + case ICGateDefinition.Randomizer.ordinal => + op.configuration = Randomizer.cycleShape(op.configuration) + case ICGateDefinition.TransparentLatch.ordinal => + op.configuration = TransparentLatch.cycleShape(op.configuration) + case ICGateDefinition.DecRandomizer.ordinal => + op.configuration = DecRandomizer.cycleShape(op.configuration) + case ICGateDefinition.IOAnalog.ordinal | + ICGateDefinition.IOSimple.ordinal | + ICGateDefinition.IOBundled.ordinal => + op.configuration = IOICGateLogic.cycleShape(op.configuration) + case ICGateDefinition.Sequencer.ordinal => + op.configuration = Sequencer.cycleShape(op.configuration) + case ICGateDefinition.StateCell.ordinal => + op.configuration = StateCell.cycleShape(op.configuration) + case ICGateDefinition.SRLatch.ordinal => + op.configuration = SRLatch.cycleShape(op.configuration) + case ICGateDefinition.Counter.ordinal => + op.configuration = Counter.cycleShape(op.configuration) + case _ => + op.configuration = 0 + } + case _ => + } + } + + def pickOp(op: CircuitOp): Unit = { + setConfigNode(null) + currentOp = op + } + + def doPickOp() { + val root = getRoot + val i = Mouse.getX * root.width / root.mc.displayWidth + val j = root.height - Mouse.getY * root.height / root.mc.displayHeight - 1 + val absPos = Point(i, j) + + val pos = parent.convertPointFromScreen(absPos) + if (rayTest(pos)) { + val part = circuit.getPart(toGridPoint(pos.vectorize)) + val op = if (part != null) { + setConfigNode(null) + part.getCircuitOperation + } else + null + currentOp = op + onPick(op) + } + } + + def incDetail() { + detailLevel = math.min(detailLevel + 1, 3) + } + + def decDetail() { + detailLevel = math.max(detailLevel - 1, 0) + } + + def incScale() { + rescaleAt(parent.frame.midPoint, math.min(scale + 0.2, 3.0)) + } + + def decScale() { + rescaleAt(parent.frame.midPoint, math.max(scale - 0.2, 0.5)) + } + + private def rescaleAt(point: Point, newScale: Double): Unit = { + val newP = (point.vectorize / scale) * newScale + val dp = (newP - point.vectorize) / (RenderCircuit.BASE_SCALE * scale) + offset = offset + dp + scale = newScale + } + + /** Scales the prefboard to the circuit with some border + */ + def scaleGuiToCircuit() = { + val circuitBounds = circuit.getPartsBoundingBox() + val circuitBoundsWithPadding = circuitBounds.union( + Rect(circuitBounds.origin.subtract(1, 1), circuitBounds.size.add(3)) + ) + // Required scaling to fit whole circuit on the screen + val requiredScale = math.min( + (parent.frame.size.width / RenderCircuit.BASE_SCALE.toDouble) / circuitBoundsWithPadding.size.width, + (parent.frame.size.height / RenderCircuit.BASE_SCALE.toDouble) / circuitBoundsWithPadding.size.height + ) + offset = circuitBoundsWithPadding.origin.vectorize + scale = requiredScale + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/StringExport.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/StringExport.scala new file mode 100644 index 000000000..49dbe5645 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/StringExport.scala @@ -0,0 +1,166 @@ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.color.Colors +import mrtjp.core.gui.{GuiLib, MCButtonNode, TNode} +import mrtjp.core.vec.{Point, Rect, Size} +import mrtjp.projectred.fabrication.IntegratedCircuit +import mrtjp.projectred.fabrication.circuitparts.CircuitPart +import mrtjp.projectred.fabrication.operations.OpAreaBase +import net.minecraft.client.gui.Gui +import net.minecraft.nbt.{JsonToNBT, NBTTagCompound} +import net.minecraft.util.StatCollector + +import java.awt.Toolkit +import java.awt.datatransfer.{DataFlavor, StringSelection} +import java.io.ByteArrayOutputStream +import java.nio.charset.{Charset, StandardCharsets} +import java.util.Base64 +import java.util.zip.{DataFormatException, Deflater, Inflater} + +/** Export/Import of Circuits: Circuit as nbt -> Deflate -> Base64 + */ +class StringExport(circuit: IntegratedCircuit, onImport: () => Unit) + extends Gui + with TNode { + + position = Point(20, -150) + + override def frame: Rect = Rect(position, Size(180, 80)) + + var statusText = "" + var statusColor = Colors.RED + + { + val close = new MCButtonNode + close.position = Point(4, 4) + close.size = Size(5, 5) + close.clickDelegate = { () => removeFromParent() } + addChild(close) + + val buttonImport = new MCButtonNode + buttonImport.position = Point(10, 10) + buttonImport.size = Size(160, 20) + buttonImport.text = + StatCollector.translateToLocal("gui.projectred.fabrication.import_string") + buttonImport.clickDelegate = { () => + try { + importString() + onImport() + } catch { + case _: IllegalArgumentException | _: DataFormatException => + statusText = "gui.projectred.fabrication.invalid_string" + statusColor = Colors.RED + case _: IllegalStateException => + statusText = "gui.projectred.fabrication.clipboard_unavailable" + statusColor = Colors.RED + } + } + addChild(buttonImport) + + val buttonExport = new MCButtonNode + buttonExport.position = Point(10, 35) + buttonExport.size = Size(160, 20) + buttonExport.text = + StatCollector.translateToLocal("gui.projectred.fabrication.export_string") + buttonExport.clickDelegate = { () => + try { + exportString(circuit) + statusText = "gui.projectred.fabrication.export_success" + statusColor = Colors.GREEN + } catch { + case _: IllegalStateException => + statusText = "gui.projectred.fabrication.clipboard_unavailable" + statusColor = Colors.RED + } + } + addChild(buttonExport) + } + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + GuiLib.drawGuiBox( + position.x, + position.y, + frame.size.width, + frame.size.height, + 0 + ) + GuiDraw.drawString( + StatCollector.translateToLocal(statusText), + position.x + 5, + position.y + 60, + statusColor.argb, + false + ) + } + + private def exportString(circuit: IntegratedCircuit): Unit = { + val nbtTagCompound = new NBTTagCompound + circuit.save(nbtTagCompound) + val data = nbtTagCompound.toString.getBytes(Charset.forName("UTF-8")) + val compressed = compress(data) + val base64EncodedString = new StringSelection( + Base64.getEncoder.encodeToString(compressed) + ) + Toolkit.getDefaultToolkit.getSystemClipboard + .setContents(base64EncodedString, null) + } + + private def compress(input: Array[Byte]): Array[Byte] = { + + val bos = new ByteArrayOutputStream() + + val compressor = new Deflater() + compressor.setInput(input) + compressor.finish() + + val buffer = new Array[Byte](1024) + while (!compressor.finished()) { + val len = compressor.deflate(buffer) + bos.write(buffer, 0, len) + } + compressor.end() + + bos.toByteArray + } + + @throws[Exception] + private def importString(): Unit = { + val clipboard = Toolkit.getDefaultToolkit.getSystemClipboard + val clipboardString = + clipboard.getData(DataFlavor.stringFlavor).asInstanceOf[String] + val decoded = Base64.getDecoder.decode(clipboardString) + val decompressed = decompress(decoded) + + val nbt = + JsonToNBT.func_150315_a(new String(decompressed, StandardCharsets.UTF_8)) + val compound = nbt.asInstanceOf[NBTTagCompound] + val x = compound.getTagList("parts", 10) + val parts = (0 until x.tagCount()) + .map { i => + x.getCompoundTagAt(i) + } + .map { partTag => + val part = CircuitPart.createPart(partTag.getByte("id")) + part.load(partTag) + part.loc = (partTag.getInteger("xpos"), partTag.getInteger("ypos")) + (part.x, part.y) -> part + } + .toMap + OpAreaBase.saveToClipboard(parts) + } + + private def decompress(data: Array[Byte]): Array[Byte] = { + val inflater = new Inflater() + inflater.setInput(data) + + val output = new ByteArrayOutputStream() + val buffer = new Array[Byte](1024) + + while (!inflater.finished()) { + val count = inflater.inflate(buffer) + output.write(buffer, 0, count) + } + output.toByteArray + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ToolbarNode.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ToolbarNode.scala new file mode 100644 index 000000000..27dbef352 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/ToolbarNode.scala @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.gui.{IconButtonNode, TNode} +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.IntegratedCircuit +import mrtjp.projectred.fabrication.operations.{CircuitOp, CircuitOpDefs} +import mrtjp.projectred.fabrication.operations.CircuitOpDefs.{ + ANDGate, + AlloyWire, + AnalogIO, + BlackBundledCable, + BlackInsulatedWire, + BufferCellGate, + BufferGate, + BundledIO, + Button, + Copy, + CounterGate, + Cut, + DecRandomizerGate, + Erase, + InvertCellGate, + Lever, + MultiplexerGate, + NANDGate, + NORGate, + NOTGate, + NeutralBundledCable, + NullCellGate, + ORGate, + OpDef, + Paste, + PulseFormerGate, + RandomizerGate, + RepeaterGate, + SRLatchGate, + SequencerGate, + SimpleIO, + StateCellGate, + SynchronizerGate, + TimerGate, + ToggleLatchGate, + Torch, + TransparentLatchGate, + WhiteInsulatedWire, + XNORGate, + XORGate +} +import net.minecraft.util.EnumChatFormatting.{AQUA, ITALIC} +import net.minecraft.util.StatCollector + +import scala.collection.JavaConversions._ + +class ToolbarNode(circuit: IntegratedCircuit, onPick: CircuitOp => Unit) + extends TNode { + + private def translate(str: String): String = { + StatCollector.translateToLocal(str) + } + + def buildToolbar(): Unit = { + addToolset("", Seq(Erase)) + addToolset("", Seq(Cut)) + addToolset("", Seq(Copy)) + addToolset("", Seq(Paste)) + addToolset( + translate("gui.projectred.fabrication.debug"), + Seq(Torch, Lever, Button) + ) + addToolset("", Seq(AlloyWire)) + addToolsetRange( + translate("gui.projectred.fabrication.insulated_wires"), + WhiteInsulatedWire, + BlackInsulatedWire + ) + addToolsetRange( + translate("gui.projectred.fabrication.bundled_cables"), + NeutralBundledCable, + BlackBundledCable + ) + addToolset( + translate("gui.projectred.fabrication.ios"), + Seq(SimpleIO, BundledIO, AnalogIO) + ) + addToolset( + translate("gui.projectred.fabrication.primitives"), + Seq( + ORGate, + NORGate, + NOTGate, + ANDGate, + NANDGate, + XORGate, + XNORGate, + BufferGate, + MultiplexerGate + ) + ) + addToolset( + translate("gui.projectred.fabrication.timing_and_clocks"), + Seq( + PulseFormerGate, + RepeaterGate, + TimerGate, + SequencerGate, + StateCellGate + ) + ) + addToolset( + translate("gui.projectred.fabrication.latches"), + Seq(SRLatchGate, ToggleLatchGate, TransparentLatchGate) + ) + addToolset("Cells", Seq(NullCellGate, InvertCellGate, BufferCellGate)) + addToolset( + translate("gui.projectred.fabrication.misc"), + Seq(RandomizerGate, CounterGate, SynchronizerGate, DecRandomizerGate) + ) + addImExport() + } + + def selectOp(op: CircuitOp): Unit = { + if (op == null) { + children + .collect { case b: ICToolsetNode => b } + .foreach(node => { + node.setUnfocused() + }) + } else { + children + .collect { case b: ICToolsetNode => b } + .foreach(node => { + node.select(op) + }) + } + } + + private def addToolsetRange(name: String, from: OpDef, to: OpDef): Unit = { + addToolset(name, (from.getID to to.getID).map(CircuitOpDefs(_))) + } + + private def addToolset(name: String, opset: Seq[OpDef]): Unit = { + val toolset = new ICToolsetNode(name, { op => onPick(op) }) + toolset.position = Point(17, 0) * children.size + toolset.opSet = opset.map(_.getOp) + toolset.setup() + addChild(toolset) + } + + private def addImExport(): Unit = { + var button: IconButtonNode = null + button = new IconButtonNode { + override def drawFront_Impl(mouse: Point, rframe: Float): Unit = { + val p = parent.children + .filter { p => p.isInstanceOf[IconButtonNode] } + .head + .position + if ( + p.x < mouse.x && mouse.x < p.x + 16 && p.y < mouse.y && mouse.y < p.y + 16 + ) { + translateToScreen() + val Point(mx, my) = parent.convertPointToScreen(mouse) + GuiDraw.drawMultilineTip( + mx + 12, + my - 16, + Seq( + ITALIC.toString + StatCollector.translateToLocal( + "gui.projectred.fabrication.im_ex_port" + ) + ) + ) + translateFromScreen() + } + } + } + button.size = Size(16, 16) + button.position = Point(17, 0) * children.size + button.clickDelegate = { () => + var exportGui: StringExport = null + exportGui = new StringExport( + circuit, + () => { + exportGui.removeFromParent() + selectOp(Paste.op) + onPick(Paste.op) + } + ) + addChild(exportGui) + } + addChild(button) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ColorPicker.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ColorPicker.scala new file mode 100644 index 000000000..4d1e885cf --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ColorPicker.scala @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.color.Colors +import mrtjp.core.gui.TNode +import mrtjp.core.vec.{Point, Rect, Size} + +class ColorPicker(var color: Int, onPickColor: Int => Unit) extends TNode { + + var size = Size.zeroSize + + override def frame = Rect(position, size) + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + val edge = size.width / 4 + + for (i <- 0 to 15) { + // Top Left Corner + val x = position.x + (i % 4) * edge + val y = position.y + (i / 4) * edge + + if (i != color) { + GuiDraw.drawRect( + x, + y, + edge, + edge, + Colors(i).argb + ) + } else { + // Border + GuiDraw.drawRect( + x, + y, + edge, + edge, + 0xffff7777 + ) + // Color + GuiDraw.drawRect( + x + 2, + y + 2, + edge - 4, + edge - 4, + Colors(i).argb + ) + } + } + } + + override def mouseClicked_Impl( + p: Point, + button: Int, + consumed: Boolean + ): Boolean = { + if (!consumed && rayTest(p)) { + val relPos = p.subtract(position) + val index = + (relPos.y / (size.height / 4)) * 4 + relPos.x / (size.width / 4) + color = index + onPickColor(color) + true + } else + false + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationAnalogIO.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationAnalogIO.scala new file mode 100644 index 000000000..89b9bd7aa --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationAnalogIO.scala @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.color.Colors +import mrtjp.core.gui.SimpleTextboxNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.io.{ + AnalogIOICGateLogic, + IOGateICPart +} +import net.minecraft.util.StatCollector + +import scala.util.Try + +class ConfigurationAnalogIO(gate: IOGateICPart) + extends ConfigurationSimpleIO(gate) { + private val logic = gate.getLogicPrimitive.asInstanceOf[AnalogIOICGateLogic] + + val freq = new SimpleTextboxNode + freq.position = Point(20, 110) + freq.size = Size(30, 12) + freq.text = "0x%x".format(logic.freq) + freq.textChangedDelegate = { () => + { + val num = Try(Integer.parseInt(freq.text.substring(2), 16)) + gate.sendFrequency(num.getOrElse(0)) + } + } + addChild(freq) + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + super.drawBack_Impl(mouse, rframe) + + val pos_text = position.add(5, 100) + GuiDraw.drawString( + StatCollector.translateToLocal( + "gui.projectred.fabrication.frequency" + ) + ":", + pos_text.x, + pos_text.y, + Colors.GREY.argb, + false + ) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationBundledIO.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationBundledIO.scala new file mode 100644 index 000000000..e49bdae48 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationBundledIO.scala @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.io.IOGateICPart + +class ConfigurationBundledIO(gate: IOGateICPart) + extends ConfigurationSimpleIO(gate) { + val colorPicker = new ColorPicker( + gate.getIOMode, + onPickColor = color => { + gate.sendFrequency(color) + } + ) + colorPicker.position = Point(5, 100) + colorPicker.size = Size(60, 60) + addChild(colorPicker) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationCounter.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationCounter.scala new file mode 100644 index 000000000..e1a730059 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationCounter.scala @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import codechicken.lib.gui.GuiDraw +import mrtjp.core.color.Colors +import mrtjp.core.gui.SimpleTextboxNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.SequentialGateICPart +import mrtjp.projectred.fabrication.circuitparts.misc.ICounterGuiLogic + +import scala.util.Try + +class ConfigurationCounter(gate: SequentialGateICPart) + extends ConfigurationRotationConfig(gate) { + private val counterLogic = + gate.getLogicPrimitive.asInstanceOf[ICounterGuiLogic] + + val max = new SimpleTextboxNode() + max.position = Point(30, 118) + max.size = Size(30, 12) + max.text = counterLogic.getCounterMax.toString + max.allowedcharacters = "0123456789" + max.textChangedDelegate = { () => + { + val num = Try(max.text.toInt) + gate.sendClientPacket( + _.writeByte(4).writeByte(0).writeShort(num.getOrElse(1)) + ) + } + } + addChild(max) + + val inc = new SimpleTextboxNode() + inc.position = Point(30, 138) + inc.size = Size(30, 12) + inc.text = counterLogic.getCounterIncr.toString + inc.allowedcharacters = "0123456789" + inc.textChangedDelegate = { () => + { + val num = Try(inc.text.toInt) + gate.sendClientPacket( + _.writeByte(4).writeByte(1).writeShort(num.getOrElse(1)) + ) + } + } + addChild(inc) + + val dec = new SimpleTextboxNode() + dec.position = Point(30, 158) + dec.size = Size(30, 12) + dec.text = counterLogic.getCounterDecr.toString + dec.allowedcharacters = "0123456789" + dec.textChangedDelegate = { () => + { + val num = Try(dec.text.toInt) + gate.sendClientPacket( + _.writeByte(4).writeByte(2).writeShort(num.getOrElse(1)) + ) + } + } + addChild(dec) + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + super.drawBack_Impl(mouse, rframe) + + val pos_state = position.add(5, 102) + GuiDraw.drawString( + translate( + "gui.projectred.fabrication.state" + ) + ": " + counterLogic.getCounterValue.toString, + pos_state.x, + pos_state.y, + Colors.GREY.argb, + false + ) + + val pos_max = position.add(5, 120) + GuiDraw.drawString( + translate("gui.projectred.fabrication.max"), + pos_max.x, + pos_max.y, + Colors.GREY.argb, + false + ) + + val pos_inc = position.add(5, 140) + GuiDraw.drawString( + translate("gui.projectred.fabrication.inc"), + pos_inc.x, + pos_inc.y, + Colors.GREY.argb, + false + ) + + val pos_dec = position.add(5, 160) + GuiDraw.drawString( + translate("gui.projectred.fabrication.dec"), + pos_dec.x, + pos_dec.y, + Colors.GREY.argb, + false + ) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotation.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotation.scala new file mode 100644 index 000000000..82a3758dd --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotation.scala @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import mrtjp.core.gui.MCButtonNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.GateICPart +import mrtjp.projectred.fabrication.gui.nodes.ConfigurationNode + +class ConfigurationRotation(gate: GateICPart) extends ConfigurationNode(gate) { + val rotate = new MCButtonNode + rotate.position = Point(8, 60) + rotate.size = Size(50, 15) + rotate.text = translate("gui.projectred.fabrication.rotate") + rotate.clickDelegate = { () => gate.sendClientPacket(_.writeByte(0)) } + addChild(rotate) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotationConfig.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotationConfig.scala new file mode 100644 index 000000000..fd136e63b --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationRotationConfig.scala @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import mrtjp.core.gui.MCButtonNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.GateICPart + +class ConfigurationRotationConfig(gate: GateICPart) + extends ConfigurationRotation(gate) { + + val conf = new MCButtonNode + conf.position = Point(8, 80) + conf.size = Size(50, 15) + conf.text = translate("gui.projectred.fabrication.configure") + conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } + addChild(conf) +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationSimpleIO.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationSimpleIO.scala new file mode 100644 index 000000000..fca252e6a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationSimpleIO.scala @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import codechicken.lib.vec.{Rotation, Scale, TransformationList, Translation} +import mrtjp.core.gui.IconButtonNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.circuitparts.io.IOGateICPart +import mrtjp.projectred.fabrication.{ArrowModel, ICComponentStore} + +class ConfigurationSimpleIO(gate: IOGateICPart) + extends ConfigurationRotation(gate) { + + val arrowModel = new ArrowModel + + val in = new IconButtonNode { + override def drawButton(mouseover: Boolean): Unit = { + renderIcon(0, position) + } + } + + in.position = Point(5, 80) + in.size = Size(20, 15) + in.clickDelegate = { () => + gate.sendClientPacket(_.writeByte(6).writeByte(0)) + } + addChild(in) + + val out = new IconButtonNode { + override def drawButton(mouseover: Boolean): Unit = + renderIcon(1, position) + } + out.position = Point(25, 80) + out.size = Size(20, 15) + out.clickDelegate = { () => + gate.sendClientPacket(_.writeByte(6).writeByte(1)) + } + addChild(out) + + val inout = new IconButtonNode { + override def drawButton(mouseover: Boolean): Unit = + renderIcon(2, position) + } + inout.position = Point(45, 80) + inout.size = Size(20, 15) + inout.clickDelegate = { () => + gate.sendClientPacket(_.writeByte(6).writeByte(2)) + } + addChild(inout) + + private def renderIcon(icon: Int, position: Point): Unit = { + val t = new TransformationList( + new Scale(40, 1, -40), + new Rotation(0.5 * math.Pi, 1, 0, 0), + new Translation(position.x - 9, position.y - 12, 0) + ) + arrowModel.arrowDirection = icon + ICComponentStore.prepairRender() + arrowModel.renderModel(t, 0, true) + ICComponentStore.finishRender() + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationTimer.scala b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationTimer.scala new file mode 100644 index 000000000..26cf351ee --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/gui/nodes/configuration/ConfigurationTimer.scala @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.gui.nodes.configuration + +import codechicken.lib.gui.GuiDraw +import codechicken.lib.vec.Translation +import mrtjp.core.color.Colors +import mrtjp.core.gui.SimpleTextboxNode +import mrtjp.core.vec.{Point, Size} +import mrtjp.projectred.fabrication.ICComponentStore +import mrtjp.projectred.fabrication.circuitparts.timing.ITimerGuiLogic +import mrtjp.projectred.fabrication.circuitparts.{ + ICGateRenderer, + SequentialGateICPart +} + +import scala.util.Try + +class ConfigurationTimer(gate: SequentialGateICPart) + extends ConfigurationRotation(gate) { + private val timerLogic = gate.getLogicPrimitive.asInstanceOf[ITimerGuiLogic] + + val text = new SimpleTextboxNode + text.position = Point(20, 95) + text.size = Size(30, 10) + text.allowedcharacters = "0123456789.," + text.text = "%.2f".format(timerLogic.getTimerMax * 0.05) + text.textChangedDelegate = () => { + val time = Try(text.text.replaceAll(",", ".").toDouble) + gate.sendClientPacket( + _.writeByte(3).writeShort((time.getOrElse(1d) * 20).toInt) + ) + } + addChild(text) + + override def drawBack_Impl(mouse: Point, rframe: Float): Unit = { + super.drawBack_Impl(mouse, rframe) + + val pos_state = position.add(13, 82) + GuiDraw.drawString( + translate("gui.projectred.fabrication.timer_interval") + ":", + pos_state.x, + pos_state.y, + Colors.GREY.argb, + false + ) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/guiicworkbench.scala b/src/main/scala/mrtjp/projectred/fabrication/guiicworkbench.scala deleted file mode 100644 index 47642fbfa..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/guiicworkbench.scala +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import java.math.MathContext -import net.minecraft.client.resources.I18n -import codechicken.lib.data.MCDataInput -import codechicken.lib.gui.GuiDraw -import codechicken.lib.render.ColourMultiplier -import codechicken.lib.render.uv.{UVScale, UVTranslation} -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.color.Colors -import mrtjp.core.gui._ -import mrtjp.core.vec.{Point, Rect, Size} -import mrtjp.core.world.WorldLib -import mrtjp.projectred.core.libmc.PRResources -import mrtjp.projectred.fabrication.ICComponentStore._ -import net.minecraft.client.Minecraft -import net.minecraft.client.gui.Gui -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.util.EnumChatFormatting -import org.lwjgl.input.{Keyboard, Mouse} -import org.lwjgl.opengl.GL11 - -import scala.collection.JavaConversions._ -import scala.collection.convert.WrapAsJava -import scala.collection.immutable.ListMap - -class PrefboardNode(circuit: IntegratedCircuit) extends TNode { - var currentOp: CircuitOp = null - - /** 0 - off 1 - name only 2 - minor details 3 - all details - */ - var detailLevel = 1 - var scale = 1.0 - var sizeMult = 8 - def size = circuit.size * sizeMult - override def frame = Rect( - position, - Size((size.width * scale).toInt, (size.height * scale).toInt) - ) - - var opPickDelegate = { _: CircuitOp => () } - - private var leftMouseDown = false - private var rightMouseDown = false - private var mouseStart = Point(0, 0) - - private def isCircuitValid = circuit.nonEmpty - - private def toGridPoint(p: Point) = { - val f = frame - val rpos = p - position - Point( - (rpos.x * circuit.size.width * 1.0 / f.width).toInt - .min(circuit.size.width - 1) - .max(0), - (rpos.y * circuit.size.height * 1.0 / f.height).toInt - .min(circuit.size.height - 1) - .max(0) - ) - } - - private def toCenteredGuiPoint(gridP: Point) = { - val dp = frame.size.vectorize / circuit.size.vectorize - Point(gridP.vectorize * dp + dp / 2) - } - - override def update_Impl() { - if (mcInst.theWorld.getTotalWorldTime % 20 == 0) - circuit.refreshErrors() - } - - override def drawBack_Impl(mouse: Point, rframe: Float) { - if (isCircuitValid) { - val f = frame - RenderCircuit.renderOrtho( - circuit, - f.x, - f.y, - size.width * scale, - size.height * scale, - rframe - ) - - if (currentOp != null) { - if (frame.contains(mouse) && rayTest(mouse) && !leftMouseDown) - currentOp.renderHover( - circuit, - toGridPoint(mouse), - f.x, - f.y, - size.width * scale, - size.height * scale - ) - else if (leftMouseDown) - currentOp.renderDrag( - circuit, - mouseStart, - toGridPoint(mouse), - f.x, - f.y, - size.width * scale, - size.height * scale - ) - } - - if ( - mcInst.theWorld.getTotalWorldTime % 100 > 5 && circuit.errors.nonEmpty - ) { - prepairRender() - PRResources.guiPrototyper.bind() - for ((Point(x, y), (_, c)) <- circuit.errors) { - val t = orthoPartT( - f.x, - f.y, - size.width * scale, - size.height * scale, - circuit.size, - x, - y - ) - faceModels(dynamicIdx(0, true)).render( - t, - new UVScale(64) `with` new UVTranslation( - 330, - 37 - ) `with` new UVScale(1 / 512d), - ColourMultiplier.instance(Colors(c).rgba) - ) - } - finishRender() - } - } - } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - if ( - isCircuitValid && !leftMouseDown && frame.contains(mouse) && rayTest( - mouse - ) - ) { - val point = toGridPoint(mouse) - val part = circuit.getPart(point) - if (part != null) { - val data = part.getRolloverData(detailLevel) - if (data.nonEmpty) { - ClipNode.tempDisableScissoring() - translateToScreen() - val Point(mx, my) = parent.convertPointToScreen(mouse) - GuiDraw.drawMultilineTip( - mx + 12, - my - 12, - WrapAsJava.seqAsJavaList(data) - ) - if (circuit.errors.contains(point)) - GuiDraw.drawMultilineTip( - mx + 12, - my - 32, - Seq(EnumChatFormatting.RED.toString + circuit.errors(point)._1) - ) - translateFromScreen() - ClipNode.tempEnableScissoring() - } - } - } - } - - override def mouseClicked_Impl( - p: Point, - button: Int, - consumed: Boolean - ): Boolean = { - if (isCircuitValid && !consumed && rayTest(p)) button match { - case 0 => - leftMouseDown = true - mouseStart = toGridPoint(p) - return true - case 1 => - rightMouseDown = true - val gridP = toGridPoint(p) - circuit.getPart(gridP) match { - case gp: IGuiCircuitPart => - val currentlyOpen = children.collect { case cg: CircuitGui => cg } - if (!currentlyOpen.exists(_.part == gp)) { - val gui = gp.createGui - gui.position = - convertPointFrom(Point(4, 4) * (currentlyOpen.size + 1), parent) - gui.linePointerCalc = () => toCenteredGuiPoint(gridP) - addChild(gui) - gui.pushZTo(currentlyOpen.size * 0.1) - } - case _ => - } - return true - case _ if button == mcInst.gameSettings.keyBindPickBlock.getKeyCode => - doPickOp() - return true - case _ => - } - false - } - - override def mouseReleased_Impl(p: Point, button: Int, consumed: Boolean) = { - if (leftMouseDown) { - leftMouseDown = false - val mouseEnd = toGridPoint(p) - val opUsed = - currentOp != null && circuit.sendOpUse(currentOp, mouseStart, mouseEnd) - if (!opUsed && mouseEnd == mouseStart) { - val part = circuit.getPart(mouseEnd) - if (part != null) part.onClicked() - } - } - if (rightMouseDown) { - rightMouseDown = false - val mouseEnd = toGridPoint(p) - if (mouseEnd == mouseStart) { - val part = circuit.getPart(mouseEnd) - if (part != null) part.onActivated() - } - } - false - } - - override def mouseScrolled_Impl(p: Point, dir: Int, consumed: Boolean) = { - if (!consumed && rayTest(p)) { - if (dir > 0) rescaleAt(p, math.min(scale + 0.1, 3.0)) - else if (dir < 0) rescaleAt(p, math.max(scale - 0.1, 0.5)) - true - } else false - } - - override def keyPressed_Impl(c: Char, keycode: Int, consumed: Boolean) = { - import Keyboard._ - if (!consumed) keycode match { - case KEY_ESCAPE if leftMouseDown => - leftMouseDown = false - true - case KEY_ESCAPE if currentOp != null => - opPickDelegate(null) - true - case _ if keycode == mcInst.gameSettings.keyBindPickBlock.getKeyCode => - doPickOp() - true - case _ if keycode == mcInst.gameSettings.keyBindInventory.getKeyCode => - opPickDelegate(CircuitOpDefs.Erase.getOp) - true - case _ => false - } - else false - } - - def doPickOp() { - val root = getRoot - val i = Mouse.getX * root.width / root.mc.displayWidth - val j = root.height - Mouse.getY * root.height / root.mc.displayHeight - 1 - val absPos = Point(i, j) - - val pos = parent.convertPointFromScreen(absPos) - if (rayTest(pos)) { - val part = circuit.getPart(toGridPoint(pos)) - opPickDelegate(if (part != null) part.getPickOp else null) - } - } - - def incDetail() { detailLevel = math.min(detailLevel + 1, 3) } - def decDetail() { detailLevel = math.max(detailLevel - 1, 0) } - - def incScale() { rescaleAt(frame.midPoint, math.min(scale + 0.2, 3.0)) } - def decScale() { rescaleAt(frame.midPoint, math.max(scale - 0.2, 0.5)) } - - def rescaleAt(point: Point, newScale: Double) { - val p = parent.convertPointTo(point, this).vectorize - val newP = (p / scale) * newScale - val dp = newP - p - scale = newScale - position -= Point(dp) - } -} - -class ICToolsetNode extends TNode { - var opSet = Seq.empty[CircuitOp] - var title = "" - var buttonSize = Size(16, 16) - var buttonGap = 1 - - var opSelectDelegate = { _: CircuitOp => () } - - private var focused = false - private var buttonOpMap = ListMap.empty[ButtonNode, CircuitOp] - - private var leadingButton: ButtonNode = null - private var groupButton: ButtonNode = null - - def setup() { - for (op <- opSet) { - val b = createButtonFor(op) - b.size = buttonSize - b.hidden = true - addChild(b) - buttonOpMap += b -> op - } - - val delta = opSet.size * (buttonSize.width + buttonGap) - val firstPoint = - Point(-delta / 2 + buttonSize.width / 2, -buttonSize.height - buttonGap) - for ((b, i) <- buttonOpMap.keys.zipWithIndex) - b.position = firstPoint.add(i * (buttonSize.width + buttonGap), 0) - - leadingButton = buttonOpMap.head._1 - - groupButton = new IconButtonNode { - override def drawButton(mouseover: Boolean) = { - val op = buttonOpMap(leadingButton) - op.renderImage( - position.x + 2, - position.y + 2, - size.width - 4, - size.height - 4 - ) - } - } - groupButton.size = buttonSize - groupButton.tooltipBuilder = { _ += buttonOpMap(leadingButton).getOpName } - groupButton.clickDelegate = { () => leadingButton.clickDelegate() } - addChild(groupButton) - } - - private def buttonClicked(op: CircuitOp, button: ButtonNode) { - setFocused() - opSelectDelegate(op) - parent.children - .collect { - case t: ICToolsetNode if t != this => t - } - .foreach(_.setUnfocused()) - leadingButton.mouseoverLock = false - leadingButton = button - leadingButton.mouseoverLock = true - } - - def setUnfocused() { - if (focused) hideSubTools() - focused = false - groupButton.mouseoverLock = false - } - - def setFocused() { - if (!focused) unhideSubTools() - focused = true - groupButton.mouseoverLock = true - } - - private def unhideSubTools() { - if (buttonOpMap.size > 1) - for (b <- buttonOpMap.keys) - b.hidden = false - } - - private def hideSubTools() { - if (buttonOpMap.size > 1) - for (b <- buttonOpMap.keys) - b.hidden = true - } - - private def createButtonFor(op: CircuitOp) = { - val b = new IconButtonNode { - override def drawButton(mouseover: Boolean) { - op.renderImage( - position.x + 2, - position.y + 2, - size.width - 4, - size.height - 4 - ) - } - } - b.tooltipBuilder = { _ += op.getOpName } - b.clickDelegate = { () => buttonClicked(op, b) } - b - } - - def pickOp(op: CircuitOp) { - setUnfocused() - buttonOpMap.find(_._2 == op) match { - case Some((b, _)) => b.clickDelegate() - case _ => - } - } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - if ( - title.nonEmpty && groupButton.rayTest(parent.convertPointTo(mouse, this)) - ) { - import net.minecraft.util.EnumChatFormatting._ - translateToScreen() - val Point(mx, my) = parent.convertPointToScreen(mouse) - GuiDraw.drawMultilineTip( - mx + 12, - my - 32, - Seq(AQUA.toString + ITALIC.toString + title) - ) - translateFromScreen() - } - } -} - -class NewICNode extends TNode { - val size = Size(100, 120) - override def frame = Rect(position, size) - - var sizerRenderSize = Size(50, 50) - var sizerRenderOffset = Point(0, -16) - var sizerRenderGap = 2 - - var maxBoardSize = Size(4, 4) - var selectedBoardSize = Size(1, 1) - - var completionDelegate = { () => () } - - var outsideColour = Colors.LIGHT_GREY.argb - var insideColour = Colors.CYAN.rgb | 0x88000000 - var hoverColour = Colors.BLUE.argb - - def getName = { - val t = textbox.text - if (t.isEmpty) "untitled" else t - } - - private var textbox: SimpleTextboxNode = null - private var sizerMap: Map[(Int, Int), Rect] = null - - private def sizerPos = - position + Point(size / 2 - sizerRenderSize / 2) + sizerRenderOffset - - private def calcSizerRects = { - val p = sizerPos - val d = sizerRenderSize / maxBoardSize - - val rcol = GuiLib.createGrid( - p.x, - p.y, - maxBoardSize.width, - maxBoardSize.height, - d.width, - d.height - ) - val icol = - GuiLib.createGrid(0, 0, maxBoardSize.width, maxBoardSize.height, 1, 1) - val zcol = rcol.zip(icol) - - var rects = Map[(Int, Int), Rect]() - for (((px, py), (x, y)) <- zcol) { - val rect = - Rect(Point(px, py) + sizerRenderGap / 2, d - sizerRenderGap / 2) - rects += (x, y) -> rect - } - rects - } - - private def getMouseoverPos(mouse: Point) = - sizerMap.find(_._2 contains mouse) match { - case Some(((x, y), r)) => Point(x, y) - case None => null - } - - override def traceHit(absPoint: Point) = true - - override def onAddedToParent_Impl() { - sizerMap = calcSizerRects - - val close = new MCButtonNode - close.size = Size(8, 8) - close.position = Point(4, 4) - close.clickDelegate = { () => removeFromParent() } - addChild(close) - - val fin = new MCButtonNode - fin.size = Size(40, 15) - fin.position = Point( - size.width / 2 - fin.size.width / 2, - size.height - fin.size.height - 4 - ) - fin.clickDelegate = { () => - removeFromParent() - completionDelegate() - } - fin.text = "start" - addChild(fin) - - textbox = new SimpleTextboxNode - textbox.size = Size(80, 14) - textbox.position = Point(size / 2 - textbox.size / 2) + Point(0, 24) - textbox.phantom = "untitled" - addChild(textbox) - } - - override def frameUpdate_Impl(mouse: Point, rframe: Float) { - if (!parent.asInstanceOf[GuiICWorkbench].tile.hasBP) - removeFromParent() - } - - override def drawBack_Impl(mouse: Point, rframe: Float) { - GuiDraw.drawGradientRect( - 0, - 0, - parent.frame.width, - parent.frame.height, - -1072689136, - -804253680 - ) - GuiLib.drawGuiBox(position.x, position.y, size.width, size.height, 0) - - val mousePos = getMouseoverPos(mouse) - for (((x, y), rect) <- sizerMap) { - GuiDraw.drawRect(rect.x, rect.y, rect.width, rect.height, outsideColour) - - if (x <= selectedBoardSize.width - 1 && y <= selectedBoardSize.height - 1) - GuiDraw.drawRect(rect.x, rect.y, rect.width, rect.height, insideColour) - - if (mousePos != null && x == mousePos.x && y == mousePos.y) - GuiDraw.drawRect(rect.midX - 2, rect.midY - 2, 4, 4, hoverColour) - } - } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - if (rayTest(mouse)) { - val mousePos = getMouseoverPos(mouse) - if (mousePos != null) { - translateToScreen() - val Point(mx, my) = parent.convertPointToScreen(mouse) - import scala.collection.JavaConversions._ - GuiDraw.drawMultilineTip( - mx + 12, - my - 12, - Seq((mousePos.x + 1) * 16 + " x " + (mousePos.y + 1) * 16) - ) - translateFromScreen() - } - } - } - - override def mouseClicked_Impl( - p: Point, - button: Int, - consumed: Boolean - ): Boolean = { - if (!consumed) { - val mousePos = getMouseoverPos(p) - if (mousePos != null) { - selectedBoardSize = Size(mousePos + 1) - return true - } - } - false - } - - override def keyPressed_Impl(c: Char, keycode: Int, consumed: Boolean) = { - if (!consumed) keycode match { - case Keyboard.KEY_ESCAPE => - removeFromParent() - true - case Keyboard.KEY_RETURN => - removeFromParent() - completionDelegate() - true - case _ => false - } - else false - } -} - -class InfoNode extends TNode { - val size = Size(18, 18) - override def frame = Rect(position, size) - - private def getTile = parent.asInstanceOf[GuiICWorkbench].tile - - override def drawBack_Impl(mouse: Point, rframe: Float) { - PRResources.guiPrototyper.bind() - if (!getTile.hasBP || getTile.getIC.isEmpty) - Gui.func_146110_a( - position.x, - position.y, - 330, - 0, - size.width, - size.height, - 512, - 512 - ) - } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - val text = - if (!getTile.hasBP) - "Lay down a blueprint on the workbench." - else if (getTile.getIC.isEmpty) - "Blueprint is empty. Redraw it." - else "" - if (text.nonEmpty && rayTest(mouse)) { - translateToScreen() - val Point(mx, my) = parent.convertPointToScreen(mouse) - import scala.collection.JavaConversions._ - GuiDraw.drawMultilineTip(mx + 12, my - 12, Seq(text)) - translateFromScreen() - } - } -} - -class GuiICWorkbench(val tile: TileICWorkbench) extends NodeGui(330, 256) { - var pref: PrefboardNode = null - var toolSets = Seq[ICToolsetNode]() - - override def onAddedToParent_Impl() { - val clip = new ClipNode - clip.position = Point(7, 18) - clip.size = Size(252, 197) - addChild(clip) - - val pan = new PanNode - pan.size = Size(252, 197) - pan.clampSlack = 35 - pan.dragTestFunction = { () => Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) } - clip.addChild(pan) - - pref = new PrefboardNode(tile.circuit) - pref.position = Point(pan.size / 2 - pref.size / 2) - pref.zPosition = -0.01 // Must be below pan/clip nodes - pref.opPickDelegate = { op => - if (op == null) pref.currentOp = null - toolSets.foreach(_.pickOp(op)) - } - pan.addChild(pref) - - val toolbar = new TNode {} - - { - import CircuitOpDefs._ - def addToolsetRange(name: String, from: OpDef, to: OpDef) { - addToolset(name, (from.getID to to.getID).map(CircuitOpDefs(_))) - } - def addToolset(name: String, opset: Seq[OpDef]) { - val toolset = new ICToolsetNode - toolset.position = Point(17, 0) * toolbar.children.size - toolset.title = name - toolset.opSet = opset.map(_.getOp) - toolset.setup() - toolset.opSelectDelegate = { op => pref.currentOp = op } - toolbar.addChild(toolset) - toolSets :+= toolset - } - - addToolset("", Seq(Erase)) - addToolset("Debug", Seq(Torch, Lever, Button)) - addToolset("", Seq(AlloyWire)) - addToolsetRange("Insulated wires", WhiteInsulatedWire, BlackInsulatedWire) - addToolsetRange("Bundled cables", NeutralBundledCable, BlackBundledCable) - addToolset("IOs", Seq(SimpleIO, BundledIO, AnalogIO)) - addToolset( - "Primatives", - Seq( - ORGate, - NORGate, - NOTGate, - ANDGate, - NANDGate, - XORGate, - XNORGate, - BufferGate, - MultiplexerGate - ) - ) - addToolset( - "Timing and Clocks", - Seq( - PulseFormerGate, - RepeaterGate, - TimerGate, - SequencerGate, - StateCellGate - ) - ) - addToolset( - "Latches", - Seq(SRLatchGate, ToggleLatchGate, TransparentLatchGate) - ) - addToolset("Cells", Seq(NullCellGate, InvertCellGate, BufferCellGate)) - addToolset( - "Misc", - Seq(RandomizerGate, CounterGate, SynchronizerGate, DecRandomizerGate) - ) - } - - addChild(toolbar) - toolbar.position = - Point(size.width / 2 - toolbar.calculateAccumulatedFrame.width / 2, 235) - - val dminus = new MCButtonNode - dminus.position = Point(269, 175) - dminus.size = Size(10, 10) - dminus.text = "-" - dminus.clickDelegate = { () => pref.decDetail() } - addChild(dminus) - - val dplus = new MCButtonNode - dplus.position = Point(309, 175) - dplus.size = Size(10, 10) - dplus.text = "+" - dplus.clickDelegate = { () => pref.incDetail() } - addChild(dplus) - - val sminus = new MCButtonNode - sminus.position = Point(269, 207) - sminus.size = Size(10, 10) - sminus.text = "-" - sminus.clickDelegate = { () => pref.decScale() } - addChild(sminus) - - val splus = new MCButtonNode - splus.position = Point(309, 207) - splus.size = Size(10, 10) - splus.text = "+" - splus.clickDelegate = { () => pref.incScale() } - addChild(splus) - - val reqNew = new MCButtonNode - reqNew.position = Point(272, 133) - reqNew.size = Size(44, 12) - reqNew.text = I18n.format("gui.projectred.integration.icblock|0.redraw") - reqNew.clickDelegate = { () => - if (tile.hasBP) { - val nic = new NewICNode - nic.position = Point(size / 2) - Point(nic.size / 2) - nic.completionDelegate = { () => - val ic = new IntegratedCircuit - ic.name = nic.getName - ic.size = nic.selectedBoardSize * 16 - tile.sendNewICToServer(ic) - } - addChild(nic) - nic.pushZTo(5) - } - } - addChild(reqNew) - - val info = new InfoNode - info.position = Point(241, 18) - info.zPosition = 1 - addChild(info) - } - - override def drawBack_Impl(mouse: Point, frame: Float) { - GL11.glColor4f(1, 1, 1, 1) - PRResources.guiPrototyper.bind() - Gui.func_146110_a(0, 0, 0, 0, size.width, size.height, 512, 512) - - GuiDraw.drawString( - I18n.format("gui.projectred.integration.icblock|0.title"), - 8, - 6, - Colors.GREY.argb, - false - ) - - GuiDraw.drawStringC( - I18n.format("gui.projectred.integration.icblock|0.detail"), - 273, - 162, - 42, - 14, - Colors.GREY.argb, - false - ) - GuiDraw.drawStringC( - pref.detailLevel + "", // TODO: GuiText Integration - 279, - 175, - 30, - 10, - Colors.GREY.argb, - false - ) - - GuiDraw.drawStringC( - I18n.format("gui.projectred.integration.icblock|0.scale"), - 273, - 193, - 42, - 14, - Colors.GREY.argb, - false - ) - GuiDraw.drawStringC( - BigDecimal( - pref.scale, - new MathContext(2) - ) + "", // TODO: GuiText Integration - 279, - 207, - 30, - 10, - Colors.GREY.argb, - false - ) - } -} - -object GuiICWorkbench extends TGuiBuilder { - override def getID = FabricationProxy.icWorkbenchGui - - @SideOnly(Side.CLIENT) - override def buildGui(player: EntityPlayer, data: MCDataInput) = { - WorldLib.getTileEntity( - Minecraft.getMinecraft.theWorld, - data.readCoord() - ) match { - case t: TileICWorkbench => - t.circuit.readDesc(data) - new GuiICWorkbench(t) - case _ => null - } - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/ic.scala b/src/main/scala/mrtjp/projectred/fabrication/ic.scala deleted file mode 100644 index 6c72dcde8..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/ic.scala +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.packet.PacketCustom -import codechicken.lib.vec.{BlockCoord, Transformation} -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.util.Enum -import mrtjp.core.vec.{Point, Size} -import mrtjp.projectred.ProjectRedCore.log -import net.minecraft.item.ItemStack -import net.minecraft.nbt.{NBTTagCompound, NBTTagList} -import net.minecraft.world.World -import net.minecraftforge.fluids.FluidStack - -import scala.collection.mutable.{Map => MMap, Seq => MSeq} - -trait WorldCircuit { - def getIC: IntegratedCircuit - def getWorld: World - - def getICStreamOf(key: Int): MCDataOutput - def getPartStream(x: Int, y: Int): MCDataOutput - - def isRemote: Boolean - def markSave() -} - -object DummyMCIO extends MCDataOutput { - override def writeVarInt(i: Int) = this - override def writeCoord(x: Int, y: Int, z: Int) = this - override def writeCoord(coord: BlockCoord) = this - override def writeString(s: String) = this - override def writeFloat(f: Float) = this - override def writeDouble(d: Double) = this - override def writeShort(s: Int) = this - override def writeVarShort(s: Int) = this - override def writeInt(i: Int) = this - override def writeFluidStack(liquid: FluidStack) = this - override def writeByteArray(array: Array[Byte]) = this - override def writeBoolean(b: Boolean) = this - override def writeItemStack(stack: ItemStack) = this - override def writeNBTTagCompound(tag: NBTTagCompound) = this - override def writeChar(c: Char) = this - override def writeLong(l: Long) = this - override def writeByte(b: Int) = this -} - -trait SimulatedWorldCircuit extends WorldCircuit { - override def getICStreamOf(key: Int) = DummyMCIO - override def getPartStream(x: Int, y: Int) = DummyMCIO - override def isRemote = false -} - -trait NetWorldCircuit extends WorldCircuit { - private var icStream: PacketCustom = null - private var partStream: PacketCustom = null - - def createPartStream(): PacketCustom - def sendPartStream(out: PacketCustom) - override def getPartStream(x: Int, y: Int): MCDataOutput = { - if (partStream == null) partStream = createPartStream() - - val part = getIC.getPart(x, y) - partStream.writeByte(part.id) - partStream.writeByte(x).writeByte(y) - - partStream - } - def flushPartStream() { - if (partStream != null) { - partStream.writeByte(255) // terminator - sendPartStream(partStream.compress()) - partStream = null - } - } - def readPartStream(in: MCDataInput) { - try { - var id = in.readUByte() - while (id != 255) { - val (x, y) = (in.readUByte(), in.readUByte()) - var part = getIC.getPart(x, y) - if (part == null || part.id != id) { - log.error("client part stream couldnt find part " + Point(x, y)) - part = CircuitPart.createPart(id) - } - part.read(in) - id = in.readUByte() - } - } catch { - case ex: IndexOutOfBoundsException => - log.error("Circuit part stream failed to be read.") - ex.printStackTrace() - } - } - - def createICStream(): PacketCustom - def sendICStream(out: PacketCustom) - override def getICStreamOf(key: Int): MCDataOutput = { - if (icStream == null) icStream = createICStream() - icStream.writeByte(key) - icStream - } - def flushICStream() { - if (icStream != null) { - icStream.writeByte(255) // terminator - sendICStream(icStream.compress()) - icStream = null - } - } - def readICStream(in: MCDataInput) { - try { - var id = in.readUByte() - while (id != 255) { - getIC.read(in, id) - id = in.readUByte() - } - } catch { - case ex: IndexOutOfBoundsException => - log.error("Circuit IC stream failed to be read") - } - } -} - -class IntegratedCircuit { - var network: WorldCircuit = null - - var name = "untitled" - var size = Size.zeroSize - - var parts = MMap[(Int, Int), CircuitPart]() - var errors = Map.empty[Point, (String, Int)] - - private var scheduledTicks = MMap[(Int, Int), Long]() - - /** Mapped inputs and outputs of this IC. Outputs go to the world, inputs come - * in from the world. OOOO OOOO OOOO OOOO IIII IIII IIII IIII - */ - val iostate = Array(0, 0, 0, 0) - - var outputChangedDelegate = { () => () } - - def setInput(r: Int, state: Int) { - iostate(r) = iostate(r) & 0xffff0000 | state & 0xffff - } - - def setOutput(r: Int, state: Int) { - iostate(r) = iostate(r) & 0xffff | (state & 0xffff) << 16 - } - - def firstSetup(): Unit = { - val ioparts = parts.values.collect { case io: IOGateICPart => io } - ioparts.foreach(_.onOutputChange(0xf)) - } - - def onInputChanged(mask: Int) { - val ioparts = parts.values.collect { case io: IIOCircuitPart => io } - for (r <- 0 until 4) if ((mask & 1 << r) != 0) { - ioparts.foreach(_.onExtInputChanged(r)) - sendInputUpdate(r) - } - } - - def onOutputChanged(mask: Int) { - val ioparts = parts.values.collect { case io: IIOCircuitPart => io } - for (r <- 0 until 4) if ((mask & 1 << r) != 0) { - ioparts.foreach(_.onExtOutputChanged(r)) - outputChangedDelegate() - sendOutputUpdate(r) - } - } - - def save(tag: NBTTagCompound) { - tag.setString("name", name) - tag.setByte("sw", size.width.toByte) - tag.setByte("sh", size.height.toByte) - tag.setIntArray("iost", iostate) - - val tagList = new NBTTagList - for (part <- parts.values) { - val partTag = new NBTTagCompound - partTag.setByte("id", part.id.toByte) - partTag.setByte("xpos", part.x.toByte) - partTag.setByte("ypos", part.y.toByte) - part.save(partTag) - tagList.appendTag(partTag) - } - tag.setTag("parts", tagList) - - // etc - } - - def load(tag: NBTTagCompound) { - clear() - name = tag.getString("name") - size = Size(tag.getByte("sw") & 0xff, tag.getByte("sh") & 0xff) - val ta = tag.getIntArray("iost") - for (i <- 0 until 4) iostate(i) = ta(i) - - val partList = tag.getTagList("parts", 10) - for (i <- 0 until partList.tagCount) { - val partTag = partList.getCompoundTagAt(i) - val part = CircuitPart.createPart(partTag.getByte("id") & 0xff) - setPart_do( - partTag.getByte("xpos") & 0xff, - partTag.getByte("ypos") & 0xff, - part - ) - part.load(partTag) - } - - // etc - } - - def writeDesc(out: MCDataOutput) { - out.writeString(name) - out.writeByte(size.width).writeByte(size.height) - for (i <- 0 until 4) out.writeInt(iostate(i)) - - for (((x, y), part) <- parts) { - out.writeByte(part.id) - out.writeByte(x).writeByte(y) - part.writeDesc(out) - } - out.writeByte(255) - - // etc - } - - def readDesc(in: MCDataInput) { - clear() - name = in.readString() - size = Size(in.readUByte(), in.readUByte()) - for (i <- 0 until 4) iostate(i) = in.readInt() - - var id = in.readUByte() - while (id != 255) { - val part = CircuitPart.createPart(id) - setPart_do(in.readUByte(), in.readUByte(), part) - part.readDesc(in) - id = in.readUByte() - } - // etc - } - - def read(in: MCDataInput, key: Int) = key match { - case 0 => readDesc(in) - case 1 => - val part = CircuitPart.createPart(in.readUByte()) - setPart_do(in.readUByte(), in.readUByte(), part) - part.readDesc(in) - case 2 => removePart(in.readUByte(), in.readUByte()) - case 3 => CircuitOp.getOperation(in.readUByte()).readOp(this, in) - case 4 => - getPart(in.readUByte(), in.readUByte()) match { - case g: TClientNetCircuitPart => g.readClientPacket(in) - case _ => log.error("Server IC stream received invalid client packet") - } - case 5 => iostate(in.readUByte()) = in.readInt() - case 6 => setInput(in.readUByte(), in.readShort()) - case 7 => setOutput(in.readUByte(), in.readShort()) - case _ => - } - - def sendPartAdded(part: CircuitPart) { - val out = network.getICStreamOf(1) - out.writeByte(part.id) - out.writeByte(part.x).writeByte(part.y) - part.writeDesc(out) - } - - def sendRemovePart(x: Int, y: Int) { - network.getICStreamOf(2).writeByte(x).writeByte(y) - } - - def sendOpUse(op: CircuitOp, start: Point, end: Point) = { - if (op.checkOp(this, start, end)) { - op.writeOp(this, start, end, network.getICStreamOf(3).writeByte(op.id)) - true - } else false - } - - def sendClientPacket( - part: TClientNetCircuitPart, - writer: MCDataOutput => Unit - ) { - val s = network.getICStreamOf(4).writeByte(part.x).writeByte(part.y) - writer(s) - } - - def sendIOUpdate(r: Int) { - network.getICStreamOf(5).writeByte(r).writeInt(iostate(r)) - } - - def sendInputUpdate(r: Int) { - network.getICStreamOf(6).writeByte(r).writeShort(iostate(r) & 0xffff) - } - - def sendOutputUpdate(r: Int) { - network.getICStreamOf(7).writeByte(r).writeShort(iostate(r) >> 16) - } - - def clear() { - parts.values.foreach { _.unbind() } // remove references - parts = MMap() - scheduledTicks = MMap() - name = "untitled" - size = Size.zeroSize - for (i <- 0 until 4) iostate(i) = 0 - } - - def isEmpty = size == Size.zeroSize - def nonEmpty = !isEmpty - - private def assertCoords(x: Int, y: Int) { - if (!(0 until size.width contains x) || !(0 until size.height contains y)) - throw new IndexOutOfBoundsException( - "Circuit does not contain " + Point(x, y) - ) - } - - def tick() { - val t = network.getWorld.getTotalWorldTime - var rem = Seq[(Int, Int)]() - for ((k, v) <- scheduledTicks) if (v >= t) { - getPart(k._1, k._2).scheduledTick() - rem :+= k - } - rem.foreach(scheduledTicks.remove) - - for (part <- parts.values) part.update() - } - - def refreshErrors() { - val eparts = parts.values.collect { case p: IErrorCircuitPart => p } - val elist = Map.newBuilder[Point, (String, Int)] - - for (part <- eparts) { - val error = part.postErrors - if (error != null) - elist += Point(part.x, part.y) -> error - } - - errors = elist.result() - } - - def setPart(x: Int, y: Int, part: CircuitPart) { - setPart_do(x, y, part) - part.onAdded() - if (!network.isRemote) sendPartAdded(part) - } - private def setPart_do(x: Int, y: Int, part: CircuitPart) { - assertCoords(x, y) - part.bind(this, x, y) - parts += (x, y) -> part - } - - def getPart(x: Int, y: Int): CircuitPart = parts.getOrElse((x, y), null) - - def removePart(x: Int, y: Int) { - assertCoords(x, y) - val part = getPart(x, y) - if (part != null) { - if (!network.isRemote) sendRemovePart(x, y) - parts.remove((x, y)) - part.onRemoved() - part.unbind() - } - } - - def notifyNeighbor(x: Int, y: Int) { - val part = getPart(x, y) - if (part != null) part.onNeighborChanged() - } - - def notifyNeighbors(x: Int, y: Int, mask: Int) { - for (r <- 0 until 4) if ((mask & 1 << r) != 0) { - val point = Point(x, y).offset(r) - val part = getPart(point.x, point.y) - if (part != null) part.onNeighborChanged() - } - } - - def scheduleTick(x: Int, y: Int, ticks: Int) { - scheduledTicks += (x, y) -> (network.getWorld.getTotalWorldTime + ticks) - } - - // Convinience functions - def setPart(p: Point, part: CircuitPart) { setPart(p.x, p.y, part) } - def getPart(p: Point): CircuitPart = getPart(p.x, p.y) - def removePart(p: Point) { removePart(p.x, p.y) } - def notifyNeighbor(p: Point) { notifyNeighbor(p.x, p.y) } - def notifyNeighbors(p: Point, mask: Int) { notifyNeighbors(p.x, p.y, mask) } - def scheduleTick(p: Point, ticks: Int) { scheduleTick(p.x, p.y, ticks) } -} - -object CircuitPartDefs extends Enum { - type EnumVal = CircuitPartDef - - val Torch = CircuitPartDef(() => new TorchICPart) - val Lever = CircuitPartDef(() => new LeverICPart) - val Button = CircuitPartDef(() => new ButtonICPart) - - val AlloyWire = CircuitPartDef(() => new AlloyWireICPart) - val InsulatedWire = CircuitPartDef(() => new InsulatedWireICPart) - val BundledCable = CircuitPartDef(() => new BundledCableICPart) - - val IOGate = CircuitPartDef(() => new IOGateICPart) - val SimpleGate = CircuitPartDef(() => new ComboGateICPart) - val ComplexGate = CircuitPartDef(() => new SequentialGateICPart) - val ArrayGate = CircuitPartDef(() => new ArrayGateICPart) - - case class CircuitPartDef(factory: () => CircuitPart) extends Value { - def id = ordinal - override def name = s"$id" - - def createPart = factory.apply() - } -} - -object CircuitPart { - def createPart(id: Int) = CircuitPartDefs(id).createPart -} - -abstract class CircuitPart { - var world: IntegratedCircuit = null - var loc: (Byte, Byte) = null - - def bind(ic: IntegratedCircuit, x: Int, y: Int) { - world = ic - loc = (x.toByte, y.toByte) - } - - def unbind() { - world = null - loc = null - } - - def x = loc._1 & 0xff - def y = loc._2 & 0xff - def id = getPartType.id - - def getPartType: CircuitPartDefs.CircuitPartDef - - def save(tag: NBTTagCompound) {} - def load(tag: NBTTagCompound) {} - - def writeDesc(out: MCDataOutput) {} - def readDesc(in: MCDataInput) {} - - def writeStreamOf(key: Int): MCDataOutput = - world.network.getPartStream(x, y).writeByte(key) - def read(in: MCDataInput) { read(in, in.readUByte()) } - def read(in: MCDataInput, key: Int) = key match { - case 0 => readDesc(in) - case _ => - } - - def sendDescUpdate() { writeDesc(writeStreamOf(0)) } - - def update() {} - def scheduledTick() {} - def scheduleTick(ticks: Int) { world.scheduleTick(x, y, ticks) } - - def onAdded() {} - def onRemoved() {} - - def onNeighborChanged() {} - - @SideOnly(Side.CLIENT) - def onClicked() {} - @SideOnly(Side.CLIENT) - def onActivated() {} - - @SideOnly(Side.CLIENT) - def getPartName: String - @SideOnly(Side.CLIENT) - def getPickOp: CircuitOp = null - @SideOnly(Side.CLIENT) - def getRolloverData(detailLevel: Int): Seq[String] = - if (detailLevel > 0) Seq(getPartName) else Seq.empty - - @SideOnly(Side.CLIENT) - def renderDynamic(t: Transformation, ortho: Boolean, frame: Float) {} -} - -trait TClientNetCircuitPart extends CircuitPart { - def readClientPacket(in: MCDataInput) - - @SideOnly(Side.CLIENT) - def sendClientPacket(writer: MCDataOutput => Unit = { _ => }) { - world.sendClientPacket(this, writer) - } -} - -trait IErrorCircuitPart extends CircuitPart { - def postErrors: (String, Int) // (message, colour) -} - -trait IGuiCircuitPart extends TClientNetCircuitPart { - @SideOnly(Side.CLIENT) - def createGui: CircuitGui -} - -trait IPoweredCircuitPart { - def rsOutputLevel(r: Int): Int - def canConnectRS(r: Int): Boolean -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/icguis.scala b/src/main/scala/mrtjp/projectred/fabrication/icguis.scala deleted file mode 100644 index d5f2109f1..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/icguis.scala +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.gui.GuiDraw -import codechicken.lib.vec.Translation -import mrtjp.core.color.Colors -import mrtjp.core.gui.{GuiLib, MCButtonNode, TNode} -import mrtjp.core.vec.{Point, Rect, Size} -import net.minecraft.client.gui.Gui -import org.lwjgl.input.Keyboard -import org.lwjgl.opengl.GL11 - -class CircuitGui(val part: IGuiCircuitPart) extends Gui with TNode { - var size = Size.zeroSize - override def frame = Rect(position, size) - - var lineColor = Colors.LIME.argb(0xaa) - var linePointerCalc = { () => Point.zeroPoint } - - private def moverFrame = Rect(position + Point(4, 9), Size(4, 6)) - private var mouseDown = false - private var mouseInit = Point.zeroPoint - - { - val close = new MCButtonNode - close.position = Point(4, 4) - close.size = Size(5, 5) - close.clickDelegate = { () => removeFromParent() } - addChild(close) - } - - override def frameUpdate_Impl(mouse: Point, rframe: Float) { - if (mouseDown) { - position += mouse - mouseInit - mouseInit = mouse - } - - if (part.world == null) removeFromParent() - } - - override def drawBack_Impl(mouse: Point, rframe: Float) { - GuiLib.drawGuiBox(position.x, position.y, size.width, size.height, 0) - GuiDraw.drawRect( - moverFrame.x, - moverFrame.y, - moverFrame.width, - moverFrame.height, - Colors.LIGHT_GREY.argb - ) - } - - override def drawFront_Impl(mouse: Point, rframe: Float) { - val from = linePointerCalc() - val to = from.clamp(frame) - GL11.glColor4d(1, 1, 1, 1) - GuiLib.drawLine(from.x, from.y, to.x, to.y, lineColor) - GuiDraw.drawRect(to.x - 3, to.y - 3, 6, 6, lineColor) - } - - override def mouseClicked_Impl( - p: Point, - button: Int, - consumed: Boolean - ): Boolean = { - if (parent == null) - false // we cant check for consume here, so manually check if closed - else - hitTest(p).find(_.isInstanceOf[CircuitGui]) match { - case Some(gui) if gui == this => - val guis = parent.childrenByZ.collect { case g: CircuitGui => g } - val otherGuis = guis.filter(_ != this) - for (i <- otherGuis.indices) - otherGuis(i).pushZTo(0.1 * i) - pushZTo(0.1 * otherGuis.size) - - if (moverFrame.contains(p)) { - mouseDown = true - mouseInit = p - } - true - case _ => false - } - } - - override def mouseReleased_Impl(p: Point, button: Int, consumed: Boolean) = { - mouseDown = false - false - } - - override def keyPressed_Impl(c: Char, keycode: Int, consumed: Boolean) = - if (!consumed && keycode == Keyboard.KEY_ESCAPE) { - removeFromParent() - true - } else false -} - -trait TGateGui extends CircuitGui { - var gateRenderSize = Size(40, 40) - var gateRenderX = 10 - - def gate: GateICPart - - abstract override def drawBack_Impl(mouse: Point, rframe: Float) { - super.drawBack_Impl(mouse, rframe) - - RenderICGate.renderDynamic( - gate, - ICComponentStore - .orthoGridT(gateRenderSize.width, gateRenderSize.height) `with` - new Translation( - position.x + gateRenderX, - position.y + (size / 2 - gateRenderSize / 2).height, - 0 - ), - true, - rframe - ) - } -} - -class ICGateGui(override val gate: GateICPart) - extends CircuitGui(gate) - with TGateGui { - { - size = Size(120, 55) - - val rotate = new MCButtonNode - rotate.position = Point(58, 12) - rotate.size = Size(50, 15) - rotate.text = "rotate" - rotate.clickDelegate = { () => gate.sendClientPacket(_.writeByte(0)) } - addChild(rotate) - - val conf = new MCButtonNode - conf.position = Point(58, 28) - conf.size = Size(50, 15) - conf.text = "configure" - conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } - addChild(conf) - } -} - -class ICTimerGateGui(override val gate: SequentialGateICPart) - extends CircuitGui(gate) - with TGateGui { - { - size = Size(160, 80) - - val ax = 54 - val aw = 50 - val ah = 15 - - val rotate = new MCButtonNode - rotate.position = Point(ax, 5) - rotate.size = Size(aw, ah) - rotate.text = "rotate" - rotate.clickDelegate = { () => gate.sendClientPacket(_.writeByte(0)) } - addChild(rotate) - - val conf = new MCButtonNode - conf.position = Point(ax + aw + 1, 5) - conf.size = Size(aw, ah) - conf.text = "configure" - conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } - addChild(conf) - - def createButton(x: Int, y: Int, w: Int, h: Int, text: String, delta: Int) { - val b = new MCButtonNode - b.position = Point(x, y) - b.size = Size(w, h) - b.text = text - b.clickDelegate = { () => - gate.sendClientPacket(_.writeByte(3).writeShort(delta)) - } - addChild(b) - } - - val bw = 32 - val bh = 12 - val r1x = 69 - val r2x = r1x + 35 - val by = 34 - val bdy = 14 - - createButton(r1x, by + (0 * bdy), bw, bh, "-50ms", -1) - createButton(r1x, by + (1 * bdy), bw, bh, "-1s", -20) - createButton(r1x, by + (2 * bdy), bw, bh, "-10s", -200) - - createButton(r2x, by + (0 * bdy), bw, bh, "+50ms", 1) - createButton(r2x, by + (1 * bdy), bw, bh, "+1s", 20) - createButton(r2x, by + (2 * bdy), bw, bh, "+10s", 200) - } - - def getLogic = gate.getLogic[ITimerGuiLogic] - - override def drawBack_Impl(mouse: Point, rframe: Float) { - super.drawBack_Impl(mouse, rframe) - val s = "Interval: " + "%.2f".format(getLogic.getTimerMax * 0.05) + "s" - GuiDraw.drawStringC( - s, - position.x + 102, - position.y + 24, - Colors.GREY.argb, - false - ) - } -} - -class ICCounterGateGui(override val gate: SequentialGateICPart) - extends CircuitGui(gate) - with TGateGui { - var valID = 0 - - { - size = Size(160, 94) - - val ax = 54 - val aw = 50 - val ah = 15 - - val rotate = new MCButtonNode - rotate.position = Point(ax, 5) - rotate.size = Size(aw, ah) - rotate.text = "rotate" - rotate.clickDelegate = { () => gate.sendClientPacket(_.writeByte(0)) } - addChild(rotate) - - val conf = new MCButtonNode - conf.position = Point(ax + aw + 1, 5) - conf.size = Size(aw, ah) - conf.text = "configure" - conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } - addChild(conf) - - val sw = new MCButtonNode - sw.position = Point(54, 28) - sw.size = Size(20, 12) - sw.text = "var" - sw.clickDelegate = { () => valID = (valID + 1) % 3 } - addChild(sw) - - def createButton(x: Int, y: Int, w: Int, h: Int, delta: Int) { - val b = new MCButtonNode - b.position = Point(x, y) - b.size = Size(w, h) - b.text = (if (delta < 0) "" else "+") + delta - b.clickDelegate = { () => - gate.sendClientPacket(_.writeByte(4).writeByte(valID).writeShort(delta)) - } - addChild(b) - } - - val bw = 32 - val bh = 12 - val r1x = 69 - val r2x = r1x + 35 - val by = 48 - val bdy = 14 - - createButton(r1x, by + (0 * bdy), bw, bh, -1) - createButton(r1x, by + (1 * bdy), bw, bh, -5) - createButton(r1x, by + (2 * bdy), bw, bh, -10) - - createButton(r2x, by + (0 * bdy), bw, bh, 1) - createButton(r2x, by + (1 * bdy), bw, bh, 5) - createButton(r2x, by + (2 * bdy), bw, bh, 10) - } - - def getLogic = gate.getLogic[ICounterGuiLogic] - - override def drawBack_Impl(mouse: Point, rframe: Float) { - super.drawBack_Impl(mouse, rframe) - val s = "State: " + getLogic.getCounterValue - GuiDraw.drawStringC( - s, - position.x + 102, - position.y + 24, - Colors.GREY.argb, - false - ) - - val m = valID match { - case 0 => "Max: " + getLogic.getCounterMax - case 1 => "Incr: " + getLogic.getCounterIncr - case 2 => "Decr: " + getLogic.getCounterDecr - } - GuiDraw.drawStringC( - m, - position.x + 102, - position.y + 36, - Colors.GREY.argb, - false - ) - } -} - -class ICIOGateGui(override val gate: IOGateICPart) - extends CircuitGui(gate) - with TGateGui { - { - size = Size(124, 55) - - val conf = new MCButtonNode - conf.position = Point(62, 33) - conf.size = Size(46, 15) - conf.text = "io mode" - conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } - addChild(conf) - } - - override def drawBack_Impl(mouse: Point, rframe: Float) { - super.drawBack_Impl(mouse, rframe) - - GuiDraw.drawStringC( - gate.shape match { - case 0 => "input" - case 1 => "output" - case 2 => "inout" - }, - position.x + 85, - position.y + 16, - Colors.GREY.argb, - false - ) - } -} - -class ICIOFreqGateGui(override val gate: IOGateICPart) - extends CircuitGui(gate) - with TGateGui { - { - size = Size(138, 55) - - val conf = new MCButtonNode - conf.position = Point(52, 7) - conf.size = Size(46, 15) - conf.text = "io mode" - conf.clickDelegate = { () => gate.sendClientPacket(_.writeByte(1)) } - addChild(conf) - - val minus = new MCButtonNode - minus.position = Point(52, 33) - minus.size = Size(14, 14) - minus.text = "-" - minus.clickDelegate = { () => gate.sendClientPacket(_.writeByte(6)) } - addChild(minus) - - val plus = new MCButtonNode - plus.position = Point(117, 33) - plus.size = Size(14, 14) - plus.text = "+" - plus.clickDelegate = { () => gate.sendClientPacket(_.writeByte(5)) } - addChild(plus) - } - - override def drawBack_Impl(mouse: Point, rframe: Float) { - super.drawBack_Impl(mouse, rframe) - - GuiDraw.drawStringC( - gate.shape match { - case 0 => "input" - case 1 => "output" - case 2 => "inout" - }, - position.x + 117, - position.y + 11, - Colors.GREY.argb, - false - ) - - GuiDraw.drawStringC( - "freq", - position.x + 66, - position.y + 22, - 50, - 14, - Colors.GREY.argb, - false - ) - GuiDraw.drawStringC( - gate.getLogic[TFreqIOICGateLogic].getFreqName, - position.x + 66, - position.y + 33, - 50, - 14, - Colors.GREY.argb, - false - ) - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/icrenders.scala b/src/main/scala/mrtjp/projectred/fabrication/icrenders.scala deleted file mode 100644 index 18254e2f8..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/icrenders.scala +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.render.uv.{IconTransformation, UVScale} -import codechicken.lib.render.{CCModel, CCRenderState, ColourMultiplier} -import codechicken.lib.vec._ -import mrtjp.core.color.Colors -import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.texture.IIconRegister -import net.minecraft.util.ResourceLocation -import org.lwjgl.opengl.GL11 -import org.lwjgl.opengl.GL11._ - -import scala.collection.JavaConversions._ - -object RenderCircuit { - def registerIcons(reg: IIconRegister) { - ICComponentStore.registerIcons(reg) - } - - def renderOrtho( - circuit: IntegratedCircuit, - x: Double, - y: Double, - xSize: Double, - ySize: Double, - frame: Float - ) { - val t = - ICComponentStore.orthoGridT(xSize, ySize) `with` new Translation(x, y, 0) - renderBoard(circuit, t, true) - renderCircuit(circuit, t, true, frame) - } - - def renderDynamic( - circuit: IntegratedCircuit, - t: Transformation, - frame: Float - ) { - glDisable(GL_DEPTH_TEST) - renderBoard(circuit, t, true) - renderCircuit(circuit, t, true, frame) - glEnable(GL_DEPTH_TEST) - } - - def renderBoard( - circuit: IntegratedCircuit, - t: Transformation, - ortho: Boolean - ) { - PrefboardRenderer.render(circuit, t, ortho) - } - - def renderCircuit( - circuit: IntegratedCircuit, - t: Transformation, - ortho: Boolean, - frame: Float - ) { - for (((x, y), part) <- circuit.parts) { - val tlist = new TransformationList( - new Scale(1.0 / circuit.size.width, 1, 1.0 / circuit.size.height), - new Translation( - x * 1.0 / circuit.size.width, - 0, - y * 1.0 / circuit.size.height - ), - t - ) - part.renderDynamic(tlist, ortho, frame) - } - } -} - -import mrtjp.projectred.fabrication.ICComponentStore._ -object PrefboardRenderer { - private var boardModels = Map[(Int, Int), Seq[CCModel]]() - private var cornerModels = Map[(Int, Int), Seq[CCModel]]() - private var edgeModels = Map[(Int, Int), Seq[CCModel]]() - - private def createBoardModel(w: Int, h: Int): Seq[CCModel] = - faceModels.map(_.copy.apply(new UVScale(w, h))) - - private def createCornerModel(w: Int, h: Int): Seq[CCModel] = { - val corners = Seq((0, 0), (0, h - 1), (w - 1, h - 1), (w - 1, 0)).map { - pair => - new TransformationList( - new Scale(1.0 / w, 1, 1.0 / h), - new Translation(pair._1 * 1.0 / w, 0, pair._2 * 1.0 / h) - ) - } - - faceModels.map { m => - var models = Seq[CCModel]() - for (t <- corners) - models :+= m.copy.apply(t) - CCModel.combine(models) - } - } - - private def createEdgeModel(w: Int, h: Int): Seq[CCModel] = { - val edges = - Seq((0, 0, 1, h), (0, 0, w, 1), (w - 1, 0, 1, h), (0, h - 1, w, 1)).map { - pair => - ( - new TransformationList( - new Scale(1.0 / w, 1, 1.0 / h), - new Scale(pair._3, 1, pair._4), - new Translation(pair._1 * 1.0 / w, 0, pair._2 * 1.0 / h) - ), - new UVScale(pair._3, pair._4) - ) - } - - faceModels.map { m => - var models = Seq[CCModel]() - for ((t, uvt) <- edges) - models :+= m.copy.apply(t).apply(uvt) - CCModel.combine(models) - } - } - - private def getBoardModel(w: Int, h: Int) = { - if (!boardModels.contains((w, h))) - boardModels += (w, h) -> createBoardModel(w, h) - boardModels((w, h)) - } - - private def getCornerModel(w: Int, h: Int) = { - if (!cornerModels.contains((w, h))) - cornerModels += (w, h) -> createCornerModel(w, h) - cornerModels((w, h)) - } - - private def getEdgeModel(w: Int, h: Int) = { - if (!edgeModels.contains((w, h))) - edgeModels += (w, h) -> createEdgeModel(w, h) - edgeModels((w, h)) - } - - def render(circuit: IntegratedCircuit, t: Transformation, ortho: Boolean) { - val w = circuit.size.width - val h = circuit.size.height - - def bind(s: String) { - val r = new ResourceLocation( - "projectred", - "textures/blocks/fabrication/" + s + ".png" - ) - Minecraft.getMinecraft.getTextureManager.bindTexture(r) - } - val state = CCRenderState.instance - state.resetInstance() - state.pullLightmapInstance() - state.setDynamicInstance() - - for ( - (tex, models) <- Seq( - ("prefboard", getBoardModel(w, h)), - ("prefboard_edge", getEdgeModel(w, h)), - ("prefboard_corner", getCornerModel(w, h)) - ) - ) { - bind(tex) - state.startDrawingInstance() - models(if (ortho) 1 else 0).render(t) - state.drawInstance() - } - } -} - -object RenderICAlloyWire { - var connMap: Byte = 0 - var signal: Byte = 0 - - def prepairInv() { - connMap = 0xf - signal = 0xff.toByte - } - - def prepairDynamic(part: AlloyWireICPart) { - connMap = part.connMap - signal = part.signal - } - - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)).render( - t, - new IconTransformation(redwireIcons(connMap & 0xff)), - ColourMultiplier.instance((signal & 0xff) / 2 + 60 << 24 | 0xff) - ) - finishRender() - } -} - -object RenderICInsulatedWire { - var connMap: Byte = 0 - var signal: Byte = 0 - var colour: Byte = 0 - - def prepairInv(c: Int) { - connMap = 0xf - signal = 255.toByte - colour = c.toByte - } - - def prepairDynamic(part: InsulatedWireICPart) { - connMap = part.connMap - signal = part.signal - colour = part.colour - } - - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)).render( - t, - new IconTransformation(redwireIcons(connMap & 0xff)), - ColourMultiplier.instance((signal & 0xff) / 2 + 60 << 24 | 0xff) - ) - faceModels(dynamicIdx(0, ortho)).render( - t, - new IconTransformation(insulatedwireIcons(connMap & 0xff)), - ColourMultiplier.instance(Colors(colour & 0xff).rgba) - ) - finishRender() - } -} - -object RenderICBundledCable { - var connMap: Byte = 0 - var colour: Byte = 0 - - def prepairInv(c: Int) { - connMap = 0xf - colour = c.toByte - } - - def prepairDynamic(part: BundledCableICPart) { - connMap = part.connMap - colour = part.colour - } - - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)) - .render(t, new IconTransformation(bundledwireIcons(connMap & 0xff))) - if (colour != -1) - faceModels(dynamicIdx(0, ortho)).render( - t, - new IconTransformation(bundledColourIcon), - ColourMultiplier.instance(Colors(colour & 0xff).rgba) - ) - finishRender() - } -} - -object RenderICTorch { - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)) - .render(t, new IconTransformation(torchOnIcon)) - finishRender() - } -} - -object RenderICLever { - var on = false - - def prepairInv() { - on = false - } - - def prepairDynamic(part: LeverICPart) { - on = part.on - } - - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)) - .render(t, new IconTransformation(if (on) leverOnIcon else leverOffIcon)) - finishRender() - } -} - -object RenderICButton { - var on = false - - def prepairInv() { - on = false - } - - def prepairDynamic(part: ButtonICPart) { - on = part.on - } - - def render(t: Transformation, ortho: Boolean) { - prepairRender() - faceModels(dynamicIdx(0, ortho)).render( - t, - new IconTransformation(if (on) buttonOnIcon else buttonOffIcon) - ) - finishRender() - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/op.scala b/src/main/scala/mrtjp/projectred/fabrication/op.scala deleted file mode 100644 index 99eea3676..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/op.scala +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.gui.GuiDraw -import codechicken.lib.vec.{Transformation, Translation} -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.util.Enum -import mrtjp.core.vec.{Point, Size} -import mrtjp.projectred.fabrication.CircuitOp._ -import mrtjp.projectred.fabrication.ICComponentStore._ - -object CircuitOpDefs extends Enum { - type EnumVal = OpDef - - // tools - val Erase = OpDef(new CircuitOpErase) - - // primitives - val Torch = OpDef(new CircuitOpTorch) - val Lever = OpDef(new CircuitOpLever) - val Button = OpDef(new CircuitOpButton) - - // alloy wire - val AlloyWire = OpDef(new OpAlloyWire) - - // insulated wires - val WhiteInsulatedWire = OpDef(new OpInsulatedWire(0)) - val OrangeInsulatedWire = OpDef(new OpInsulatedWire(1)) - val MagentaInsulatedWire = OpDef(new OpInsulatedWire(2)) - val LightBlueInsulatedWire = OpDef(new OpInsulatedWire(3)) - val YellowInsulatedWire = OpDef(new OpInsulatedWire(4)) - val LimeInsulatedWire = OpDef(new OpInsulatedWire(5)) - val PinkInsulatedWire = OpDef(new OpInsulatedWire(6)) - val GreyInsulatedWire = OpDef(new OpInsulatedWire(7)) - val LightGreyInsulatedWire = OpDef(new OpInsulatedWire(8)) - val CyanInsulatedWire = OpDef(new OpInsulatedWire(9)) - val PurpleInsulatedWire = OpDef(new OpInsulatedWire(10)) - val BlueInsulatedWire = OpDef(new OpInsulatedWire(11)) - val BrownInsulatedWire = OpDef(new OpInsulatedWire(12)) - val GreenInsulatedWire = OpDef(new OpInsulatedWire(13)) - val RedInsulatedWire = OpDef(new OpInsulatedWire(14)) - val BlackInsulatedWire = OpDef(new OpInsulatedWire(15)) - - // bundled cables - val NeutralBundledCable = OpDef(new OpBundledCable(-1)) - val WhiteBundledCable = OpDef(new OpBundledCable(0)) - val OrangeBundledCable = OpDef(new OpBundledCable(1)) - val MagentaBundledCable = OpDef(new OpBundledCable(2)) - val LightBlueBundledCable = OpDef(new OpBundledCable(3)) - val YellowBundledCable = OpDef(new OpBundledCable(4)) - val LimeBundledCable = OpDef(new OpBundledCable(5)) - val PinkBundledCable = OpDef(new OpBundledCable(6)) - val GreyBundledCable = OpDef(new OpBundledCable(7)) - val LightGreyBundledCable = OpDef(new OpBundledCable(8)) - val CyanBundledCable = OpDef(new OpBundledCable(9)) - val PurpleBundledCable = OpDef(new OpBundledCable(10)) - val BlueBundledCable = OpDef(new OpBundledCable(11)) - val BrownBundledCable = OpDef(new OpBundledCable(12)) - val GreenBundledCable = OpDef(new OpBundledCable(13)) - val RedBundledCable = OpDef(new OpBundledCable(14)) - val BlackBundledCable = OpDef(new OpBundledCable(15)) - - // ios - val SimpleIO = OpDef(new OpIOGate(ICGateDefinition.IOSimple.ordinal)) - val AnalogIO = OpDef(new OpIOGate(ICGateDefinition.IOAnalog.ordinal)) - val BundledIO = OpDef(new OpIOGate(ICGateDefinition.IOBundled.ordinal)) - - // gates - val ORGate = OpDef(new OpGate(ICGateDefinition.OR.ordinal)) - val NORGate = OpDef(new OpGate(ICGateDefinition.NOR.ordinal)) - val NOTGate = OpDef(new OpGate(ICGateDefinition.NOT.ordinal)) - val ANDGate = OpDef(new OpGate(ICGateDefinition.AND.ordinal)) - val NANDGate = OpDef(new OpGate(ICGateDefinition.NAND.ordinal)) - val XORGate = OpDef(new OpGate(ICGateDefinition.XOR.ordinal)) - val XNORGate = OpDef(new OpGate(ICGateDefinition.XNOR.ordinal)) - val BufferGate = OpDef(new OpGate(ICGateDefinition.Buffer.ordinal)) - val MultiplexerGate = OpDef(new OpGate(ICGateDefinition.Multiplexer.ordinal)) - val PulseFormerGate = OpDef(new OpGate(ICGateDefinition.Pulse.ordinal)) - val RepeaterGate = OpDef(new OpGate(ICGateDefinition.Repeater.ordinal)) - val RandomizerGate = OpDef(new OpGate(ICGateDefinition.Randomizer.ordinal)) - val SRLatchGate = OpDef(new OpGate(ICGateDefinition.SRLatch.ordinal)) - val ToggleLatchGate = OpDef(new OpGate(ICGateDefinition.ToggleLatch.ordinal)) - val TransparentLatchGate = OpDef( - new OpGate(ICGateDefinition.TransparentLatch.ordinal) - ) - val TimerGate = OpDef(new OpGate(ICGateDefinition.Timer.ordinal)) - val SequencerGate = OpDef(new OpGate(ICGateDefinition.Sequencer.ordinal)) - val CounterGate = OpDef(new OpGate(ICGateDefinition.Counter.ordinal)) - val StateCellGate = OpDef(new OpGate(ICGateDefinition.StateCell.ordinal)) - val SynchronizerGate = OpDef( - new OpGate(ICGateDefinition.Synchronizer.ordinal) - ) - val DecRandomizerGate = OpDef( - new OpGate(ICGateDefinition.DecRandomizer.ordinal) - ) - val NullCellGate = OpDef(new OpGate(ICGateDefinition.NullCell.ordinal)) - val InvertCellGate = OpDef(new OpGate(ICGateDefinition.InvertCell.ordinal)) - val BufferCellGate = OpDef(new OpGate(ICGateDefinition.BufferCell.ordinal)) - - val INSULATED = WhiteInsulatedWire to BlackInsulatedWire toArray - val BUNDLED = NeutralBundledCable to BlackBundledCable toArray - - case class OpDef(op: CircuitOp) extends Value { - op.id = ordinal - - override def name = "op[" + ordinal + "]" - - def getID = ordinal - def getOp = op - } -} - -object CircuitOp { - def getOperation(id: Int) = CircuitOpDefs(id).getOp - - def renderHolo( - x: Double, - y: Double, - xSize: Double, - ySize: Double, - csize: Size, - point: Point, - colour: Int - ) { - val x1 = (x + xSize / csize.width * point.x).toInt - val y1 = (y + ySize / csize.height * point.y).toInt - val x2 = (x + xSize / csize.width * (point.x + 1)).toInt - val y2 = (y + ySize / csize.height * (point.y + 1)).toInt - - GuiDraw.drawRect(x1, y1, x2 - x1, y2 - y1, colour) - } - - def isOnBorder(cSize: Size, point: Point) = - point.x == 0 || point.y == 0 || point.x == cSize.width - 1 || point.y == cSize.height - 1 - - def isOnEdge(cSize: Size, point: Point) = - point == Point(0, 0) || point == Point( - 0, - cSize.height - 1 - ) || point == Point(cSize.width - 1, 0) || point == Point( - cSize.width - 1, - cSize.height - 1 - ) -} - -trait CircuitOp { - var id = -1 - - def checkOp(circuit: IntegratedCircuit, start: Point, end: Point): Boolean - - def writeOp( - circuit: IntegratedCircuit, - start: Point, - end: Point, - out: MCDataOutput - ) - def readOp(circuit: IntegratedCircuit, in: MCDataInput) - - @SideOnly(Side.CLIENT) - def getOpName: String - @SideOnly(Side.CLIENT) - def renderHover( - circuit: IntegratedCircuit, - point: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) - @SideOnly(Side.CLIENT) - def renderDrag( - circuit: IntegratedCircuit, - start: Point, - end: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) - @SideOnly(Side.CLIENT) - def renderImage(x: Double, y: Double, width: Double, height: Double) -} - -abstract class SimplePlacementOp extends CircuitOp { - override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = - circuit.getPart(end.x, end.y) == null - - override def writeOp( - circuit: IntegratedCircuit, - start: Point, - end: Point, - out: MCDataOutput - ) { - out.writeByte(end.x).writeByte(end.y) - } - - override def readOp(circuit: IntegratedCircuit, in: MCDataInput) { - val point = Point(in.readUByte(), in.readUByte()) - if (circuit.getPart(point.x, point.y) == null) - circuit.setPart(point.x, point.y, createPart) - } - - @SideOnly(Side.CLIENT) - override def renderImage( - x: Double, - y: Double, - width: Double, - height: Double - ) { - val t = orthoGridT(width, height) `with` new Translation(x, y, 0) - doPartRender(t) - } - - @SideOnly(Side.CLIENT) - override def renderHover( - circuit: IntegratedCircuit, - point: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(point) != null) return - - renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - point, - if (!isOnBorder(circuit.size, point)) 0x33ffffff else 0x33ff0000 - ) - - val t = orthoPartT(x, y, xSize, ySize, circuit.size, point.x, point.y) - doPartRender(t) - - } - - @SideOnly(Side.CLIENT) - override def renderDrag( - circuit: IntegratedCircuit, - start: Point, - end: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(end) != null) return - - renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - end, - if (!isOnBorder(circuit.size, end)) 0x44ffffff else 0x44ff0000 - ) - - val t = orthoPartT(x, y, xSize, ySize, circuit.size, end.x, end.y) - doPartRender(t) - } - - def doPartRender(t: Transformation) - - def createPart: CircuitPart -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOp.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOp.scala new file mode 100644 index 000000000..2c92a4748 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOp.scala @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.gui.GuiDraw +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.fabrication.{IntegratedCircuit, RenderCircuit} + +/** Circuit Operations describe the communication between server and client: + * + * - 1: Client sends operation to the server with [[clientSendOperation]] + * - 2: Server receives operation with [[serverReceiveOperation]] and sends + * updates back to the client(s). The sending back is done in + * [[IntegratedCircuit]] + * - 3: Client(s) receive updated circuit. This step is handled in + * [[IntegratedCircuit]] + */ +trait CircuitOp { + var id = -1 + + /** Can this operation be executed + */ + def checkOp(circuit: IntegratedCircuit, start: Point, end: Point): Boolean + + def getRotation(): Int + + def getConfiguration(): Int + + def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ): Unit = { + out.writeByte(id) + } + + protected def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ): Unit + + /** Get unlocalized name + */ + @SideOnly(Side.CLIENT) + def getOpName: String + + /** Render the selected Operation, when on the mouse cursor + * @param position + * Position in Grid coordinates + * @param scale + * Prefboard scaling + */ + @SideOnly(Side.CLIENT) + def renderHover(position: Vec2, scale: Double, prefboardOffset: Vec2): Unit + + /** Render the selected Operation when dragging + * @param start + * Start in Grid coordinates + * @param end + * End in Grid coordinates + * @param positionsWithParts + * Positions in Rect(start, end) with existing parts + * @param scale + * Prefboard scaling + * @param prefboardOffset + * Prefboard offset + */ + @SideOnly(Side.CLIENT) + def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit + + /** Render the part, that will be placed by this operation + */ + @SideOnly(Side.CLIENT) + def renderImage(x: Double, y: Double, width: Double, height: Double) + + /** Same as renderImage, however it ignores configuration and rotation (e.g. + * toolbar) + */ + @SideOnly(Side.CLIENT) + def renderImageStatic( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = + renderImage(x, y, width, height) +} + +object CircuitOp { + + /** Read operation from stream and create Circuit Part in circuit + * @param circuit + * The circuit in which the part is being created + * @param in + * Stream + */ + def readOp(circuit: IntegratedCircuit, in: MCDataInput): Unit = { + getOperation(in.readUByte()).serverReceiveOperation(circuit, in) + } + + /** IDs as in CircuitOpDefs -> CircuitOp + */ + private def getOperation(id: Int): CircuitOp = CircuitOpDefs(id).getOp + + /** Draw a rectangle in the size of one tile + * @param position + * In Grid Coordinates + * @param colour + * in ARGB + */ + def renderHolo(position: Vec2, scale: Double, colour: Int): Unit = { + val start = position * RenderCircuit.BASE_SCALE * scale + val end = start + Vec2( + RenderCircuit.BASE_SCALE * scale, + RenderCircuit.BASE_SCALE * scale + ) + GuiDraw.drawRect( + start.dx.toInt, + start.dy.toInt, + (end - start).dx.toInt, + (end - start).dy.toInt, + colour + ) + } + + /** Same as other renderHolo, only for drawing a rectangle over multiple cells + * of the grid + * @param topLeft + * In Grid Coordinates + * @param bottomRight + * In Grid coordinates, excluding that cell + */ + def renderHolo( + topLeft: Vec2, + bottomRight: Vec2, + scale: Double, + colour: Int + ): Unit = { + val s = topLeft * RenderCircuit.BASE_SCALE * scale + val e = bottomRight * RenderCircuit.BASE_SCALE * scale + GuiDraw.drawRect( + s.dx.toInt, + s.dy.toInt, + (e - s).dx.toInt, + (e - s).dy.toInt, + colour + ) + } + + def partsBetweenPoints( + start: Vec2, + end: Vec2, + circuit: IntegratedCircuit + ): Seq[Vec2] = { + var partPositions: Seq[Vec2] = Seq.empty + for ( + x <- math.min(start.dx.toInt, end.dx.toInt) to math.max( + start.dx.toInt, + end.dx.toInt + ) + ) { + for ( + y <- math.min(start.dy.toInt, end.dy.toInt) to math.max( + start.dy.toInt, + end.dy.toInt + ) + ) { + if (circuit.getPart(x, y) != null) { + partPositions = partPositions :+ Vec2(x, y) + } + } + } + partPositions + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOpDefs.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOpDefs.scala new file mode 100644 index 000000000..b269098fb --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/CircuitOpDefs.scala @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import mrtjp.core.util.Enum +import mrtjp.projectred.fabrication.circuitparts.ICGateDefinition + +object CircuitOpDefs extends Enum { + type EnumVal = OpDef + + // tools + val Erase = OpDef(new OpErase) + val Cut = OpDef(new OpCut) + val Copy = OpDef(new OpCopy) + val Paste = OpDef(new OpPaste) + + // primitives + val Torch = OpDef(new OpTorch) + val Lever = OpDef(new OpLever) + val Button = OpDef(new OpButton) + + // alloy wire + val AlloyWire = OpDef(new OpAlloyWire) + + // insulated wires + val WhiteInsulatedWire = OpDef(new OpInsulatedWire(0)) + val OrangeInsulatedWire = OpDef(new OpInsulatedWire(1)) + val MagentaInsulatedWire = OpDef(new OpInsulatedWire(2)) + val LightBlueInsulatedWire = OpDef(new OpInsulatedWire(3)) + val YellowInsulatedWire = OpDef(new OpInsulatedWire(4)) + val LimeInsulatedWire = OpDef(new OpInsulatedWire(5)) + val PinkInsulatedWire = OpDef(new OpInsulatedWire(6)) + val GreyInsulatedWire = OpDef(new OpInsulatedWire(7)) + val LightGreyInsulatedWire = OpDef(new OpInsulatedWire(8)) + val CyanInsulatedWire = OpDef(new OpInsulatedWire(9)) + val PurpleInsulatedWire = OpDef(new OpInsulatedWire(10)) + val BlueInsulatedWire = OpDef(new OpInsulatedWire(11)) + val BrownInsulatedWire = OpDef(new OpInsulatedWire(12)) + val GreenInsulatedWire = OpDef(new OpInsulatedWire(13)) + val RedInsulatedWire = OpDef(new OpInsulatedWire(14)) + val BlackInsulatedWire = OpDef(new OpInsulatedWire(15)) + + // bundled cables + val NeutralBundledCable = OpDef(new OpBundledCable(-1)) + val WhiteBundledCable = OpDef(new OpBundledCable(0)) + val OrangeBundledCable = OpDef(new OpBundledCable(1)) + val MagentaBundledCable = OpDef(new OpBundledCable(2)) + val LightBlueBundledCable = OpDef(new OpBundledCable(3)) + val YellowBundledCable = OpDef(new OpBundledCable(4)) + val LimeBundledCable = OpDef(new OpBundledCable(5)) + val PinkBundledCable = OpDef(new OpBundledCable(6)) + val GreyBundledCable = OpDef(new OpBundledCable(7)) + val LightGreyBundledCable = OpDef(new OpBundledCable(8)) + val CyanBundledCable = OpDef(new OpBundledCable(9)) + val PurpleBundledCable = OpDef(new OpBundledCable(10)) + val BlueBundledCable = OpDef(new OpBundledCable(11)) + val BrownBundledCable = OpDef(new OpBundledCable(12)) + val GreenBundledCable = OpDef(new OpBundledCable(13)) + val RedBundledCable = OpDef(new OpBundledCable(14)) + val BlackBundledCable = OpDef(new OpBundledCable(15)) + + // ios + val SimpleIO = OpDef(new OpGate(ICGateDefinition.IOSimple.ordinal)) + val AnalogIO = OpDef(new OpGate(ICGateDefinition.IOAnalog.ordinal)) + val BundledIO = OpDef(new OpGate(ICGateDefinition.IOBundled.ordinal)) + + // gates + val ORGate = OpDef(new OpGate(ICGateDefinition.OR.ordinal)) + val NORGate = OpDef(new OpGate(ICGateDefinition.NOR.ordinal)) + val NOTGate = OpDef(new OpGate(ICGateDefinition.NOT.ordinal)) + val ANDGate = OpDef(new OpGate(ICGateDefinition.AND.ordinal)) + val NANDGate = OpDef(new OpGate(ICGateDefinition.NAND.ordinal)) + val XORGate = OpDef(new OpGate(ICGateDefinition.XOR.ordinal)) + val XNORGate = OpDef(new OpGate(ICGateDefinition.XNOR.ordinal)) + val BufferGate = OpDef(new OpGate(ICGateDefinition.Buffer.ordinal)) + val MultiplexerGate = OpDef(new OpGate(ICGateDefinition.Multiplexer.ordinal)) + val PulseFormerGate = OpDef(new OpGate(ICGateDefinition.Pulse.ordinal)) + val RepeaterGate = OpDef(new OpGate(ICGateDefinition.Repeater.ordinal)) + val RandomizerGate = OpDef(new OpGate(ICGateDefinition.Randomizer.ordinal)) + val SRLatchGate = OpDef(new OpGate(ICGateDefinition.SRLatch.ordinal)) + val ToggleLatchGate = OpDef(new OpGate(ICGateDefinition.ToggleLatch.ordinal)) + val TransparentLatchGate = OpDef( + new OpGate(ICGateDefinition.TransparentLatch.ordinal) + ) + val TimerGate = OpDef(new OpGate(ICGateDefinition.Timer.ordinal)) + val SequencerGate = OpDef(new OpGate(ICGateDefinition.Sequencer.ordinal)) + val CounterGate = OpDef(new OpGate(ICGateDefinition.Counter.ordinal)) + val StateCellGate = OpDef(new OpGate(ICGateDefinition.StateCell.ordinal)) + val SynchronizerGate = OpDef( + new OpGate(ICGateDefinition.Synchronizer.ordinal) + ) + val DecRandomizerGate = OpDef( + new OpGate(ICGateDefinition.DecRandomizer.ordinal) + ) + val NullCellGate = OpDef(new OpGate(ICGateDefinition.NullCell.ordinal)) + val InvertCellGate = OpDef(new OpGate(ICGateDefinition.InvertCell.ordinal)) + val BufferCellGate = OpDef(new OpGate(ICGateDefinition.BufferCell.ordinal)) + + val INSULATED = WhiteInsulatedWire to BlackInsulatedWire toArray + val BUNDLED = NeutralBundledCable to BlackBundledCable toArray + + case class OpDef(op: CircuitOp) extends Value { + op.id = ordinal + + override def name = "op[" + ordinal + "]" + + def getID = ordinal + def getOp = op + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpAreaBase.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpAreaBase.scala new file mode 100644 index 000000000..ceaa656ee --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpAreaBase.scala @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.render.uv.{UVScale, UVTranslation} +import codechicken.lib.vec.Translation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.ICComponentStore.{dynamicIdx, faceModels, finishRender, orthoGridT, prepairRender} +import mrtjp.projectred.fabrication.IntegratedCircuit +import mrtjp.projectred.fabrication.circuitparts.CircuitPart +import mrtjp.projectred.fabrication.operations.OpAreaBase.clipboard + +object OpAreaBase { + type List = Seq[(Point, CircuitOp)] + + /** clipboard for copy/past/cut operations + */ + var clipboard: List = Seq() + + /** Saves parts to [[OpAreaBase.clipboard]] + */ + def saveToClipboard(parts: Map[(Int, Int), CircuitPart]): Unit = { + val (x, y) = if (parts.nonEmpty) { + parts + .reduce((a, b) => + ((math.min(a._1._1, b._1._1), math.min(a._1._2, b._1._2)), null) + ) + ._1 + } else (0, 0) + OpAreaBase.clipboard = parts + .map(element => { + ( + Point(element._1._1 - x, element._1._2 - y), + element._2.getCircuitOperation + ) + }) + .toList + } +} + +abstract class OpAreaBase extends CircuitOp { + + override def checkOp( + circuit: IntegratedCircuit, + start: Point, + end: Point + ): Boolean = true + + override def getConfiguration(): Int = 0 + + override def getRotation(): Int = 0 + + /** Draw partially transparent rectangle over area + */ + @SideOnly(Side.CLIENT) + override def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + var (topLeft, bottomRight) = ( + Vec2( + math.min(start.dx, end.dx), + math.min(start.dy, end.dy) + ) - prefboardOffset, + Vec2( + math.max(start.dx, end.dx), + math.max(start.dy, end.dy) + ) - prefboardOffset + ) + bottomRight = bottomRight.add(1, 1) + CircuitOp.renderHolo(topLeft, bottomRight, scale, 0x44ffffff) + } + + protected def renderImage( + x: Double, + y: Double, + width: Double, + height: Double, + texTranslation: UVTranslation + ): Unit = { + val t = orthoGridT(width, height) `with` new Translation(x, y, 0) + + prepairRender() + PRResources.guiPrototyper.bind() + faceModels(dynamicIdx(0, true)).render( + t, + new UVScale(32) `with` texTranslation `with` new UVScale( + 1 / 512d + ) + ) + finishRender() + } + + def rotateClipboard(): Unit = { + if (clipboard.size > 1) { + val p2 = clipboard + .reduce((a, b) => + (Point(math.max(a._1.x, b._1.x), math.max(a._1.y, b._1.y)), null) + ) + ._1 + clipboard = clipboard.map { item => + ( + Point(-item._1.y + p2.y, item._1.x), + item._2 match { + case a: OpGate => + a.rotation = (a.rotation + 1) % 4 + a + case a => a + } + ) + }.toList + } + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpCopy.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpCopy.scala new file mode 100644 index 000000000..41223a0a0 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpCopy.scala @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.uv.UVTranslation +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.fabrication.IntegratedCircuit + +class OpCopy extends OpAreaBase { + + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ): Unit = { + // Save Parts in clipboard (only client) + val topLeft = Point(math.min(start.x, end.x), math.min(start.y, end.y)) + val bottomRight = Point(math.max(start.x, end.x), math.max(start.y, end.y)) + val parts = circuit.getParts(topLeft, bottomRight + Point(1, 1)) + OpAreaBase.saveToClipboard(parts) + super.clientSendOperation(circuit, start, end, out) + } + + // Nothing to process + override protected def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ): Unit = {} + + override def getOpName: String = "gui.projectred.fabrication.copy" + + override def renderHover( + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + // TODO + } + + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = { + renderImage(x, y, width, height, new UVTranslation(330, 104)) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpCut.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpCut.scala new file mode 100644 index 000000000..83099338c --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpCut.scala @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.MCDataOutput +import codechicken.lib.render.uv.UVTranslation +import mrtjp.core.vec.Point +import mrtjp.projectred.fabrication.IntegratedCircuit + +class OpCut extends OpErase { + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ): Unit = { + // Save Parts in clipboard (only client + val topLeft = Point(math.min(start.x, end.x), math.min(start.y, end.y)) + val bottomRight = Point(math.max(start.x, end.x), math.max(start.y, end.y)) + val parts = circuit.getParts(topLeft, bottomRight + Point(1, 1)) + OpAreaBase.saveToClipboard(parts) + // Delete parts + super.clientSendOperation(circuit, start, end, out) + } + + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = { + renderImage(x, y, width, height, new UVTranslation(330, 202)) + } + + override def getOpName: String = "gui.projectred.fabrication.cut" +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpErase.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpErase.scala new file mode 100644 index 000000000..49a732ece --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpErase.scala @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.uv.{UVScale, UVTranslation} +import codechicken.lib.vec.Translation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.core.libmc.PRResources +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication.IntegratedCircuit + +class OpErase extends OpAreaBase { + override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = + true + + override def getConfiguration(): Int = 0 + + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ) { + super.clientSendOperation(circuit, start, end, out) + out.writeInt(start.x).writeInt(start.y) + out.writeInt(end.x).writeInt(end.y) + } + + override def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ): Unit = { + val start = Point(in.readInt(), in.readInt()) + val end = Point(in.readInt(), in.readInt()) + + for (x <- math.min(start.x, end.x) to math.max(start.x, end.x)) + for (y <- math.min(start.y, end.y) to math.max(start.y, end.y)) + circuit.removePart(x, y) + } + + @SideOnly(Side.CLIENT) + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ) { + val t = orthoGridT(width, height) `with` new Translation(x, y, 0) + + prepairRender() + PRResources.guiPrototyper.bind() + faceModels(dynamicIdx(0, true)).render( + t, + new UVScale(16) `with` new UVTranslation(330, 18) `with` new UVScale( + 1 / 512d + ) + ) + finishRender() + } + + @SideOnly(Side.CLIENT) + override def renderHover( + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + CircuitOp.renderHolo(position - prefboardOffset, scale, 0x33ff0000) + } + + override def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + super.renderDrag(start, end, positionsWithParts, scale, prefboardOffset) + // Mark elements that are going to get removed + for (posWithPart <- positionsWithParts) { + CircuitOp.renderHolo(posWithPart - prefboardOffset, scale, 0x44ff0000) + } + } + + @SideOnly(Side.CLIENT) + override def getOpName = "gui.projectred.fabrication.erase" +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpGate.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpGate.scala new file mode 100644 index 000000000..a57d7ea27 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpGate.scala @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.vec.{Rotation, Transformation, Translation, Vector3} +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.{ + CircuitPart, + GateICPart, + ICGateDefinition, + ICGateRenderer +} +import mrtjp.projectred.fabrication.operations.CircuitOp.renderHolo + +class OpGate(meta: Int) extends CircuitOp { + + var rotation: Int = 0 + var configuration: Int = 0 + + def getID: Int = meta + + override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = + circuit.getPart(start) == null + + override def getRotation(): Int = rotation + + override def getConfiguration(): Int = configuration + + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ) { + super.clientSendOperation(circuit, start, end, out) + out.writeByte(start.x).writeByte(start.y) + out.writeByte(rotation) + out.writeByte(configuration) + } + + override def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ) { + val position = Point(in.readByte(), in.readByte()) + rotation = in.readUByte() + configuration = in.readUByte() + + if (circuit.getPart(position) == null) { + val part = CircuitPart + .createPart(ICGateDefinition(meta).gateType) + .asInstanceOf[GateICPart] + part.preparePlacement(rotation, configuration, meta) + circuit.setPart(position, part) + } + } + + @SideOnly(Side.CLIENT) + override def renderHover( + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + val t = orthoPartT(position.subtract(prefboardOffset), scale) + doRender(t, rotation, configuration) + renderHolo(position.subtract(prefboardOffset), scale, 0x33ffffff) + } + + @SideOnly(Side.CLIENT) + def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + // Gates can't be dragged, so only the first will be rendered + val t = orthoPartT(start - prefboardOffset, scale) + doRender(t, rotation, configuration) + renderHolo(start - prefboardOffset, scale, 0x44ffffff) + } + + @SideOnly(Side.CLIENT) + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ) { + val t = orthoGridT(width, height) `with` new Translation(x, y, 0) + doRender(t, rotation, configuration) + } + + override def renderImageStatic( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = { + val t = orthoGridT(width, height) `with` new Translation(x, y, 0) + doRender(t, 0, 0) + } + + @SideOnly(Side.CLIENT) + def doRender(t: Transformation, rot: Int, configuration: Int) { + ICGateRenderer.renderWithConfiguration( + configuration, + Rotation.quarterRotations(rot).at(Vector3.center) `with` t, + meta + ) + } + + @SideOnly(Side.CLIENT) + override def getOpName = ICGateDefinition(meta).unlocalized +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpPaste.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpPaste.scala new file mode 100644 index 000000000..76769930a --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpPaste.scala @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.render.uv.UVTranslation +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.fabrication.IntegratedCircuit + +class OpPaste extends OpAreaBase { + + override def checkOp( + circuit: IntegratedCircuit, + start: Point, + end: Point + ): Boolean = { + OpAreaBase.clipboard.forall(op => circuit.getPart(start + op._1) == null) + } + + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ): Unit = { + super.clientSendOperation(circuit, start, end, out) + out.writeInt(OpAreaBase.clipboard.size) + OpAreaBase.clipboard.foreach { op => + op._2.clientSendOperation(circuit, start + op._1, start + op._1, out) + } + } + + override protected def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ): Unit = { + for (_ <- 0 until in.readInt()) { + CircuitOp.readOp(circuit, in) + } + } + + override def getOpName: String = "gui.projectred.fabrication.paste" + + override def renderHover( + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + for (part <- OpAreaBase.clipboard) { + part._2.renderHover(position + part._1.vectorize, scale, prefboardOffset) + } + } + + override def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = + renderHover(start, scale, prefboardOffset) + + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = { + renderImage(x, y, width, height, new UVTranslation(330, 138)) + } +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpSimplePlacement.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpSimplePlacement.scala new file mode 100644 index 000000000..a0b3c29ef --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpSimplePlacement.scala @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.data.{MCDataInput, MCDataOutput} +import codechicken.lib.vec.{Transformation, Translation} +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.core.vec.{Point, Vec2} +import mrtjp.projectred.fabrication.ICComponentStore.{orthoGridT, orthoPartT} +import mrtjp.projectred.fabrication.IntegratedCircuit +import mrtjp.projectred.fabrication.circuitparts.CircuitPart +import mrtjp.projectred.fabrication.operations.CircuitOp.renderHolo + +abstract class OpSimplePlacement extends CircuitOp { + override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = + circuit.getPart(end.x, end.y) == null + + override def getRotation(): Int = 0 + + override def getConfiguration(): Int = 0 + + override def clientSendOperation( + circuit: IntegratedCircuit, + start: Point, + end: Point, + out: MCDataOutput + ) { + super.clientSendOperation(circuit, start, end, out) + out.writeInt(end.x).writeInt(end.y) + } + + override def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ) { + val point = Point(in.readInt(), in.readInt()) + if (circuit.getPart(point.x, point.y) == null) + circuit.setPart(point.x, point.y, createPart) + } + + @SideOnly(Side.CLIENT) + override def renderImage( + x: Double, + y: Double, + width: Double, + height: Double + ): Unit = { + val t = orthoGridT(width, height) `with` new Translation(x, y, 0) + doPartRender(t) + } + + @SideOnly(Side.CLIENT) + override def renderHover( + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + val t = orthoPartT(position - prefboardOffset, scale) + doPartRender(t) + renderHolo(position.subtract(prefboardOffset), scale, 0x33ff0000) + } + + @SideOnly(Side.CLIENT) + override def renderDrag( + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + val t = orthoPartT(end - prefboardOffset, scale) + doPartRender(t) + renderHolo(end - prefboardOffset, scale, 0x44ffffff) + } + + def doPartRender(t: Transformation) + + def createPart: CircuitPart +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/operations/OpsICPart.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpsICPart.scala new file mode 100644 index 000000000..64a6710d2 --- /dev/null +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpsICPart.scala @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015. + * Created by MrTJP. + * All rights reserved. + */ +package mrtjp.projectred.fabrication.operations + +import codechicken.lib.vec.Transformation +import cpw.mods.fml.relauncher.{Side, SideOnly} +import mrtjp.projectred.fabrication.circuitparts.CircuitPartDefs +import mrtjp.projectred.fabrication.circuitparts.wire.{ + RenderICButton, + RenderICLever, + RenderICTorch +} + +class OpTorch extends OpSimplePlacement { + override def doPartRender(t: Transformation) = RenderICTorch.render(t, true) + + override def createPart = CircuitPartDefs.Torch.createPart + + @SideOnly(Side.CLIENT) + override def getOpName = "tile.notGate.name" +} + +class OpButton extends OpSimplePlacement { + override def doPartRender(t: Transformation) { + RenderICButton.prepairInv() + RenderICButton.render(t, true) + } + + override def createPart = CircuitPartDefs.Button.createPart + + @SideOnly(Side.CLIENT) + override def getOpName = "tile.button.name" +} + +class OpLever extends OpSimplePlacement { + override def doPartRender(t: Transformation) { + RenderICLever.prepairInv() + RenderICLever.render(t, true) + } + + override def createPart = CircuitPartDefs.Lever.createPart + + @SideOnly(Side.CLIENT) + override def getOpName = "tile.lever.name" +} diff --git a/src/main/scala/mrtjp/projectred/fabrication/opwires.scala b/src/main/scala/mrtjp/projectred/fabrication/operations/OpsWire.scala similarity index 51% rename from src/main/scala/mrtjp/projectred/fabrication/opwires.scala rename to src/main/scala/mrtjp/projectred/fabrication/operations/OpsWire.scala index 410a82da0..4bfce8142 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/opwires.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/operations/OpsWire.scala @@ -3,110 +3,133 @@ * Created by MrTJP. * All rights reserved. */ -package mrtjp.projectred.fabrication +package mrtjp.projectred.fabrication.operations import codechicken.lib.data.{MCDataInput, MCDataOutput} import codechicken.lib.vec.{Transformation, Translation} import cpw.mods.fml.relauncher.{Side, SideOnly} import mrtjp.core.color.Colors -import mrtjp.core.vec.Point -import mrtjp.projectred.fabrication.CircuitOp._ +import mrtjp.core.vec.{Point, Vec2} import mrtjp.projectred.fabrication.ICComponentStore._ +import mrtjp.projectred.fabrication._ +import mrtjp.projectred.fabrication.circuitparts.wire._ +import mrtjp.projectred.fabrication.circuitparts.{CircuitPart, CircuitPartDefs} +import mrtjp.projectred.fabrication.operations.CircuitOp.renderHolo abstract class OpWire extends CircuitOp { override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = circuit.getPart(start.x, start.y) == null - override def writeOp( + override def getRotation(): Int = 0 + + override def getConfiguration(): Int = 0 + + override def clientSendOperation( circuit: IntegratedCircuit, start: Point, end: Point, out: MCDataOutput ) { - out.writeByte(start.x).writeByte(start.y) - out.writeByte(end.x).writeByte(end.y) + super.clientSendOperation(circuit, start, end, out) + out.writeInt(start.x).writeInt(start.y) + out.writeInt(end.x).writeInt(end.y) } - override def readOp(circuit: IntegratedCircuit, in: MCDataInput) { - val start = Point(in.readUByte(), in.readUByte()) - val end = Point(in.readUByte(), in.readUByte()) - val end2 = start + Point((end - start).vectorize.axialProject) - - for (px <- math.min(start.x, end2.x) to math.max(start.x, end2.x)) - for (py <- math.min(start.y, end2.y) to math.max(start.y, end2.y)) - if (!isOnBorder(circuit.size, Point(px, py))) - if (circuit.getPart(px, py) == null) - circuit.setPart(px, py, createPart) + override def serverReceiveOperation( + circuit: IntegratedCircuit, + in: MCDataInput + ) { + val start = Point(in.readInt(), in.readInt()) + val end = Point(in.readInt(), in.readInt()) + val corner = start + Point((end - start).vectorize.axialProject) + + for (x <- math.min(start.x, corner.x) to math.max(start.x, corner.x)) { + for (y <- math.min(start.y, corner.y) to math.max(start.y, corner.y)) { + if (circuit.getPart(x, y) == null) { + circuit.setPart(x, y, createPart) + } + } + } + for (x <- math.min(corner.x, end.x) to math.max(corner.x, end.x)) { + for (y <- math.min(corner.y, end.y) to math.max(corner.y, end.y)) { + if (circuit.getPart(x, y) == null) { + circuit.setPart(x, y, createPart) + } + } + } } def createPart: CircuitPart @SideOnly(Side.CLIENT) override def renderHover( - circuit: IntegratedCircuit, - point: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(point) != null) return - - renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - point, - if (isOnBorder(circuit.size, point)) 0x33ff0000 else 0x33ffffff - ) - - val t = orthoPartT(x, y, xSize, ySize, circuit.size, point.x, point.y) + position: Vec2, + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + val t = orthoPartT(position.subtract(prefboardOffset), scale) doRender(t, 0) + renderHolo(position.subtract(prefboardOffset), scale, 0x33ffffff) } @SideOnly(Side.CLIENT) override def renderDrag( - circuit: IntegratedCircuit, - start: Point, - end: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(start) != null) return - - val end2 = start + Point((end - start).vectorize.axialProject) - - for (px <- math.min(start.x, end2.x) to math.max(start.x, end2.x)) - for (py <- math.min(start.y, end2.y) to math.max(start.y, end2.y)) { - val point = Point(px, py) + start: Vec2, + end: Vec2, + positionsWithParts: Seq[Vec2], + scale: Double, + prefboardOffset: Vec2 + ): Unit = { + val corner = start + (end - start).axialProject + + for ( + x <- math.min(start.dx.toInt, corner.dx.toInt) to math.max( + start.dx.toInt, + corner.dx.toInt + ) + ) { + for ( + y <- math.min(start.dy.toInt, corner.dy.toInt) to math.max( + start.dy.toInt, + corner.dy.toInt + ) + ) { + if (!positionsWithParts.contains(Point(x, y))) { + val t = orthoPartT(Vec2(x, y) - prefboardOffset, scale) + doRender(t, 0) + } renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - point, - if (isOnBorder(circuit.size, point)) 0x44ff0000 else 0x44ffffff + Vec2(x, y) - prefboardOffset, + corner.subtract(prefboardOffset), + scale, + 0x44ffffff ) - - if (circuit.getPart(px, py) == null) { - val t = orthoPartT(x, y, xSize, ySize, circuit.size, px, py) - var m = 0 - if (px > start.x) { m |= 8; if (px != end2.x) m |= 2 } - if (px < start.x) { m |= 2; if (px != end2.x) m |= 8 } - if (py > start.y) { m |= 1; if (py != end2.y) m |= 4 } - if (py < start.y) { m |= 4; if (py != end2.y) m |= 1 } - if (px == start.x && end2.x > start.x) m |= 2 - if (px == start.x && end2.x < start.x) m |= 8 - if (py == start.y && end2.y > start.y) m |= 4 - if (py == start.y && end2.y < start.y) m |= 1 - doRender(t, m) + } + } + for ( + x <- math.min(corner.dx.toInt, end.dx.toInt) to math.max( + corner.dx.toInt, + end.dx.toInt + ) + ) { + for ( + y <- math.min(corner.dy.toInt, end.dy.toInt) to math.max( + corner.dy.toInt, + end.dy.toInt + ) + ) { + if (!positionsWithParts.contains(Point(x, y))) { + val t = orthoPartT(Vec2(x, y) - prefboardOffset, scale) + doRender(t, 0) } + renderHolo( + Vec2(x, y) - prefboardOffset, + corner.subtract(prefboardOffset), + scale, + 0x44ffffff + ) } + } } @SideOnly(Side.CLIENT) @@ -171,7 +194,8 @@ class OpInsulatedWire(colour: Int) extends OpWire { } @SideOnly(Side.CLIENT) - override def getOpName = Colors(colour & 0xff).name + " Insulated wire" + override def getOpName = + "item.projectred.transmission.wire|" + colour + ".name" } class OpBundledCable(colour: Int) extends OpWire { diff --git a/src/main/scala/mrtjp/projectred/fabrication/opgates.scala b/src/main/scala/mrtjp/projectred/fabrication/opgates.scala deleted file mode 100644 index 8b3b5af62..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/opgates.scala +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.vec.{Vector3, Rotation, Transformation, Translation} -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.vec.{Point, Vec2} -import mrtjp.projectred.fabrication.CircuitOp._ -import mrtjp.projectred.fabrication.ICComponentStore._ - -abstract class OpGateCommons(meta: Int) extends CircuitOp { - def canPlace(circuit: IntegratedCircuit, point: Point): Boolean - def findRot(circuit: IntegratedCircuit, start: Point, end: Point): Int - - override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = - canPlace(circuit, start) && circuit.getPart(start) == null - - override def writeOp( - circuit: IntegratedCircuit, - start: Point, - end: Point, - out: MCDataOutput - ) { - out.writeByte(start.x).writeByte(start.y) - out.writeByte(findRot(circuit, start, end)) - } - - override def readOp(circuit: IntegratedCircuit, in: MCDataInput) { - val point = Point(in.readByte(), in.readByte()) - val r = in.readUByte() - - if (circuit.getPart(point) == null && canPlace(circuit, point)) { - val part = CircuitPart - .createPart(ICGateDefinition(meta).gateType) - .asInstanceOf[GateICPart] - part.preparePlacement(r, meta) - circuit.setPart(point, part) - } - } - - @SideOnly(Side.CLIENT) - override def renderHover( - circuit: IntegratedCircuit, - point: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(point) != null) return - - val t = orthoPartT(x, y, xSize, ySize, circuit.size, point.x, point.y) - doRender(t, findRot(circuit, point, point)) - - renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - point, - if (canPlace(circuit, point)) 0x33ffffff else 0x33ff0000 - ) - } - - @SideOnly(Side.CLIENT) - override def renderDrag( - circuit: IntegratedCircuit, - start: Point, - end: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(start) != null) return - - val t = orthoPartT(x, y, xSize, ySize, circuit.size, start.x, start.y) - doRender(t, findRot(circuit, start, end)) - - renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - start, - if (canPlace(circuit, start)) 0x44ffffff else 0x44ff0000 - ) - } - - @SideOnly(Side.CLIENT) - override def renderImage( - x: Double, - y: Double, - width: Double, - height: Double - ) { - val t = orthoGridT(width, height) `with` new Translation(x, y, 0) - doRender(t, 0) - } - - @SideOnly(Side.CLIENT) - def doRender(t: Transformation, rot: Int) { - RenderICGate.renderInv( - Rotation.quarterRotations(rot).at(Vector3.center) `with` t, - meta - ) - } - - @SideOnly(Side.CLIENT) - override def getOpName = ICGateDefinition(meta).unlocal -} - -class OpGate(meta: Int) extends OpGateCommons(meta) { - override def findRot(circuit: IntegratedCircuit, start: Point, end: Point) = { - (end - start).vectorize.axialProject.normalize match { - case Vec2(0, -1) => 0 - case Vec2(1, 0) => 1 - case Vec2(0, 1) => 2 - case Vec2(-1, 0) => 3 - case _ => 0 - } - } - - override def canPlace(circuit: IntegratedCircuit, point: Point) = - !isOnBorder(circuit.size, point) -} - -class OpIOGate(meta: Int) extends OpGateCommons(meta) { - override def canPlace(circuit: IntegratedCircuit, point: Point) = - isOnBorder(circuit.size, point) && !isOnEdge(circuit.size, point) - - override def findRot(circuit: IntegratedCircuit, start: Point, end: Point) = { - val wm = circuit.size.width - 1 - val hm = circuit.size.height - 1 - start match { - case Point(_, 0) => 0 - case Point(`wm`, _) => 1 - case Point(_, `hm`) => 2 - case Point(0, _) => 3 - case _ => 0 - } - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/oputils.scala b/src/main/scala/mrtjp/projectred/fabrication/oputils.scala deleted file mode 100644 index c2d9d36ae..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/oputils.scala +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.data.{MCDataInput, MCDataOutput} -import codechicken.lib.gui.GuiDraw -import codechicken.lib.render.uv.{UVScale, UVTranslation, IconTransformation} -import codechicken.lib.vec.Translation -import cpw.mods.fml.relauncher.{Side, SideOnly} -import mrtjp.core.vec.Point -import mrtjp.projectred.core.libmc.PRResources -import mrtjp.projectred.fabrication.ICComponentStore._ - -class CircuitOpErase extends CircuitOp { - override def checkOp(circuit: IntegratedCircuit, start: Point, end: Point) = - true - - override def writeOp( - circuit: IntegratedCircuit, - start: Point, - end: Point, - out: MCDataOutput - ) { - out.writeByte(start.x).writeByte(start.y) - out.writeByte(end.x).writeByte(end.y) - } - - override def readOp(circuit: IntegratedCircuit, in: MCDataInput) { - val start = Point(in.readUByte(), in.readUByte()) - val end = Point(in.readUByte(), in.readUByte()) - - for (x <- math.min(start.x, end.x) to math.max(start.x, end.x)) - for (y <- math.min(start.y, end.y) to math.max(start.y, end.y)) - circuit.removePart(x, y) - } - - @SideOnly(Side.CLIENT) - override def renderImage( - x: Double, - y: Double, - width: Double, - height: Double - ) { - val t = orthoGridT(width, height) `with` new Translation(x, y, 0) - - prepairRender() - PRResources.guiPrototyper.bind() - faceModels(dynamicIdx(0, true)).render( - t, - new UVScale(16) `with` new UVTranslation(330, 18) `with` new UVScale( - 1 / 512d - ) - ) - finishRender() - } - - @SideOnly(Side.CLIENT) - override def renderHover( - circuit: IntegratedCircuit, - point: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - if (circuit.getPart(point) != null) - CircuitOp.renderHolo(x, y, xSize, ySize, circuit.size, point, 0x33ff0000) - } - - @SideOnly(Side.CLIENT) - override def renderDrag( - circuit: IntegratedCircuit, - start: Point, - end: Point, - x: Double, - y: Double, - xSize: Double, - ySize: Double - ) { - for (px <- math.min(start.x, end.x) to math.max(start.x, end.x)) - for (py <- math.min(start.y, end.y) to math.max(start.y, end.y)) { - val point = Point(px, py) - CircuitOp.renderHolo( - x, - y, - xSize, - ySize, - circuit.size, - point, - if (circuit.getPart(point) != null) 0x44ff0000 else 0x44ffffff - ) - } - } - - @SideOnly(Side.CLIENT) - override def getOpName = "Erase" -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/partabstracts.scala b/src/main/scala/mrtjp/projectred/fabrication/partabstracts.scala deleted file mode 100644 index 64ccbbf0e..000000000 --- a/src/main/scala/mrtjp/projectred/fabrication/partabstracts.scala +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2015. - * Created by MrTJP. - * All rights reserved. - */ -package mrtjp.projectred.fabrication - -import codechicken.lib.vec.{Vector3, Rotation} -import mrtjp.core.vec.Point -import mrtjp.projectred.fabrication.IWireICPart._ - -trait TICOrient extends CircuitPart { - var orientation: Byte = 0 - - def rotation = orientation & 0x3 - - def setRotation(r: Int) { - orientation = (orientation & 0xfc | r).toByte - } - - def rotationT = - Rotation.quarterRotations(rotation).at(new Vector3(0.5, 0, 0.5)) - - // internal r from absRot - def toInternal(absRot: Int) = (absRot + 4 - rotation) % 4 - // absRot from internal r - def toAbsolute(r: Int) = (r + rotation) % 4 - - def toInternalMask(mask: Int) = TICOrient.shiftMask(mask, toInternal(0)) - def toAbsoluteMask(mask: Int) = TICOrient.shiftMask(mask, toAbsolute(0)) -} - -object TICOrient { - def shiftMask(mask: Int, r: Int) = - (mask & ~0xf) | (mask << r | mask >> 4 - r) & 0xf - def flipMaskZ(mask: Int) = mask & 5 | mask << 2 & 8 | mask >> 2 & 2 -} - -trait TICAcquisitions extends CircuitPart { - def getStraight(r: Int) = world.getPart(posOfStraight(r)) - def posOfStraight(r: Int) = Point(x, y).offset(r) - def rotFromStraight(r: Int) = (r + 2) % 4 - - def notifyToDir(r: Int) { world.notifyNeighbor(posOfStraight(r)) } - def notify(mask: Int) { world.notifyNeighbors(x, y, mask) } -} - -trait TICRSAcquisitions extends TICAcquisitions with IPoweredCircuitPart { - def calcSignal(r: Int): Int = - resolveSignal(getStraight(r), rotFromStraight(r)) - - def resolveSignal(part: Any, r: Int): Int -} - -trait TICBundledAcquisitions extends TICAcquisitions { - def calcArray(r: Int): Array[Byte] = - resolveArray(getStraight(r), rotFromStraight(r)) - - def resolveArray(part: Any, r: Int): Array[Byte] -} - -trait TConnectableICPart extends CircuitPart with TICAcquisitions { - var connMap: Byte = 0 - - def maskConnects(r: Int) = (connMap & 1 << r) != 0 - - def discover(r: Int) = getStraight(r) match { - case c: TConnectableICPart => - canConnectPart(c, r) && c.connect(this, rotFromStraight(r)) - case c => discoverOverride(r, c) - } - - def discoverOverride(r: Int, part: CircuitPart) = false - - def connect(part: CircuitPart, r: Int) = { - if (canConnectPart(part, r)) { - val oldConn = connMap - connMap = (connMap | 1 << r).toByte - if (oldConn != connMap) onMaskChanged() - true - } else false - } - - def updateConns() = { - var newConn = 0 - for (r <- 0 until 4) if (discover(r)) newConn |= 1 << r - if (newConn != connMap) { - connMap = newConn.toByte - onMaskChanged() - true - } else false - } - - def canConnectPart(part: CircuitPart, r: Int): Boolean - - def onMaskChanged() {} -} - -trait TPropagatingICPart - extends CircuitPart - with TConnectableICPart - with IWireICPart { - var propagationMask = 0xf - - def propagate(prev: CircuitPart, mode: Int) { - if (mode != FORCED) ICPropagator.addPartChange(this) - for (r <- 0 until 4) - if ((propagationMask & 1 << r) != 0) - if (maskConnects(r)) - propagateExternal(getStraight(r), posOfStraight(r), prev, mode) - - propagateOther(mode) - } - - def propagateOther(mode: Int) {} - - def propagateExternal( - to: CircuitPart, - at: Point, - from: CircuitPart, - mode: Int - ) { - if (to != null) { - if (to == from) return - if (propagateTo(to, mode)) return - } - ICPropagator.addNeighborChange(at) - } - - def propagateTo(part: CircuitPart, mode: Int) = part match { - case w: IWireICPart => - ICPropagator.propagateTo(w, this, mode) - true - case _ => false - } -} - -trait TRSPropagatingICPart extends TPropagatingICPart { - def calculateSignal: Int - - def getSignal: Int - def setSignal(signal: Int) - - override def updateAndPropagate(prev: CircuitPart, mode: Int) { - if (mode == DROPPING && getSignal == 0) return - val newSignal = calculateSignal - if (newSignal < getSignal) { - if (newSignal > 0) ICPropagator.propagateAnalogDrop(this) - setSignal(0) - propagate(prev, DROPPING) - } else if (newSignal > getSignal) { - setSignal(newSignal) - if (mode == DROPPING) propagate(null, RISING) - else propagate(prev, RISING) - } else if (mode == DROPPING) propagateTo(prev, RISING) - else if (mode == FORCE) propagate(prev, FORCED) - } -} diff --git a/src/main/scala/mrtjp/projectred/fabrication/wirepropagation.scala b/src/main/scala/mrtjp/projectred/fabrication/wirepropagation.scala index 7ac20f92d..fa4271e64 100644 --- a/src/main/scala/mrtjp/projectred/fabrication/wirepropagation.scala +++ b/src/main/scala/mrtjp/projectred/fabrication/wirepropagation.scala @@ -6,9 +6,9 @@ package mrtjp.projectred.fabrication import java.util.{Stack => JStack} - -import cpw.mods.fml.relauncher.{SideOnly, Side} +import cpw.mods.fml.relauncher.{Side, SideOnly} import mrtjp.core.vec.Point +import mrtjp.projectred.fabrication.circuitparts.{CircuitPart, IWireICPart} import scala.collection.immutable.HashSet @@ -153,61 +153,3 @@ class ICPropagationRun { class ICPropagation(part: IWireICPart, from: CircuitPart, mode: Int) { def go() { part.updateAndPropagate(from, mode) } } - -object IWireICPart { - - /** Standard operation procedure, no special propogation rules. The propogator - * signal may not have increased. - */ - final val RISING = 0 - - /** Used when the propogator signal dropped (to 0). Propagation should - * continue until a rising or constant change is encountered at which point a - * RISING should be propogated back to this wire. - */ - final val DROPPING = 1 - - /** Used when a wire's connection state has changed. Even if the signal - * remains the same, new connections still need to be recalculated - */ - final val FORCE = 2 - - /** Used when the propogator did not change signal, but a new connection may - * have been established and signal needs recalculating - */ - final val FORCED = 3 -} - -trait IWireICPart { - - /** Recalculates the signal of this wire and calls the appropriate propogation - * methods in WirePropagator. DO NOT CALL THIS YOURSELF. Use - * WirePropagator.propagateTo - * - * @param prev - * The part which called this propogation (should be connected) may be - * null. - * @param mode - * One of RISING, DROPPING, FORCE and FORCED specified above - */ - def updateAndPropagate(prev: CircuitPart, mode: Int) - - /** Called at the end of a propogation run for partChanged events. Marks the - * end of a state change for this part. - */ - def onSignalUpdate() - - /** @param r - * The rotation of this part to test for wire connection. - * @return - * true if the specified side of this block is connected to, for example, a - * 'wire' where signal should decrease by one. - */ - def diminishOnSide(r: Int): Boolean - - /** The world in which this part resides - * - * @return - */ - def world: IntegratedCircuit -}