From 8ed48750a3c4c12900b96dda60779fff4a0ea047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 14 Oct 2013 13:26:13 +0200 Subject: [PATCH] disk drive and floppy disks (disk drives are mountable and act as a "proxy" for the item in them); minor refactoring; --- assets/opencomputers/lang/de_DE.lang | 2 + assets/opencomputers/lang/en_US.lang | 2 + assets/opencomputers/lua/kernel.lua | 4 +- assets/opencomputers/lua/rom/lib/event.lua | 5 +- assets/opencomputers/lua/rom/lib/fs.lua | 6 +- .../textures/blocks/adapter_top.png | Bin 650 -> 399 bytes .../textures/blocks/disk_drive_front.png | Bin 0 -> 592 bytes .../textures/blocks/disk_drive_side.png | Bin 0 -> 605 bytes .../opencomputers/textures/gui/background.png | Bin 0 -> 542 bytes .../opencomputers/textures/gui/computer.png | Bin 583 -> 0 bytes assets/opencomputers/textures/gui/slot.png | Bin 0 -> 143 bytes assets/opencomputers/textures/items/disk.png | Bin 0 -> 508 bytes li/cil/oc/Blocks.scala | 2 + li/cil/oc/Items.scala | 31 ++-- li/cil/oc/api/FileSystem.scala | 8 +- li/cil/oc/api/driver/Item.scala | 1 + li/cil/oc/api/driver/Memory.scala | 20 +++ li/cil/oc/api/driver/Slot.scala | 18 ++- li/cil/oc/api/network/Node.scala | 6 +- li/cil/oc/client/GuiHandler.scala | 12 +- li/cil/oc/client/Proxy.scala | 1 + li/cil/oc/client/gui/Computer.scala | 56 ++------ li/cil/oc/client/gui/DiskDrive.scala | 14 ++ .../oc/client/gui/DynamicGuiContainer.scala | 65 +++++++++ .../tileentity}/ComputerRenderer.scala | 7 +- .../PowerDistributorRenderer.scala | 7 +- .../tileentity}/ScreenRenderer.scala | 7 +- li/cil/oc/common/GuiHandler.scala | 7 +- li/cil/oc/common/GuiType.scala | 1 + li/cil/oc/common/block/Computer.scala | 14 +- li/cil/oc/common/block/Delegate.scala | 4 +- li/cil/oc/common/block/DiskDrive.scala | 57 ++++++++ li/cil/oc/common/container/DiskDrive.scala | 18 +++ li/cil/oc/common/item/Delegate.scala | 6 +- li/cil/oc/common/item/Disk.scala | 14 ++ li/cil/oc/common/item/GraphicsCard.scala | 2 +- .../item/{Hdd.scala => HardDiskDrive.scala} | 4 +- li/cil/oc/common/item/Memory.scala | 2 +- li/cil/oc/common/item/NetworkCard.scala | 2 +- li/cil/oc/common/item/RedstoneCard.scala | 2 +- li/cil/oc/common/tileentity/Adapter.scala | 14 ++ .../tileentity/ComponentInventory.scala | 135 ++++++------------ li/cil/oc/common/tileentity/Computer.scala | 36 +++-- li/cil/oc/common/tileentity/DiskDrive.scala | 57 ++++++++ li/cil/oc/common/tileentity/Inventory.scala | 66 +++++++++ li/cil/oc/common/tileentity/Keyboard.scala | 8 +- li/cil/oc/common/tileentity/Screen.scala | 8 +- li/cil/oc/server/driver/FileSystem.scala | 47 +++--- li/cil/oc/server/driver/GraphicsCard.scala | 8 +- li/cil/oc/server/driver/Memory.scala | 11 +- li/cil/oc/server/driver/NetworkCard.scala | 8 +- li/cil/oc/server/driver/RedstoneCard.scala | 8 +- li/cil/oc/server/fs/VirtualFileSystem.scala | 7 - li/cil/oc/util/LuaStateFactory.scala | 2 +- .../RenderState.scala} | 4 +- 55 files changed, 553 insertions(+), 273 deletions(-) create mode 100644 assets/opencomputers/textures/blocks/disk_drive_front.png create mode 100644 assets/opencomputers/textures/blocks/disk_drive_side.png create mode 100644 assets/opencomputers/textures/gui/background.png delete mode 100644 assets/opencomputers/textures/gui/computer.png create mode 100644 assets/opencomputers/textures/gui/slot.png create mode 100644 assets/opencomputers/textures/items/disk.png create mode 100644 li/cil/oc/api/driver/Memory.scala create mode 100644 li/cil/oc/client/gui/DiskDrive.scala create mode 100644 li/cil/oc/client/gui/DynamicGuiContainer.scala rename li/cil/oc/client/{ => renderer/tileentity}/ComputerRenderer.scala (90%) rename li/cil/oc/client/{ => renderer/tileentity}/PowerDistributorRenderer.scala (92%) rename li/cil/oc/client/{ => renderer/tileentity}/ScreenRenderer.scala (97%) create mode 100644 li/cil/oc/common/block/DiskDrive.scala create mode 100644 li/cil/oc/common/container/DiskDrive.scala create mode 100644 li/cil/oc/common/item/Disk.scala rename li/cil/oc/common/item/{Hdd.scala => HardDiskDrive.scala} (89%) create mode 100644 li/cil/oc/common/tileentity/DiskDrive.scala create mode 100644 li/cil/oc/common/tileentity/Inventory.scala rename li/cil/oc/{client/RenderUtil.scala => util/RenderState.scala} (94%) 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 fa3f11d7c476aa0d49b720d4029d483d909220b2..8af4f6ff48752adb109cfd70693b5a0755b31798 100644 GIT binary patch delta 336 zcmV-W0k8gw1&;%eNPhrtP)t-sQc_YF7#JBD8BtMDP*6}#PEJ%*R8vz^7Z(=*001Z` zC{IsMRaI41R#qx1DpyxmDJdz4h=?aAC&I$Q8yg#ggM(ODSb>3ofPjF8hK5Z|O^1hv zOG`@@78V*B8iIm?OiWCLg@uHKgexm6!NI{svDG{P006d0M1Mh4c-j<@2a-e~2t-?= znEs#H9B0%0&$wt&B}nt=5@jE%R5JDjQXOFP0aZ*ZsDja%MZw~aOen%)>ih-9D>z4B z!*OI^#Vt$n%$^^>Pv5SvnopuHZQbEqH(?~Szg=2elYiU!b9vv4h-+JFt(_6PM;y_v ze`qUsZ%H5M5lPb{AhsEbOnP?*rr;B0+DPfa*?>w(4YQi~JQAiojU~gRLow1Kc1hSQc_Y>R8(7A zTV-WsKtDf^kB{SS561ui0Q5;jK~#9!6p)2(#6S#0z1iK+hB-NAzAJNkWoBml|9_}s zS+X?J8;=bnFOYy>=L3MTVN&b#h6!WIpo1bS_6#AIR(}+%HV^EJT3X#j~|)t|40D(_wMzmy{NCW@9&;L6b#nqT})qTH*0HaZ*OlcEv@M2XgfPQO-)UGeSI@Cv(V5` zdwcuh;$lxvPZt-Ll#~={X=x`XCnF;xb#--jcXwlBKQdU+@Pft%vOG`*haIm)*6BDztvMMPl zv9_`b3k!>gh&b*w!35~%SDr48Ar-fD0@(A881QUML*Skom_mgXxe|h z#kLnbEaX2F2o%jzQDpDhGu>#%%9K)379)mJ7dMAjf4#gxs%p2j98c2es{I;WapyO^ z3VtoNP^qu>;rt(M0*8LIC9JvHIWe~WSI@?22NIRNPOk9h&$za{#YxQI&|UU|?ydYi c|5+p$x~GX=nP)9E73gaQPgg&ebxsLQ0HRpe6#xJL literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9192d2dca3a059de1209fb6f646831a83618cb55 GIT binary patch literal 605 zcmV-j0;2tiP)>MHm@|DJgSvb2&LV8yg!{RaHJdK4fHMVPRo+cXw%NX)`l3adB~6TwHW?bZ~HR zUteD`GBPJ8CqhC(c6N4nczAAZZbwH)S65dyHa1#XT4!fxW@TkJH#bjDPeVgPU|?WY zR#s+aWk5hbTwPrBqT*dL|a^3KtDek8X9J1W=%~^Wo2buU0u<;yix!F0PaadK~#9!6p#gu z#4rp+lLiVYGq=OcvkbG$O!q&^x|StNmfyF(5o!WU7(q4#VM^OsZ#HOWlxFi8LJ}Pg zEJdN}P@%oK0wb!dD%*uzTe9_S$$)sO-0>FPb}u;Ts2&K_N96ji6}*z5Cc&?SF!8TO zmm@+*Yx8kNK(yTW$EDw2^~;-;{{$K-=M$bx63){!;ecpAnx;R7T6m!AnhwbOixWA~ z?J`_CcW(|fDj_}(<9Iq1B03dc2*p)p8s>wU8-|fTgE70-L1;Fyx1 zl&avFo0y&&l$w}QS$Hzl2B=6hz$e7@*s){X-QEBH|2H=`2a1J;h635XR()H69QKkR zzhEF22pFWincaZ4^mw{BhE&{obJvjThyf3agXQuU|NZSQJv-HXKxy;Rt_C)q#Df;A ziu_*vba`s1&dX$&`CoYxyTY<3Hk+9hfJV{+G|Xg}Uwtiaa$ZB}>5aEp(5?7ja^P3x z*~IOgZYKoM-jBus2jUGcfG1TqXKV9$h}8b?YH3M+Sy(xArqG`1I@D x3=@WseU<;Y7ZmxeVtsHG6dg1M5|h_6Ff-g|U;Qm(ee@=fWuC5nF6*2UngGxJa;^XX literal 0 HcmV?d00001 diff --git a/assets/opencomputers/textures/gui/computer.png b/assets/opencomputers/textures/gui/computer.png deleted file mode 100644 index d301a403767313273432eb2f99ab6a76ae8564e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 583 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911MRQ8&P5FjO4;u=vBoS#-wo>-L1;Fyx1 zl&avFo0y&&l$w}QS$Hzl2B=6hz$e7@*s){X-QEBH|2H=`2a1J;h635XR()H69QKkR zzhEF22pFWincaZ4Z1r?;45_&F=C&hOi-7>kffvVq{+}$qzAEx2Pm0giLOv%h=35uV zF1}Vdw%qmpYZb=@p;7Gd2`iAZLM8gWHS3)1No3KQizBHFVjAax*7x#wVz{*qHD1Z%v<_ z!hGl6QaG}WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!fo&H$ef*Y57_|NsA+o105Xobdz-%6PgshE&{2N^oN5;c;l; ll5lVRz-ef(h`E7*nZfTMLrQ4jl*d4I44$rjF6*2UngHI~CrJPR literal 0 HcmV?d00001 diff --git a/assets/opencomputers/textures/items/disk.png b/assets/opencomputers/textures/items/disk.png new file mode 100644 index 0000000000000000000000000000000000000000..58cf5bafbcabd1c3d3332c0ff15ce4185b0126ec GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8MFBn`uK)l4*VNQ>b#*m2H@CI51qw$+MY*`RXlrXbIXNXI zB|UodC?g}|&!0brhKBa`_W%C<)7RI(fB*jD$B$D}Q%y`v($mx9;^HDABOM(bqavdM z0s=fdJnr4QXJuujqoWfV8fs%>la-bA_wQe4XXjtPe%-!(J0&H>+uQrWg9pjU$;QUU znVFeCfByXa`}eI|x6I7UG&D5s-o5MN;}aDb33T3)lb<#Mon=-M - * 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() {