diff --git a/assets/opencomputers/lang/de_DE.lang b/assets/opencomputers/lang/de_DE.lang index c923949db..33dd0dded 100644 --- a/assets/opencomputers/lang/de_DE.lang +++ b/assets/opencomputers/lang/de_DE.lang @@ -3,6 +3,8 @@ oc.block.Computer.name=Computer oc.block.Keyboard.name=Tastatur oc.block.Screen.name=Bildschirm oc.container.computer=Computer +oc.container.disk_drive=Diskettenlaufwerk +oc.item.Disk.name=Diskette oc.item.GraphicsCard.name=Grafikkarte oc.item.HardDiskDrive2m.name=Festplatte (2MB) oc.item.HardDiskDrive4m.name=Festplatte (4MB) diff --git a/assets/opencomputers/lang/en_US.lang b/assets/opencomputers/lang/en_US.lang index fa2c64360..39de24f7a 100644 --- a/assets/opencomputers/lang/en_US.lang +++ b/assets/opencomputers/lang/en_US.lang @@ -3,6 +3,8 @@ oc.block.Computer.name=Computer oc.block.Keyboard.name=Keyboard oc.block.Screen.name=Screen oc.container.computer=Computer +oc.container.disk_drive=Disk Drive +oc.item.Disk.name=Floppy Disk oc.item.GraphicsCard.name=Graphics Card oc.item.HardDiskDrive2m.name=Hard Disk Drive (2MB) oc.item.HardDiskDrive4m.name=Hard Disk Drive (4MB) diff --git a/assets/opencomputers/lua/kernel.lua b/assets/opencomputers/lua/kernel.lua index 564fea643..963c85c94 100644 --- a/assets/opencomputers/lua/kernel.lua +++ b/assets/opencomputers/lua/kernel.lua @@ -180,7 +180,9 @@ local function main(args) debug.sethook(co, checkDeadline, "", 10000) end local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n))) - if result[1] then + if coroutine.status(co) == "dead" then + error("computer stopped unexpectedly", 0) + elseif result[1] then args = table.pack(coroutine.yield(result[2])) -- system yielded value else error(result[2], 0) diff --git a/assets/opencomputers/lua/rom/lib/event.lua b/assets/opencomputers/lua/rom/lib/event.lua index 7be6a582a..d5f07b696 100644 --- a/assets/opencomputers/lua/rom/lib/event.lua +++ b/assets/opencomputers/lua/rom/lib/event.lua @@ -109,9 +109,10 @@ end function event.wait(seconds) seconds = seconds or 0/0 checkArg(1, seconds, "number") - local target = os.uptime() + (seconds == seconds and seconds or 0) + local function isNaN(n) return n ~= n end + local target = os.uptime() + (isNaN(seconds) and 0 or seconds) repeat - local closest = seconds == seconds and target or math.huge + local closest = isNaN(seconds) and math.huge or target for _, info in pairs(timers) do if info.after < closest then closest = info.after diff --git a/assets/opencomputers/lua/rom/lib/fs.lua b/assets/opencomputers/lua/rom/lib/fs.lua index 1f445409b..d589985c0 100644 --- a/assets/opencomputers/lua/rom/lib/fs.lua +++ b/assets/opencomputers/lua/rom/lib/fs.lua @@ -23,7 +23,8 @@ end ------------------------------------------------------------------------------- local function onComponentAdded(_, address) - if component.type(address) == "filesystem" and + local componentType = component.type(address) + if (componentType == "filesystem" or componentType == "disk_drive") and address ~= os.romAddress() and address ~= os.tmpAddress() then @@ -44,7 +45,8 @@ local function onComponentAdded(_, address) end local function onComponentRemoved(_, address) - if component.type(address) == "filesystem" then + local componentType = component.type(address) + if componentType == "filesystem" or componentType == "disk_drive" then fs.umount(address) end end diff --git a/assets/opencomputers/textures/blocks/adapter_top.png b/assets/opencomputers/textures/blocks/adapter_top.png index fa3f11d7c..8af4f6ff4 100644 Binary files a/assets/opencomputers/textures/blocks/adapter_top.png and b/assets/opencomputers/textures/blocks/adapter_top.png differ diff --git a/assets/opencomputers/textures/blocks/disk_drive_front.png b/assets/opencomputers/textures/blocks/disk_drive_front.png new file mode 100644 index 000000000..334098460 Binary files /dev/null and b/assets/opencomputers/textures/blocks/disk_drive_front.png differ diff --git a/assets/opencomputers/textures/blocks/disk_drive_side.png b/assets/opencomputers/textures/blocks/disk_drive_side.png new file mode 100644 index 000000000..9192d2dca Binary files /dev/null and b/assets/opencomputers/textures/blocks/disk_drive_side.png differ diff --git a/assets/opencomputers/textures/gui/background.png b/assets/opencomputers/textures/gui/background.png new file mode 100644 index 000000000..78c467424 Binary files /dev/null and b/assets/opencomputers/textures/gui/background.png differ diff --git a/assets/opencomputers/textures/gui/computer.png b/assets/opencomputers/textures/gui/computer.png deleted file mode 100644 index d301a4037..000000000 Binary files a/assets/opencomputers/textures/gui/computer.png and /dev/null differ diff --git a/assets/opencomputers/textures/gui/slot.png b/assets/opencomputers/textures/gui/slot.png new file mode 100644 index 000000000..6f9164f6d Binary files /dev/null and b/assets/opencomputers/textures/gui/slot.png differ diff --git a/assets/opencomputers/textures/items/disk.png b/assets/opencomputers/textures/items/disk.png new file mode 100644 index 000000000..58cf5bafb Binary files /dev/null and b/assets/opencomputers/textures/items/disk.png differ diff --git a/li/cil/oc/Blocks.scala b/li/cil/oc/Blocks.scala index c889dbd4c..d683670a0 100644 --- a/li/cil/oc/Blocks.scala +++ b/li/cil/oc/Blocks.scala @@ -14,6 +14,7 @@ object Blocks { var powerDistributor: PowerDistributor = null var adapter: Adapter = null + var diskDrive: DiskDrive = null def init() { // IMPORTANT: the multi block must come first, since the sub blocks will @@ -30,5 +31,6 @@ object Blocks { powerDistributor = new PowerDistributor(blockSimple) adapter = new Adapter(blockSimple) + diskDrive = new DiskDrive(blockSimple) } } \ No newline at end of file diff --git a/li/cil/oc/Items.scala b/li/cil/oc/Items.scala index b02b70cdc..9edd8c606 100644 --- a/li/cil/oc/Items.scala +++ b/li/cil/oc/Items.scala @@ -9,28 +9,29 @@ object Items { var rs: item.RedstoneCard = null var lan: item.NetworkCard = null - var ram32k: item.Memory = null - var ram64k: item.Memory = null - var ram128k: item.Memory = null + var ram1: item.Memory = null + var ram2: item.Memory = null + var ram3: item.Memory = null - var hdd2: item.Hdd = null - var hdd4: item.Hdd = null - var hdd8: item.Hdd = null + var hdd1: item.HardDiskDrive = null + var hdd2: item.HardDiskDrive = null + var hdd3: item.HardDiskDrive = null + var disk: item.Disk = null def init() { multi = new item.Delegator(Config.itemId) gpu = new item.GraphicsCard(multi) rs = new item.RedstoneCard(multi) - - ram32k = new item.Memory(multi, 32) - ram64k = new item.Memory(multi, 64) - ram128k = new item.Memory(multi, 128) - - hdd2 = new item.Hdd(multi, 2) - hdd4 = new item.Hdd(multi, 4) - hdd8 = new item.Hdd(multi, 8) - lan = new item.NetworkCard(multi) + + ram1 = new item.Memory(multi, 32) + ram2 = new item.Memory(multi, 64) + ram3 = new item.Memory(multi, 128) + + hdd1 = new item.HardDiskDrive(multi, 2) + hdd2 = new item.HardDiskDrive(multi, 4) + hdd3 = new item.HardDiskDrive(multi, 8) + disk = new item.Disk(multi) } } \ No newline at end of file diff --git a/li/cil/oc/api/FileSystem.scala b/li/cil/oc/api/FileSystem.scala index 733bc6b02..84607b212 100644 --- a/li/cil/oc/api/FileSystem.scala +++ b/li/cil/oc/api/FileSystem.scala @@ -209,10 +209,12 @@ trait FileSystem extends Persistable { def file(handle: Int): Option[Handle] /** - * Called when the file system is deconstructed. + * Called when the file system is close. *

- * This should close any open real file handles (e.g. all open I/O streams) - * and clear any other internal state. + * This should close any open real file handles (e.g. all open I/O streams), + * but keep any internal state that may have to be persisted, for example + * for floppy disks (which are removed before they are saved so they don't + * save any open handles). *

* When the filesystem is made available as a network node created via * `FileSystem.asNode` this will be called whenever the node is disconnected diff --git a/li/cil/oc/api/driver/Item.scala b/li/cil/oc/api/driver/Item.scala index 862196ac8..645c9ec52 100644 --- a/li/cil/oc/api/driver/Item.scala +++ b/li/cil/oc/api/driver/Item.scala @@ -44,6 +44,7 @@ trait Item extends Driver { * driver supports may go. This will only be called if a previous call to * `worksWith` with the same item type returned true. * + * @param item the item to get the slot type for. * @return the component type of the specified item. */ def slot(item: ItemStack): Slot.Value diff --git a/li/cil/oc/api/driver/Memory.scala b/li/cil/oc/api/driver/Memory.scala new file mode 100644 index 000000000..1c190f8e3 --- /dev/null +++ b/li/cil/oc/api/driver/Memory.scala @@ -0,0 +1,20 @@ +package li.cil.oc.api.driver + +import net.minecraft.item.ItemStack + +/** + * Use this trait to implement components extending the memory of a computer. + *

+ * Note that the item must be installed in the actual computer's inventory to + * work. If it is installed in an external inventory the computer will not + * recognize the memory. + */ +trait Memory extends Item { + /** + * The amount of RAM this component provides, in byte. + * + * @param item the item to get the provided memory for. + * @return the amount of memory the specified component provides. + */ + def amount(item: ItemStack): Int +} diff --git a/li/cil/oc/api/driver/Slot.scala b/li/cil/oc/api/driver/Slot.scala index 81f0ac7af..6f91d30fe 100644 --- a/li/cil/oc/api/driver/Slot.scala +++ b/li/cil/oc/api/driver/Slot.scala @@ -8,8 +8,18 @@ package li.cil.oc.api.driver * inside the computer, not next to it. */ object Slot extends Enumeration { - val PSU = Value("PSU") - val RAM = Value("RAM") - val HDD = Value("HDD") - val PCI = Value("PCI") + /** Power generating components, such as generators. */ + val Power = Value("Power") + + /** Memory extension components. */ + val Memory = Value("Memory") + + /** Hard disk drives. */ + val HardDiskDrive = Value("HardDiskDrive") + + /** Extension cards such as graphics or redstone cards. */ + val Card = Value("Card") + + /** Floppy disks. */ + val Disk = Value("Disk") } \ No newline at end of file diff --git a/li/cil/oc/api/network/Node.scala b/li/cil/oc/api/network/Node.scala index 2e8cf5f03..c6ee822e0 100644 --- a/li/cil/oc/api/network/Node.scala +++ b/li/cil/oc/api/network/Node.scala @@ -76,7 +76,7 @@ trait Node extends Persistable { * they have is to *not* have an address, which can be useful for "dummy" * nodes, such as cables. In that case they may ignore the address being set. */ - var address: Option[String] = None + final var address: Option[String] = None /** * The network this node is currently in. @@ -88,7 +88,7 @@ trait Node extends Persistable { * This will always be set automatically by the network manager. Do not * change this value and do not return anything that it wasn't set to. */ - var network: Option[Network] = None + final var network: Option[Network] = None /** * Makes the node handle a message. @@ -183,7 +183,7 @@ trait Node extends Persistable { * @param args the values to return. * @return and array option as required by `receive`. */ - protected def result(args: Any*): Option[Array[Any]] = { + final protected def result(args: Any*): Option[Array[Any]] = { def unwrap(arg: Any): AnyRef = arg match { case x: ScalaNumber => x.underlying case x => x.asInstanceOf[AnyRef] diff --git a/li/cil/oc/client/GuiHandler.scala b/li/cil/oc/client/GuiHandler.scala index 56af8381c..588f36a79 100644 --- a/li/cil/oc/client/GuiHandler.scala +++ b/li/cil/oc/client/GuiHandler.scala @@ -1,6 +1,6 @@ package li.cil.oc.client -import li.cil.oc.common.tileentity.{Screen, Computer} +import li.cil.oc.common.tileentity import li.cil.oc.common.{GuiHandler => CommonGuiHandler, GuiType} import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World @@ -8,10 +8,12 @@ import net.minecraft.world.World object GuiHandler extends CommonGuiHandler { override def getClientGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int) = world.getBlockTileEntity(x, y, z) match { - case tileEntity: Computer if id == GuiType.Computer.id => - new gui.Computer(player.inventory, tileEntity) - case tileEntity: Screen if id == GuiType.Screen.id => - new gui.Screen(tileEntity) + case computer: tileentity.Computer if id == GuiType.Computer.id => + new gui.Computer(player.inventory, computer) + case screen: tileentity.Screen if id == GuiType.Screen.id => + new gui.Screen(screen) + case drive: tileentity.DiskDrive if id == GuiType.DiskDrive.id => + new gui.DiskDrive(player.inventory, drive) case _ => null } } diff --git a/li/cil/oc/client/Proxy.scala b/li/cil/oc/client/Proxy.scala index 06845f910..4c4f81f97 100644 --- a/li/cil/oc/client/Proxy.scala +++ b/li/cil/oc/client/Proxy.scala @@ -8,6 +8,7 @@ import cpw.mods.fml.relauncher.Side import li.cil.oc.OpenComputers import li.cil.oc.common.tileentity import li.cil.oc.common.{Proxy => CommonProxy} +import li.cil.oc.client.renderer.tileentity.{PowerDistributorRenderer, ScreenRenderer, ComputerRenderer} private[oc] class Proxy extends CommonProxy { override def init(e: FMLInitializationEvent) = { diff --git a/li/cil/oc/client/gui/Computer.scala b/li/cil/oc/client/gui/Computer.scala index fe6c09750..7bf9d8212 100644 --- a/li/cil/oc/client/gui/Computer.scala +++ b/li/cil/oc/client/gui/Computer.scala @@ -3,17 +3,11 @@ package li.cil.oc.client.gui import li.cil.oc.Config import li.cil.oc.common.container import li.cil.oc.common.tileentity -import net.minecraft.client.gui.inventory.GuiContainer -import net.minecraft.client.renderer.Tessellator import net.minecraft.entity.player.InventoryPlayer import net.minecraft.inventory.Slot -import net.minecraft.util.ResourceLocation -import net.minecraft.util.StatCollector -import org.lwjgl.opengl.GL11 - -class Computer(inventory: InventoryPlayer, val tileEntity: tileentity.Computer) extends GuiContainer(new container.Computer(inventory, tileEntity)) { - private val background = new ResourceLocation(Config.resourceDomain, "textures/gui/computer.png") +import net.minecraft.util.{ResourceLocation, StatCollector} +class Computer(playerInventory: InventoryPlayer, val computer: tileentity.Computer) extends DynamicGuiContainer(new container.Computer(playerInventory, computer)) { private val iconPsu = new ResourceLocation(Config.resourceDomain, "textures/gui/icon_psu.png") private val iconPci = new ResourceLocation(Config.resourceDomain, "textures/gui/icon_pci.png") private val iconRam = new ResourceLocation(Config.resourceDomain, "textures/gui/icon_ram.png") @@ -21,52 +15,18 @@ class Computer(inventory: InventoryPlayer, val tileEntity: tileentity.Computer) private val icons = Array(iconPsu, iconPci, iconPci, iconPci, iconRam, iconRam, iconHdd, iconHdd) - private var (x, y) = (0, 0) - - override def initGui() = { - super.initGui() - x = (width - xSize) / 2 - y = (height - ySize) / 2 - } - - override def drawSlotInventory(slot: Slot) = { - super.drawSlotInventory(slot) - if (slot.slotNumber < 8 && !slot.getHasStack) - drawSlotIcon(slot, icons(slot.slotNumber)) - } - override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { fontRenderer.drawString( StatCollector.translateToLocal("oc.container.computer"), 8, 6, 0x404040) - fontRenderer.drawString( - StatCollector.translateToLocal("container.inventory"), - 8, ySize - 96 + 2, 0x404040) } - override def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) = { - GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F) - mc.renderEngine.bindTexture(background) - drawTexturedModalRect(x, y, 0, 0, xSize, ySize) - } + override protected def bindIconBackground(slot: Slot) = + if (slot.slotNumber < 8 && !slot.getHasStack) { + mc.renderEngine.bindTexture(icons(slot.slotNumber)) + true + } + else false override def doesGuiPauseGame = false - - private def drawSlotIcon(slot: Slot, icon: ResourceLocation) = { - GL11.glPushAttrib(0xFFFFFF) - GL11.glDisable(GL11.GL_LIGHTING) - GL11.glDisable(GL11.GL_DEPTH_TEST) - GL11.glEnable(GL11.GL_BLEND) - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA) - GL11.glColor4f(1, 1, 1, 0.25f) - mc.renderEngine.bindTexture(icon) - val t = Tessellator.instance - t.startDrawingQuads() - t.addVertexWithUV(slot.xDisplayPosition, slot.yDisplayPosition + 16, zLevel, 0, 1) - t.addVertexWithUV(slot.xDisplayPosition + 16, slot.yDisplayPosition + 16, zLevel, 1, 1) - t.addVertexWithUV(slot.xDisplayPosition + 16, slot.yDisplayPosition, zLevel, 1, 0) - t.addVertexWithUV(slot.xDisplayPosition, slot.yDisplayPosition, zLevel, 0, 0) - t.draw() - GL11.glPopAttrib() - } } \ No newline at end of file diff --git a/li/cil/oc/client/gui/DiskDrive.scala b/li/cil/oc/client/gui/DiskDrive.scala new file mode 100644 index 000000000..3ff76adb3 --- /dev/null +++ b/li/cil/oc/client/gui/DiskDrive.scala @@ -0,0 +1,14 @@ +package li.cil.oc.client.gui + +import li.cil.oc.common.container +import li.cil.oc.common.tileentity +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.util.StatCollector + +class DiskDrive(playerInventory: InventoryPlayer, val drive: tileentity.DiskDrive) extends DynamicGuiContainer(new container.DiskDrive(playerInventory, drive)) { + override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { + fontRenderer.drawString( + StatCollector.translateToLocal("oc.container.disk_drive"), + 8, 6, 0x404040) + } +} diff --git a/li/cil/oc/client/gui/DynamicGuiContainer.scala b/li/cil/oc/client/gui/DynamicGuiContainer.scala new file mode 100644 index 000000000..d5e48d739 --- /dev/null +++ b/li/cil/oc/client/gui/DynamicGuiContainer.scala @@ -0,0 +1,65 @@ +package li.cil.oc.client.gui + +import li.cil.oc.Config +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.client.renderer.Tessellator +import net.minecraft.inventory.{Container, Slot} +import net.minecraft.util.{StatCollector, ResourceLocation} +import org.lwjgl.opengl.GL11 + +abstract class DynamicGuiContainer(container: Container) extends GuiContainer(container) { + protected val slotBackground = new ResourceLocation(Config.resourceDomain, "textures/gui/slot.png") + protected val background = new ResourceLocation(Config.resourceDomain, "textures/gui/background.png") + + protected var (x, y) = (0, 0) + + override def initGui() = { + super.initGui() + x = (width - xSize) / 2 + y = (height - ySize) / 2 + } + + override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { + fontRenderer.drawString( + StatCollector.translateToLocal("container.inventory"), + 8, ySize - 96 + 2, 0x404040) + } + + override def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) = { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F) + mc.renderEngine.bindTexture(background) + drawTexturedModalRect(x, y, 0, 0, xSize, ySize) + } + + override def drawSlotInventory(slot: Slot) = { + if (slot.slotNumber < container.inventorySlots.size() - 36) { + mc.renderEngine.bindTexture(slotBackground) + drawSlot(slot.xDisplayPosition - 1, slot.yDisplayPosition - 1, 18) + } + super.drawSlotInventory(slot) + if (bindIconBackground(slot)) + drawSlot(slot.xDisplayPosition, slot.yDisplayPosition, 16, blend = true) + } + + protected def bindIconBackground(slot: Slot) = false + + private def drawSlot(x: Int, y: Int, size: Int, blend: Boolean = false) { + GL11.glPushAttrib(0xFFFFFF) + GL11.glDisable(GL11.GL_LIGHTING) + GL11.glDisable(GL11.GL_DEPTH_TEST) + if (blend) { + GL11.glEnable(GL11.GL_BLEND) + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA) + GL11.glColor4f(1, 1, 1, 0.25f) + } + else GL11.glColor4f(1, 1, 1, 1) + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(x, y + size, zLevel, 0, 1) + t.addVertexWithUV(x + size, y + size, zLevel, 1, 1) + t.addVertexWithUV(x + size, y, zLevel, 1, 0) + t.addVertexWithUV(x, y, zLevel, 0, 0) + t.draw() + GL11.glPopAttrib() + } +} diff --git a/li/cil/oc/client/ComputerRenderer.scala b/li/cil/oc/client/renderer/tileentity/ComputerRenderer.scala similarity index 90% rename from li/cil/oc/client/ComputerRenderer.scala rename to li/cil/oc/client/renderer/tileentity/ComputerRenderer.scala index be2677724..3f4fef360 100644 --- a/li/cil/oc/client/ComputerRenderer.scala +++ b/li/cil/oc/client/renderer/tileentity/ComputerRenderer.scala @@ -1,4 +1,4 @@ -package li.cil.oc.client +package li.cil.oc.client.renderer.tileentity import li.cil.oc.Config import li.cil.oc.common.tileentity.Computer @@ -8,6 +8,7 @@ import net.minecraft.tileentity.TileEntity import net.minecraft.util.ResourceLocation import net.minecraftforge.common.ForgeDirection import org.lwjgl.opengl.GL11 +import li.cil.oc.util.RenderState object ComputerRenderer extends TileEntitySpecialRenderer { private val frontOn = new ResourceLocation(Config.resourceDomain, "textures/blocks/computer_front_on.png") @@ -17,8 +18,8 @@ object ComputerRenderer extends TileEntitySpecialRenderer { if (computer.isOn) { GL11.glPushAttrib(0xFFFFFF) - RenderUtil.disableLighting() - RenderUtil.makeItBlend() + RenderState.disableLighting() + RenderState.makeItBlend() GL11.glPushMatrix() diff --git a/li/cil/oc/client/PowerDistributorRenderer.scala b/li/cil/oc/client/renderer/tileentity/PowerDistributorRenderer.scala similarity index 92% rename from li/cil/oc/client/PowerDistributorRenderer.scala rename to li/cil/oc/client/renderer/tileentity/PowerDistributorRenderer.scala index 80ff3e6f5..c7970bf21 100644 --- a/li/cil/oc/client/PowerDistributorRenderer.scala +++ b/li/cil/oc/client/renderer/tileentity/PowerDistributorRenderer.scala @@ -1,4 +1,4 @@ -package li.cil.oc.client +package li.cil.oc.client.renderer.tileentity import li.cil.oc.Config import li.cil.oc.common.tileentity @@ -7,6 +7,7 @@ import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer import net.minecraft.tileentity.TileEntity import net.minecraft.util.ResourceLocation import org.lwjgl.opengl.GL11 +import li.cil.oc.util.RenderState object PowerDistributorRenderer extends TileEntitySpecialRenderer { private val sideOn = new ResourceLocation(Config.resourceDomain, "textures/blocks/power_distributor_on.png") @@ -16,8 +17,8 @@ object PowerDistributorRenderer extends TileEntitySpecialRenderer { if (distributor.isActive) { GL11.glPushAttrib(0xFFFFFF) - RenderUtil.disableLighting() - RenderUtil.makeItBlend() + RenderState.disableLighting() + RenderState.makeItBlend() GL11.glPushMatrix() diff --git a/li/cil/oc/client/ScreenRenderer.scala b/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala similarity index 97% rename from li/cil/oc/client/ScreenRenderer.scala rename to li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala index 09c39b913..b0239f9a4 100644 --- a/li/cil/oc/client/ScreenRenderer.scala +++ b/li/cil/oc/client/renderer/tileentity/ScreenRenderer.scala @@ -1,4 +1,4 @@ -package li.cil.oc.client +package li.cil.oc.client.renderer.tileentity import com.google.common.cache.{CacheBuilder, RemovalNotification, RemovalListener} import cpw.mods.fml.common.{TickType, ITickHandler} @@ -12,6 +12,7 @@ import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer import net.minecraft.tileentity.TileEntity import net.minecraftforge.common.ForgeDirection import org.lwjgl.opengl.{GL14, GL11} +import li.cil.oc.util.RenderState object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] with ITickHandler { @@ -52,8 +53,8 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with GL11.glPushAttrib(0xFFFFFF) - RenderUtil.disableLighting() - RenderUtil.makeItBlend() + RenderState.disableLighting() + RenderState.makeItBlend() GL11.glPushMatrix() diff --git a/li/cil/oc/common/GuiHandler.scala b/li/cil/oc/common/GuiHandler.scala index 9b1fc0549..d50aeff60 100644 --- a/li/cil/oc/common/GuiHandler.scala +++ b/li/cil/oc/common/GuiHandler.scala @@ -1,15 +1,16 @@ package li.cil.oc.common import cpw.mods.fml.common.network.IGuiHandler -import li.cil.oc.common.tileentity.Computer import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World abstract class GuiHandler extends IGuiHandler { override def getServerGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int) = world.getBlockTileEntity(x, y, z) match { - case tileEntity: Computer => - new container.Computer(player.inventory, tileEntity) + case computer: tileentity.Computer => + new container.Computer(player.inventory, computer) + case drive: tileentity.DiskDrive => + new container.DiskDrive(player.inventory, drive) case _ => null } } \ No newline at end of file diff --git a/li/cil/oc/common/GuiType.scala b/li/cil/oc/common/GuiType.scala index b9463d5b3..98bf31b03 100644 --- a/li/cil/oc/common/GuiType.scala +++ b/li/cil/oc/common/GuiType.scala @@ -3,4 +3,5 @@ package li.cil.oc.common object GuiType extends Enumeration { val Computer = Value("Computer") val Screen = Value("Screen") + val DiskDrive = Value("DiskDrive") } diff --git a/li/cil/oc/common/block/Computer.scala b/li/cil/oc/common/block/Computer.scala index 1f6871264..e81ac29bd 100644 --- a/li/cil/oc/common/block/Computer.scala +++ b/li/cil/oc/common/block/Computer.scala @@ -16,8 +16,6 @@ class Computer(val parent: Delegator) extends Delegate { val unlocalizedName = "Computer" - // ----------------------------------------------------------------------- // - // Rendering stuff // ----------------------------------------------------------------------- // private object Icons { @@ -55,16 +53,12 @@ class Computer(val parent: Delegator) extends Delegate { Icons.on(ForgeDirection.EAST.ordinal) = Icons.on(ForgeDirection.WEST.ordinal) } - // ----------------------------------------------------------------------- // - // Tile entity // ----------------------------------------------------------------------- // override def hasTileEntity = true override def createTileEntity(world: World, metadata: Int) = Some(new tileentity.Computer(world.isRemote)) - // ----------------------------------------------------------------------- // - // Destruction / Interaction // ----------------------------------------------------------------------- // override def canConnectRedstone(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = @@ -77,8 +71,12 @@ class Computer(val parent: Delegator) extends Delegate { world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Computer].output(side) override def breakBlock(world: World, x: Int, y: Int, z: Int, blockId: Int, metadata: Int) = { - if (!world.isRemote) - world.getBlockTileEntity(x, y, z).asInstanceOf[tileentity.Computer].turnOff() + if (!world.isRemote) world.getBlockTileEntity(x, y, z) match { + case computer: tileentity.Computer => + computer.turnOff() + computer.dropContent(world, x, y, z) + case _ => // Ignore. + } super.breakBlock(world, x, y, z, blockId, metadata) } diff --git a/li/cil/oc/common/block/Delegate.scala b/li/cil/oc/common/block/Delegate.scala index b448042e9..8ff7c40a4 100644 --- a/li/cil/oc/common/block/Delegate.scala +++ b/li/cil/oc/common/block/Delegate.scala @@ -13,9 +13,9 @@ import net.minecraftforge.common.ForgeDirection /** The base class on which all our blocks are built. */ trait Delegate { - def parent: Delegator + val parent: Delegator - def unlocalizedName: String + val unlocalizedName: String val blockId = parent.add(this) diff --git a/li/cil/oc/common/block/DiskDrive.scala b/li/cil/oc/common/block/DiskDrive.scala new file mode 100644 index 000000000..5fc2ce40b --- /dev/null +++ b/li/cil/oc/common/block/DiskDrive.scala @@ -0,0 +1,57 @@ +package li.cil.oc.common.block + +import cpw.mods.fml.common.registry.GameRegistry +import li.cil.oc.common.{GuiType, tileentity} +import li.cil.oc.{OpenComputers, Config} +import net.minecraft.client.renderer.texture.IconRegister +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.util.Icon +import net.minecraft.world.World +import net.minecraftforge.common.ForgeDirection + +class DiskDrive(val parent: Delegator) extends Delegate { + GameRegistry.registerTileEntity(classOf[tileentity.DiskDrive], "oc.disk_drive") + + val unlocalizedName = "DiskDrive" + + // ----------------------------------------------------------------------- // + + private val icons = Array.fill[Icon](6)(null) + + override def icon(side: ForgeDirection) = Some(icons(side.ordinal)) + + override def registerIcons(iconRegister: IconRegister) = { + icons(ForgeDirection.DOWN.ordinal) = iconRegister.registerIcon(Config.resourceDomain + ":computer_top") + icons(ForgeDirection.UP.ordinal) = icons(ForgeDirection.DOWN.ordinal) + + icons(ForgeDirection.NORTH.ordinal) = iconRegister.registerIcon(Config.resourceDomain + ":disk_drive_side") + icons(ForgeDirection.SOUTH.ordinal) = iconRegister.registerIcon(Config.resourceDomain + ":disk_drive_front") + icons(ForgeDirection.WEST.ordinal) = icons(ForgeDirection.NORTH.ordinal) + icons(ForgeDirection.EAST.ordinal) = icons(ForgeDirection.NORTH.ordinal) + } + + // ----------------------------------------------------------------------- // + + override def hasTileEntity = true + + override def createTileEntity(world: World, metadata: Int) = Some(new tileentity.DiskDrive) + + // ----------------------------------------------------------------------- // + + override def breakBlock(world: World, x: Int, y: Int, z: Int, blockId: Int, metadata: Int) = { + if (!world.isRemote) world.getBlockTileEntity(x, y, z) match { + case drive: tileentity.DiskDrive => drive.dropContent(world, x, y, z) + case _ => // Ignore. + } + super.breakBlock(world, x, y, z, blockId, metadata) + } + + override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, + side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { + if (!player.isSneaking) { + player.openGui(OpenComputers, GuiType.DiskDrive.id, world, x, y, z) + true + } + else false + } +} diff --git a/li/cil/oc/common/container/DiskDrive.scala b/li/cil/oc/common/container/DiskDrive.scala new file mode 100644 index 000000000..ae08c80b0 --- /dev/null +++ b/li/cil/oc/common/container/DiskDrive.scala @@ -0,0 +1,18 @@ +package li.cil.oc.common.container + +import li.cil.oc.common.tileentity +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.inventory.Slot +import net.minecraft.item.ItemStack + +class DiskDrive(playerInventory: InventoryPlayer, drive: tileentity.DiskDrive) extends Player(playerInventory, drive) { + // Floppy slot. + addSlotToContainer(new Slot(drive, 0, 80, 35) { + override def isItemValid(item: ItemStack) = { + drive.isItemValidForSlot(0, item) + } + }) + + // Show the player's inventory. + addPlayerInventorySlots(8, 84) +} diff --git a/li/cil/oc/common/item/Delegate.scala b/li/cil/oc/common/item/Delegate.scala index bd4680286..b06b5d5d4 100644 --- a/li/cil/oc/common/item/Delegate.scala +++ b/li/cil/oc/common/item/Delegate.scala @@ -7,9 +7,9 @@ import net.minecraft.util.Icon import net.minecraft.world.World trait Delegate { - def parent: Delegator + val parent: Delegator - def unlocalizedName: String + val unlocalizedName: String val itemId = parent.add(this) @@ -23,7 +23,7 @@ trait Delegate { def icon: Option[Icon] = _icon - protected def icon_=(value: Icon) = _icon = Some(value) + protected def icon_=(value: Icon) = _icon = Option(value) def onItemRightClick(item: ItemStack, world: World, player: EntityPlayer): ItemStack = item diff --git a/li/cil/oc/common/item/Disk.scala b/li/cil/oc/common/item/Disk.scala new file mode 100644 index 000000000..c8eb3c837 --- /dev/null +++ b/li/cil/oc/common/item/Disk.scala @@ -0,0 +1,14 @@ +package li.cil.oc.common.item + +import li.cil.oc.Config +import net.minecraft.client.renderer.texture.IconRegister + +class Disk(val parent: Delegator) extends Delegate { + val unlocalizedName = "Disk" + + override def registerIcons(iconRegister: IconRegister) { + super.registerIcons(iconRegister) + + icon = iconRegister.registerIcon(Config.resourceDomain + ":disk") + } +} diff --git a/li/cil/oc/common/item/GraphicsCard.scala b/li/cil/oc/common/item/GraphicsCard.scala index 1c7e4ed77..4892e63ff 100644 --- a/li/cil/oc/common/item/GraphicsCard.scala +++ b/li/cil/oc/common/item/GraphicsCard.scala @@ -4,7 +4,7 @@ import li.cil.oc.Config import net.minecraft.client.renderer.texture.IconRegister class GraphicsCard(val parent: Delegator) extends Delegate { - def unlocalizedName = "GraphicsCard" + val unlocalizedName = "GraphicsCard" override def registerIcons(iconRegister: IconRegister) { super.registerIcons(iconRegister) diff --git a/li/cil/oc/common/item/Hdd.scala b/li/cil/oc/common/item/HardDiskDrive.scala similarity index 89% rename from li/cil/oc/common/item/Hdd.scala rename to li/cil/oc/common/item/HardDiskDrive.scala index f9070ee78..0857e3f80 100644 --- a/li/cil/oc/common/item/Hdd.scala +++ b/li/cil/oc/common/item/HardDiskDrive.scala @@ -6,8 +6,8 @@ import net.minecraft.client.renderer.texture.IconRegister import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack -class Hdd(val parent: Delegator, val megaBytes: Int) extends Delegate { - def unlocalizedName = "HardDiskDrive" + megaBytes + "m" +class HardDiskDrive(val parent: Delegator, val megaBytes: Int) extends Delegate { + val unlocalizedName = "HardDiskDrive" + megaBytes + "m" override def addInformation(item: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) = { super.addInformation(item, player, tooltip, advanced) diff --git a/li/cil/oc/common/item/Memory.scala b/li/cil/oc/common/item/Memory.scala index 2b1ee4eec..404244f83 100644 --- a/li/cil/oc/common/item/Memory.scala +++ b/li/cil/oc/common/item/Memory.scala @@ -4,7 +4,7 @@ import li.cil.oc.Config import net.minecraft.client.renderer.texture.IconRegister class Memory(val parent: Delegator, val kiloBytes: Int) extends Delegate { - def unlocalizedName = "Memory" + kiloBytes + "k" + val unlocalizedName = "Memory" + kiloBytes + "k" override def registerIcons(iconRegister: IconRegister) { super.registerIcons(iconRegister) diff --git a/li/cil/oc/common/item/NetworkCard.scala b/li/cil/oc/common/item/NetworkCard.scala index 9e5253ef9..ff61d21e6 100644 --- a/li/cil/oc/common/item/NetworkCard.scala +++ b/li/cil/oc/common/item/NetworkCard.scala @@ -4,7 +4,7 @@ import li.cil.oc.Config import net.minecraft.client.renderer.texture.IconRegister class NetworkCard(val parent: Delegator) extends Delegate { - def unlocalizedName = "NetworkCard" + val unlocalizedName = "NetworkCard" override def registerIcons(iconRegister: IconRegister) = { super.registerIcons(iconRegister) diff --git a/li/cil/oc/common/item/RedstoneCard.scala b/li/cil/oc/common/item/RedstoneCard.scala index a85248255..56cf1d095 100644 --- a/li/cil/oc/common/item/RedstoneCard.scala +++ b/li/cil/oc/common/item/RedstoneCard.scala @@ -4,7 +4,7 @@ import li.cil.oc.Config import net.minecraft.client.renderer.texture.IconRegister class RedstoneCard(val parent: Delegator) extends Delegate { - def unlocalizedName = "RedstoneCard" + val unlocalizedName = "RedstoneCard" override def registerIcons(iconRegister: IconRegister) { super.registerIcons(iconRegister) diff --git a/li/cil/oc/common/tileentity/Adapter.scala b/li/cil/oc/common/tileentity/Adapter.scala index e5647b736..872f76102 100644 --- a/li/cil/oc/common/tileentity/Adapter.scala +++ b/li/cil/oc/common/tileentity/Adapter.scala @@ -6,6 +6,7 @@ import li.cil.oc.api.network.{Message, Visibility, Node} import li.cil.oc.server.driver import net.minecraftforge.common.ForgeDirection import scala.collection.mutable +import net.minecraft.nbt.NBTTagCompound class Adapter extends Rotatable with Node with IPeripheral { val name = "adapter" @@ -71,6 +72,19 @@ class Adapter extends Rotatable with Node with IPeripheral { } } + override def readFromNBT(nbt: NBTTagCompound) { + super.readFromNBT(nbt) + load(nbt.getCompoundTag("node")) + } + + override def writeToNBT(nbt: NBTTagCompound) { + super.writeToNBT(nbt) + + val nodeNbt = new NBTTagCompound + save(nodeNbt) + nbt.setCompoundTag("node", nodeNbt) + } + // ----------------------------------------------------------------------- // override def getType = "oc_adapter" diff --git a/li/cil/oc/common/tileentity/ComponentInventory.scala b/li/cil/oc/common/tileentity/ComponentInventory.scala index f95957cf3..e3e75c002 100644 --- a/li/cil/oc/common/tileentity/ComponentInventory.scala +++ b/li/cil/oc/common/tileentity/ComponentInventory.scala @@ -1,33 +1,23 @@ package li.cil.oc.common.tileentity -import li.cil.oc.Items -import li.cil.oc.api.driver.Slot -import li.cil.oc.api.network.{PoweredNode, Node} -import li.cil.oc.common.item -import li.cil.oc.server.component +import li.cil.oc.api.driver +import li.cil.oc.api.network.Node import li.cil.oc.server.driver.Registry -import net.minecraft.inventory.IInventory import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagList import net.minecraft.world.World -trait ComponentInventory extends IInventory with PoweredNode { - protected val inventory = new Array[ItemStack](inventorySize) - - protected val itemComponents = Array.fill[Option[Node]](inventorySize)(None) - - protected val computer: component.Computer +trait ComponentInventory extends Inventory with Node { + protected val components = Array.fill[Option[Node]](getSizeInventory)(None) def world: World - def inventorySize = 8 - // ----------------------------------------------------------------------- // - def installedMemory = inventory.foldLeft(0)((sum, stack) => sum + (Registry.driverFor(stack) match { - case Some(driver) if driver.slot(stack) == Slot.RAM => Items.multi.subItem(stack) match { - case Some(ram: item.Memory) => ram.kiloBytes * 1024 + def installedMemory = inventory.foldLeft(0)((sum, stack) => sum + (stack match { + case Some(item) => Registry.driverFor(item) match { + case Some(driver: driver.Memory) => driver.amount(item) case _ => 0 } case _ => 0 @@ -37,14 +27,16 @@ trait ComponentInventory extends IInventory with PoweredNode { override protected def onConnect() { super.onConnect() - for (node <- itemComponents.filter(_.isDefined).map(_.get)) - network.foreach(_.connect(this, node)) + components collect { + case Some(node) => network.foreach(_.connect(this, node)) + } } override protected def onDisconnect() { super.onDisconnect() - for (node <- itemComponents.filter(_.isDefined).map(_.get)) - node.network.foreach(_.remove(node)) + components collect { + case Some(node) => node.network.foreach(_.remove(node)) + } } // ----------------------------------------------------------------------- // @@ -56,32 +48,37 @@ trait ComponentInventory extends IInventory with PoweredNode { val slotNbt = list.tagAt(i).asInstanceOf[NBTTagCompound] val slot = slotNbt.getByte("slot") if (slot >= 0 && slot < inventory.length) { - inventory(slot) = ItemStack.loadItemStackFromNBT( - slotNbt.getCompoundTag("item")) - itemComponents(slot) = Registry.driverFor(inventory(slot)) match { - case None => None - case Some(driver) => driver.node(inventory(slot)) + val item = ItemStack.loadItemStackFromNBT(slotNbt.getCompoundTag("item")) + inventory(slot) = Some(item) + components(slot) = Registry.driverFor(item) match { + case Some(driver) => + driver.node(item) match { + case Some(node) => + node.load(driver.nbt(item)) + Some(node) + case _ => None + } + case _ => None } } } - computer.recomputeMemory() } override def save(nbt: NBTTagCompound) = { super.save(nbt) val list = new NBTTagList - inventory.zipWithIndex filter { - case (stack, slot) => stack != null + inventory.zipWithIndex collect { + case (Some(stack), slot) => (stack, slot) } foreach { case (stack, slot) => { val slotNbt = new NBTTagCompound slotNbt.setByte("slot", slot.toByte) - itemComponents(slot) match { - case None => // Nothing special to save. + components(slot) match { case Some(node) => // We're guaranteed to have a driver for entries. node.save(Registry.driverFor(stack).get.nbt(stack)) + case _ => // Nothing special to save. } val itemNbt = new NBTTagCompound @@ -97,75 +94,27 @@ trait ComponentInventory extends IInventory with PoweredNode { def getInventoryStackLimit = 1 - def getInvName = "oc.container.computer" - - def getSizeInventory = inventory.length - - def getStackInSlot(i: Int) = inventory(i) - - def decrStackSize(slot: Int, amount: Int) = { - val stack = getStackInSlot(slot) - val result = if (stack == null) - null - else if (stack.stackSize <= amount) { - setInventorySlotContents(slot, null) - stack - } - else { - val subStack = stack.splitStack(amount) - if (stack.stackSize == 0) { - setInventorySlotContents(slot, null) + override protected def onItemAdded(slot: Int, item: ItemStack) = if (!world.isRemote) { + Registry.driverFor(item) match { + case None => // No driver. + case Some(driver) => driver.node(item) match { + case None => // No node. + case Some(node) => + components(slot) = Some(node) + node.load(driver.nbt(item)) + network.foreach(_.connect(this, node)) } - subStack } - onInventoryChanged() - result } - def getStackInSlotOnClosing(slot: Int) = null - - def setInventorySlotContents(slot: Int, item: ItemStack) = { + override protected def onItemRemoved(slot: Int, item: ItemStack) = if (!world.isRemote) { // Uninstall component previously in that slot. - if (!world.isRemote) itemComponents(slot) match { - case None => // Nothing to do. + components(slot) match { case Some(node) => - itemComponents(slot) = None + components(slot) = None node.network.foreach(_.remove(node)) - node.save(Registry.driverFor(inventory(slot)).get.nbt(inventory(slot))) + Registry.driverFor(item).foreach(driver => node.save(driver.nbt(item))) + case _ => // Nothing to do. } - - inventory(slot) = item - if (item != null && item.stackSize > getInventoryStackLimit) - item.stackSize = getInventoryStackLimit - - if (!world.isRemote) { - Registry.driverFor(inventory(slot)) match { - case None => // No driver. - case Some(driver) => - driver.node(inventory(slot)) match { - case None => // No node. - case Some(node) => - itemComponents(slot) = Some(node) - network.foreach(_.connect(this, node)) - } - } - } - - onInventoryChanged() } - - def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match { - case (_, None) => false // Invalid item. - case (0, Some(driver)) => driver.slot(item) == Slot.PSU - case (1 | 2 | 3, Some(driver)) => driver.slot(item) == Slot.PCI - case (4 | 5, Some(driver)) => driver.slot(item) == Slot.RAM - case (6 | 7, Some(driver)) => driver.slot(item) == Slot.HDD - case _ => false // Invalid slot. - } - - def isInvNameLocalized = false - - def openChest() {} - - def closeChest() {} } \ No newline at end of file diff --git a/li/cil/oc/common/tileentity/Computer.scala b/li/cil/oc/common/tileentity/Computer.scala index 9510a2cba..8a04a45ac 100644 --- a/li/cil/oc/common/tileentity/Computer.scala +++ b/li/cil/oc/common/tileentity/Computer.scala @@ -1,16 +1,20 @@ package li.cil.oc.common.tileentity import java.util.concurrent.atomic.AtomicBoolean +import li.cil.oc.api.driver.Slot +import li.cil.oc.api.network.PoweredNode import li.cil.oc.client.{PacketSender => ClientPacketSender} import li.cil.oc.server.component import li.cil.oc.server.component.Redstone import li.cil.oc.server.driver +import li.cil.oc.server.driver.Registry import li.cil.oc.server.{PacketSender => ServerPacketSender} import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection -class Computer(isClient: Boolean) extends Rotatable with component.Computer.Environment with ComponentInventory with Redstone { +class Computer(isClient: Boolean) extends Rotatable with component.Computer.Environment with ComponentInventory with Redstone with PoweredNode { def this() = this(false) // ----------------------------------------------------------------------- // @@ -45,15 +49,16 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi override def readFromNBT(nbt: NBTTagCompound) = { super.readFromNBT(nbt) - load(nbt.getCompoundTag("data")) + load(nbt.getCompoundTag("node")) + computer.recomputeMemory() } override def writeToNBT(nbt: NBTTagCompound) = { super.writeToNBT(nbt) - val dataNbt = new NBTTagCompound - save(dataNbt) - nbt.setCompoundTag("data", dataNbt) + val nodeNbt = new NBTTagCompound + save(nodeNbt) + nbt.setCompoundTag("node", nodeNbt) } // ----------------------------------------------------------------------- // @@ -67,7 +72,7 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi ServerPacketSender.sendComputerState(this, computer.isRunning) isRunning = computer.isRunning - for (component <- itemComponents) component match { + for (component <- components) component match { case Some(node) => node.update() case _ => // Empty. } @@ -83,6 +88,19 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi // ----------------------------------------------------------------------- // + def getInvName = "oc.container.computer" + + def getSizeInventory = 8 + + def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match { + case (_, None) => false // Invalid item. + case (0, Some(driver)) => driver.slot(item) == Slot.Power + case (1 | 2 | 3, Some(driver)) => driver.slot(item) == Slot.Card + case (4 | 5, Some(driver)) => driver.slot(item) == Slot.Memory + case (6 | 7, Some(driver)) => driver.slot(item) == Slot.HardDiskDrive + case _ => false // Invalid slot. + } + override def isUseableByPlayer(player: EntityPlayer) = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this && player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64 @@ -118,6 +136,8 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi else worldObj.markBlockForRenderUpdate(xCoord, yCoord, zCoord) } - private def hasRedstoneCard = - !inventory.isEmpty && inventory.exists(item => item != null && driver.RedstoneCard.worksWith(item)) + private def hasRedstoneCard = inventory.exists { + case Some(item) => driver.RedstoneCard.worksWith(item) + case _ => false + } } \ No newline at end of file diff --git a/li/cil/oc/common/tileentity/DiskDrive.scala b/li/cil/oc/common/tileentity/DiskDrive.scala new file mode 100644 index 000000000..e90d86ef8 --- /dev/null +++ b/li/cil/oc/common/tileentity/DiskDrive.scala @@ -0,0 +1,57 @@ +package li.cil.oc.common.tileentity + +import li.cil.oc.api.driver.Slot +import li.cil.oc.api.network.{Message, Visibility, Node} +import li.cil.oc.server.driver.Registry +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +class DiskDrive extends Rotatable with Node with ComponentInventory { + val name = "disk_drive" + + val visibility = Visibility.Network + + def world = worldObj + + // ----------------------------------------------------------------------- // + + override def receive(message: Message) = super.receive(message) orElse { + components(0) match { + case Some(node) if node.address.isDefined => + node.receive(message) + case _ if message.name.startsWith("fs.") => result(Unit, "no disk") + case _ => None + } + } + + // ----------------------------------------------------------------------- // + + override def readFromNBT(nbt: NBTTagCompound) { + super.readFromNBT(nbt) + load(nbt.getCompoundTag("node")) + } + + override def writeToNBT(nbt: NBTTagCompound) { + super.writeToNBT(nbt) + + val nodeNbt = new NBTTagCompound + save(nodeNbt) + nbt.setCompoundTag("node", nodeNbt) + } + + // ----------------------------------------------------------------------- // + + def getInvName = "oc.container.disk_drive" + + def getSizeInventory = 1 + + def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match { + case (0, Some(driver)) => driver.slot(item) == Slot.Disk + case _ => false + } + + def isUseableByPlayer(player: EntityPlayer) = + worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this && + player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64 +} diff --git a/li/cil/oc/common/tileentity/Inventory.scala b/li/cil/oc/common/tileentity/Inventory.scala new file mode 100644 index 000000000..0f87b1b73 --- /dev/null +++ b/li/cil/oc/common/tileentity/Inventory.scala @@ -0,0 +1,66 @@ +package li.cil.oc.common.tileentity + +import net.minecraft.entity.item.EntityItem +import net.minecraft.inventory.IInventory +import net.minecraft.item.ItemStack +import net.minecraft.world.World + +trait Inventory extends IInventory { + protected val inventory = Array.fill[Option[ItemStack]](getSizeInventory)(None) + + def getStackInSlot(i: Int) = inventory(i).orNull + + def decrStackSize(slot: Int, amount: Int) = inventory(slot) match { + case Some(stack) if stack.stackSize <= amount => + setInventorySlotContents(slot, null) + stack + case Some(stack) => + val result = stack.splitStack(amount) + onInventoryChanged() + result + case _ => null + } + + def setInventorySlotContents(slot: Int, item: ItemStack) = { + if (inventory(slot).isDefined) + onItemRemoved(slot, inventory(slot).get) + + inventory(slot) = Option(item) + if (item != null && item.stackSize > getInventoryStackLimit) + item.stackSize = getInventoryStackLimit + + if (inventory(slot).isDefined) + onItemAdded(slot, inventory(slot).get) + + onInventoryChanged() + } + + def getStackInSlotOnClosing(slot: Int) = null + + def isInvNameLocalized = false + + def openChest() {} + + def closeChest() {} + + def dropContent(world: World, x: Int, y: Int, z: Int) { + val rng = world.rand + for (slot <- 0 until getSizeInventory) { + inventory(slot) match { + case Some(stack) if stack.stackSize > 0 => + setInventorySlotContents(slot, null) + val (tx, ty, tz) = (0.25 + (rng.nextDouble() * 0.5), 0.25 + (rng.nextDouble() * 0.5), 0.25 + (rng.nextDouble() * 0.5)) + val (vx, vy, vz) = ((rng.nextDouble() - 0.3) * 0.5, (rng.nextDouble() - 0.5) * 0.3, (rng.nextDouble() - 0.5) * 0.3) + val entity = new EntityItem(world, x + tx, y + ty, z + tz, stack.copy()) + entity.setVelocity(vx, vy, vz) + entity.delayBeforeCanPickup = 20 + world.spawnEntityInWorld(entity) + case _ => // Nothing. + } + } + } + + protected def onItemAdded(slot: Int, item: ItemStack) {} + + protected def onItemRemoved(slot: Int, item: ItemStack) {} +} diff --git a/li/cil/oc/common/tileentity/Keyboard.scala b/li/cil/oc/common/tileentity/Keyboard.scala index 3cbd2b7ad..aa0f0e519 100644 --- a/li/cil/oc/common/tileentity/Keyboard.scala +++ b/li/cil/oc/common/tileentity/Keyboard.scala @@ -28,15 +28,15 @@ class Keyboard extends Rotatable with Node { override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) - load(nbt.getCompoundTag("data")) + load(nbt.getCompoundTag("node")) } override def writeToNBT(nbt: NBTTagCompound) { super.writeToNBT(nbt) - val dataNbt = new NBTTagCompound - save(dataNbt) - nbt.setCompoundTag("data", dataNbt) + val nodeNbt = new NBTTagCompound + save(nodeNbt) + nbt.setCompoundTag("node", nodeNbt) } def isUseableByPlayer(p: Player) = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this && diff --git a/li/cil/oc/common/tileentity/Screen.scala b/li/cil/oc/common/tileentity/Screen.scala index f48b9bb86..0528de26a 100644 --- a/li/cil/oc/common/tileentity/Screen.scala +++ b/li/cil/oc/common/tileentity/Screen.scala @@ -15,15 +15,15 @@ class Screen extends Rotatable with ScreenEnvironment with PoweredNode { override def readFromNBT(nbt: NBTTagCompound) = { super.readFromNBT(nbt) - load(nbt.getCompoundTag("data")) + load(nbt.getCompoundTag("node")) } override def writeToNBT(nbt: NBTTagCompound) = { super.writeToNBT(nbt) - val dataNbt = new NBTTagCompound - save(dataNbt) - nbt.setCompoundTag("data", dataNbt) + val nodeNbt = new NBTTagCompound + save(nodeNbt) + nbt.setCompoundTag("node", nodeNbt) } override def validate() = { diff --git a/li/cil/oc/server/driver/FileSystem.scala b/li/cil/oc/server/driver/FileSystem.scala index 651ada21c..793e39f49 100644 --- a/li/cil/oc/server/driver/FileSystem.scala +++ b/li/cil/oc/server/driver/FileSystem.scala @@ -2,34 +2,43 @@ package li.cil.oc.server.driver import li.cil.oc import li.cil.oc.api.driver.{Item, Slot} -import li.cil.oc.common.item.Hdd +import li.cil.oc.common.item.{Disk, HardDiskDrive} import li.cil.oc.{Config, Items} import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound object FileSystem extends Item { override def api = Option(getClass.getResourceAsStream(Config.driverPath + "filesystem.lua")) - override def worksWith(item: ItemStack) = WorksWith(Items.hdd2, Items.hdd4, Items.hdd8)(item) + override def worksWith(item: ItemStack) = WorksWith(Items.hdd1, Items.hdd2, Items.hdd3, Items.disk)(item) - override def slot(item: ItemStack) = Slot.HDD + override def slot(item: ItemStack) = Items.multi.subItem(item) match { + case Some(hdd: HardDiskDrive) => Slot.HardDiskDrive + case Some(disk: Disk) => Slot.Disk + case _ => throw new IllegalArgumentException() + } override def node(item: ItemStack) = Items.multi.subItem(item) match { - case Some(subItem: Hdd) => - // We have a bit of a chicken-egg problem here, because we want to use the - // node's address as the folder name... so we generate the address here, - // if necessary. No one will know, right? Right!? - val tag = nbt(item) - val address = - if (tag.hasKey("address")) tag.getString("address") - else java.util.UUID.randomUUID().toString - oc.api.FileSystem.fromSaveDirectory(address, subItem.megaBytes * 1024 * 1024, Config.filesBuffered). - flatMap(oc.api.FileSystem.asNode) match { - case None => None - case Some(node) => - node.address = Some(address) - node.load(tag) - Some(node) - } + case Some(hdd: HardDiskDrive) => createNode(item, hdd.megaBytes * 1024 * 1024) + case Some(disk: Disk) => createNode(item, 512 * 1024) case _ => None } + + private def createNode(item: ItemStack, capacity: Int) = { + // We have a bit of a chicken-egg problem here, because we want to use the + // node's address as the folder name... so we generate the address here, + // if necessary. No one will know, right? Right!? + val address = addressFromTag(nbt(item)) + oc.api.FileSystem.fromSaveDirectory(address, capacity, Config.filesBuffered). + flatMap(oc.api.FileSystem.asNode) match { + case Some(node) => + node.address = Some(address) + Some(node) + case None => None + } + } + + private def addressFromTag(tag: NBTTagCompound) = + if (tag.hasKey("address")) tag.getString("address") + else java.util.UUID.randomUUID().toString } \ No newline at end of file diff --git a/li/cil/oc/server/driver/GraphicsCard.scala b/li/cil/oc/server/driver/GraphicsCard.scala index 508bedead..c48a8d590 100644 --- a/li/cil/oc/server/driver/GraphicsCard.scala +++ b/li/cil/oc/server/driver/GraphicsCard.scala @@ -11,11 +11,7 @@ object GraphicsCard extends driver.Item { override def worksWith(item: ItemStack) = WorksWith(Items.gpu)(item) - override def slot(item: ItemStack) = Slot.PCI + override def slot(item: ItemStack) = Slot.Card - override def node(item: ItemStack) = { - val instance = new component.GraphicsCard() - instance.load(nbt(item)) - Some(instance) - } + override def node(item: ItemStack) = Some(new component.GraphicsCard()) } \ No newline at end of file diff --git a/li/cil/oc/server/driver/Memory.scala b/li/cil/oc/server/driver/Memory.scala index 2e3cf09ab..eefb32ecf 100644 --- a/li/cil/oc/server/driver/Memory.scala +++ b/li/cil/oc/server/driver/Memory.scala @@ -5,8 +5,13 @@ import li.cil.oc.api.driver import li.cil.oc.api.driver.Slot import net.minecraft.item.ItemStack -object Memory extends driver.Item { - override def worksWith(item: ItemStack) = WorksWith(Items.ram128k, Items.ram32k, Items.ram64k)(item) +object Memory extends driver.Memory { + override def amount(item: ItemStack) = if (item.itemID == Items.multi.itemID) Items.multi.subItem(item) match { + case Some(memory: li.cil.oc.common.item.Memory) => memory.kiloBytes * 1024 + case _ => 0 + } else 0 - override def slot(item: ItemStack) = Slot.RAM + override def worksWith(item: ItemStack) = WorksWith(Items.ram3, Items.ram1, Items.ram2)(item) + + override def slot(item: ItemStack) = Slot.Memory } diff --git a/li/cil/oc/server/driver/NetworkCard.scala b/li/cil/oc/server/driver/NetworkCard.scala index 6252596e2..7168838b2 100644 --- a/li/cil/oc/server/driver/NetworkCard.scala +++ b/li/cil/oc/server/driver/NetworkCard.scala @@ -11,11 +11,7 @@ object NetworkCard extends driver.Item { def worksWith(item: ItemStack) = WorksWith(Items.lan)(item) - def slot(item: ItemStack) = Slot.PCI + def slot(item: ItemStack) = Slot.Card - override def node(item: ItemStack) = { - val instance = new component.NetworkCard() - instance.load(nbt(item)) - Some(instance) - } + override def node(item: ItemStack) = Some(new component.NetworkCard()) } diff --git a/li/cil/oc/server/driver/RedstoneCard.scala b/li/cil/oc/server/driver/RedstoneCard.scala index 49d475652..6db152efc 100644 --- a/li/cil/oc/server/driver/RedstoneCard.scala +++ b/li/cil/oc/server/driver/RedstoneCard.scala @@ -11,11 +11,7 @@ object RedstoneCard extends driver.Item { override def worksWith(item: ItemStack) = WorksWith(Items.rs)(item) - override def slot(item: ItemStack) = Slot.PCI + override def slot(item: ItemStack) = Slot.Card - override def node(item: ItemStack) = { - val instance = new component.RedstoneCard() - instance.load(nbt(item)) - Some(instance) - } + override def node(item: ItemStack) = Some(new component.RedstoneCard()) } diff --git a/li/cil/oc/server/fs/VirtualFileSystem.scala b/li/cil/oc/server/fs/VirtualFileSystem.scala index 80722cfef..8301d6bf9 100644 --- a/li/cil/oc/server/fs/VirtualFileSystem.scala +++ b/li/cil/oc/server/fs/VirtualFileSystem.scala @@ -95,13 +95,6 @@ trait VirtualFileSystem extends OutputStreamFileSystem { // ----------------------------------------------------------------------- // - override def close() = { - super.close() - root.children.clear() - } - - // ----------------------------------------------------------------------- // - override protected def openInputStream(path: String) = root.get(segments(path)) match { case Some(obj: VirtualFile) => obj.openInputStream() diff --git a/li/cil/oc/util/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 9ba8a3479..0b9ddbd80 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -99,7 +99,7 @@ object LuaStateFactory { // ----------------------------------------------------------------------- // def createState(): Option[LuaState] = { - val state = new LuaState(Integer.MAX_VALUE) + val state = new LuaState(Int.MaxValue) try { // Load all libraries. state.openLib(LuaState.Library.BASE) diff --git a/li/cil/oc/client/RenderUtil.scala b/li/cil/oc/util/RenderState.scala similarity index 94% rename from li/cil/oc/client/RenderUtil.scala rename to li/cil/oc/util/RenderState.scala index e94df5288..37ec45178 100644 --- a/li/cil/oc/client/RenderUtil.scala +++ b/li/cil/oc/util/RenderState.scala @@ -1,9 +1,9 @@ -package li.cil.oc.client +package li.cil.oc.util import net.minecraft.client.renderer.OpenGlHelper import org.lwjgl.opengl.{ARBMultitexture, GLContext, GL11, GL13} -object RenderUtil { +object RenderState { val arb = GLContext.getCapabilities.GL_ARB_multitexture && !GLContext.getCapabilities.OpenGL13 def disableLighting() {