diff --git a/assets/opencomputers/textures/items/terminal.png b/assets/opencomputers/textures/items/terminal.png new file mode 100644 index 000000000..46c8e2ac3 Binary files /dev/null and b/assets/opencomputers/textures/items/terminal.png differ diff --git a/assets/opencomputers/textures/items/terminal.png.mcmeta b/assets/opencomputers/textures/items/terminal.png.mcmeta new file mode 100644 index 000000000..6274fbfe5 --- /dev/null +++ b/assets/opencomputers/textures/items/terminal.png.mcmeta @@ -0,0 +1,6 @@ +{ + "animation": { + "frametime": 10, + "frames": [ 0, 1 ] + } +} \ No newline at end of file diff --git a/li/cil/oc/client/GuiHandler.scala b/li/cil/oc/client/GuiHandler.scala index b86978596..320b1091f 100644 --- a/li/cil/oc/client/GuiHandler.scala +++ b/li/cil/oc/client/GuiHandler.scala @@ -1,10 +1,11 @@ package li.cil.oc.client -import li.cil.oc.Items import li.cil.oc.common.inventory.ServerInventory import li.cil.oc.common.{GuiHandler => CommonGuiHandler, item, tileentity, GuiType} +import li.cil.oc.{Settings, Items} import net.minecraft.entity.player.EntityPlayer import net.minecraft.world.World +import scala.collection.convert.WrapAsScala._ object GuiHandler extends CommonGuiHandler { override def getClientGuiElement(id: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int) = @@ -20,7 +21,7 @@ object GuiHandler extends CommonGuiHandler { case rack: tileentity.Rack if id == GuiType.Rack.id => new gui.Rack(player.inventory, rack) case screen: tileentity.Screen if id == GuiType.Screen.id => - new gui.Screen(screen) + new gui.Screen(screen.origin.buffer, screen.tier > 0, () => screen.origin.hasPower) case _ => Items.multi.subItem(player.getCurrentEquippedItem) match { case Some(server: item.Server) if id == GuiType.Server.id => new gui.Server(player.inventory, new ServerInventory { @@ -29,7 +30,27 @@ object GuiHandler extends CommonGuiHandler { override def isUseableByPlayer(player: EntityPlayer) = player == player }) case Some(terminal: item.Terminal) if id == GuiType.Terminal.id => - null // TODO + val stack = player.getCurrentEquippedItem + if (stack.hasTagCompound) { + val address = stack.getTagCompound.getString(Settings.namespace + "server") + if (address != null && !address.isEmpty) { + // Check if bound to server is loaded. TODO optimize this? + world.loadedTileEntityList.flatMap { + case rack: tileentity.Rack => rack.terminals + case _ => Iterable.empty + } find (_.rack.isPresent.exists { + case Some(value) => value == address + case _ => false + }) match { + case Some(term) => + // TODO check reachability + new gui.Screen(term.buffer, true, () => true) + case _ => null + } + } + else null + } + else null case _ => null } } diff --git a/li/cil/oc/client/PacketHandler.scala b/li/cil/oc/client/PacketHandler.scala index 85262537b..948858fbc 100644 --- a/li/cil/oc/client/PacketHandler.scala +++ b/li/cil/oc/client/PacketHandler.scala @@ -167,44 +167,53 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } - def onScreenColorChange(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => - t.buffer.foreground = p.readInt() - t.buffer.background = p.readInt() - case _ => // Invalid packet. + def onScreenColorChange(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + buffer.foreground = p.readInt() + buffer.background = p.readInt() + } - def onScreenCopy(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => - val col = p.readInt() - val row = p.readInt() - val w = p.readInt() - val h = p.readInt() - val tx = p.readInt() - val ty = p.readInt() - t.buffer.copy(col, row, w, h, tx, ty) - case _ => // Invalid packet. + def onScreenCopy(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + val col = p.readInt() + val row = p.readInt() + val w = p.readInt() + val h = p.readInt() + val tx = p.readInt() + val ty = p.readInt() + buffer.copy(col, row, w, h, tx, ty) + } - def onScreenDepthChange(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => t.buffer.depth = PackedColor.Depth(p.readInt()) - case _ => // Invalid packet. + def onScreenDepthChange(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + buffer.depth = PackedColor.Depth(p.readInt()) + } - def onScreenFill(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => - val col = p.readInt() - val row = p.readInt() - val w = p.readInt() - val h = p.readInt() - val c = p.readChar() - t.buffer.fill(col, row, w, h, c) - case _ => // Invalid packet. + def onScreenFill(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + val col = p.readInt() + val row = p.readInt() + val w = p.readInt() + val h = p.readInt() + val c = p.readChar() + buffer.fill(col, row, w, h, c) + } def onScreenPowerChange(p: PacketParser) = p.readTileEntity[Screen]() match { @@ -212,28 +221,37 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } - def onScreenResolutionChange(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => - val w = p.readInt() - val h = p.readInt() - t.buffer.resolution = (w, h) - case _ => // Invalid packet. + def onScreenResolutionChange(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + val w = p.readInt() + val h = p.readInt() + buffer.resolution = (w, h) + } - def onScreenSet(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(t) => - val col = p.readInt() - val row = p.readInt() - val s = p.readUTF() - t.buffer.set(col, row, s) - case _ => // Invalid packet. + def onScreenSet(p: PacketParser) { + val buffer = p.readTileEntity[TileEntity]() match { + case Some(t: Buffer) => t.buffer + case Some(t: Rack) => t.terminals(p.readInt()).buffer + case _ => return // Invalid packet. } + val col = p.readInt() + val row = p.readInt() + val s = p.readUTF() + buffer.set(col, row, s) + } def onServerPresence(p: PacketParser) = p.readTileEntity[Rack]() match { - case Some(t) => for (i <- 0 until t.isPresent.length) t.isPresent(i) = p.readBoolean() + case Some(t) => for (i <- 0 until t.isPresent.length) { + if (p.readBoolean()) { + t.isPresent(i) = Some(p.readUTF()) + } + else t.isPresent(i) = None + } case _ => // Invalid packet. } } \ No newline at end of file diff --git a/li/cil/oc/client/PacketSender.scala b/li/cil/oc/client/PacketSender.scala index 1fd9aaea3..17817ad42 100644 --- a/li/cil/oc/client/PacketSender.scala +++ b/li/cil/oc/client/PacketSender.scala @@ -2,6 +2,7 @@ package li.cil.oc.client import li.cil.oc.common.PacketBuilder import li.cil.oc.common.PacketType +import li.cil.oc.common.component import li.cil.oc.common.tileentity._ import net.minecraftforge.common.ForgeDirection @@ -15,61 +16,93 @@ object PacketSender { pb.sendToServer() } - def sendKeyDown(t: Buffer, char: Char, code: Int) = - if (t.hasKeyboard) { - val pb = new PacketBuilder(PacketType.KeyDown) + def sendKeyDown(b: component.Buffer, char: Char, code: Int) { + val pb = new PacketBuilder(PacketType.KeyDown) - pb.writeTileEntity(t) - pb.writeChar(char) - pb.writeInt(code) - - pb.sendToServer() + b.owner match { + case t: Buffer if t.hasKeyboard => + pb.writeTileEntity(t) + case t: component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + case _ => return } + pb.writeChar(char) + pb.writeInt(code) - def sendKeyUp(t: Buffer, char: Char, code: Int) = - if (t.hasKeyboard) { - val pb = new PacketBuilder(PacketType.KeyUp) + pb.sendToServer() + } - pb.writeTileEntity(t) - pb.writeChar(char) - pb.writeInt(code) + def sendKeyUp(b: component.Buffer, char: Char, code: Int) { + val pb = new PacketBuilder(PacketType.KeyUp) - pb.sendToServer() + b.owner match { + case t: Buffer if t.hasKeyboard => + pb.writeTileEntity(t) + case t: component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + case _ => return } + pb.writeChar(char) + pb.writeInt(code) - def sendClipboard(t: Buffer, value: String) = - if (value != null && !value.isEmpty && t.hasKeyboard) { + pb.sendToServer() + } + + def sendClipboard(b: component.Buffer, value: String) { + if (value != null && !value.isEmpty) { val pb = new PacketBuilder(PacketType.Clipboard) - pb.writeTileEntity(t) + b.owner match { + case t: Buffer if t.hasKeyboard => + pb.writeTileEntity(t) + case t: component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + case _ => return + } pb.writeUTF(value.substring(0, math.min(value.length, 1024))) pb.sendToServer() } + } - def sendMouseClick(t: Buffer, x: Int, y: Int, drag: Boolean) = - if (t.tier > 0) { - val pb = new PacketBuilder(PacketType.MouseClickOrDrag) + def sendMouseClick(b: component.Buffer, x: Int, y: Int, drag: Boolean) { + val pb = new PacketBuilder(PacketType.MouseClickOrDrag) - pb.writeTileEntity(t) - pb.writeInt(x) - pb.writeInt(y) - pb.writeBoolean(drag) - - pb.sendToServer() + b.owner match { + case t: Buffer if t.tier > 0 => + pb.writeTileEntity(t) + case t: component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + case _ => return } + pb.writeInt(x) + pb.writeInt(y) + pb.writeBoolean(drag) - def sendMouseScroll(t: Buffer, x: Int, y: Int, scroll: Int) = - if (t.tier > 0) { - val pb = new PacketBuilder(PacketType.MouseScroll) + pb.sendToServer() + } - pb.writeTileEntity(t) - pb.writeInt(x) - pb.writeInt(y) - pb.writeByte(scroll) + def sendMouseScroll(b: component.Buffer, x: Int, y: Int, scroll: Int) { + val pb = new PacketBuilder(PacketType.MouseScroll) - pb.sendToServer() + b.owner match { + case t: Buffer if t.tier > 0 => + pb.writeTileEntity(t) + case t: component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + case _ => return } + pb.writeInt(x) + pb.writeInt(y) + pb.writeByte(scroll) + + pb.sendToServer() + } def sendServerPower(t: Rack, number: Int, power: Boolean) { val pb = new PacketBuilder(PacketType.ComputerPower) diff --git a/li/cil/oc/client/gui/Buffer.scala b/li/cil/oc/client/gui/Buffer.scala index f751d6c14..ee141566a 100644 --- a/li/cil/oc/client/gui/Buffer.scala +++ b/li/cil/oc/client/gui/Buffer.scala @@ -43,7 +43,7 @@ trait Buffer extends GuiScreen { super.onGuiClosed() buffer.owner.currentGui = None for ((code, char) <- pressedKeys) { - PacketSender.sendKeyUp(buffer.owner, char, code) + PacketSender.sendKeyUp(buffer, char, code) } Keyboard.enableRepeatEvents(false) } @@ -75,17 +75,17 @@ trait Buffer extends GuiScreen { if (Keyboard.getEventKeyState) { val char = Keyboard.getEventCharacter if (!pressedKeys.contains(code) || !ignoreRepeat(char, code)) { - PacketSender.sendKeyDown(buffer.owner, char, code) + PacketSender.sendKeyDown(buffer, char, code) pressedKeys += code -> char } } else pressedKeys.remove(code) match { - case Some(char) => PacketSender.sendKeyUp(buffer.owner, char, code) + case Some(char) => PacketSender.sendKeyUp(buffer, char, code) case _ => // Wasn't pressed while viewing the screen. } if (isPasteShortcutPressed && Keyboard.getEventKeyState) { - PacketSender.sendClipboard(buffer.owner, GuiScreen.getClipboardString) + PacketSender.sendClipboard(buffer, GuiScreen.getClipboardString) } } } @@ -93,7 +93,7 @@ trait Buffer extends GuiScreen { override protected def mouseClicked(x: Int, y: Int, button: Int) { super.mouseClicked(x, y, button) if (button == 2) { - PacketSender.sendClipboard(buffer.owner, GuiScreen.getClipboardString) + PacketSender.sendClipboard(buffer, GuiScreen.getClipboardString) } } diff --git a/li/cil/oc/client/gui/Screen.scala b/li/cil/oc/client/gui/Screen.scala index f8cae6695..25c939742 100644 --- a/li/cil/oc/client/gui/Screen.scala +++ b/li/cil/oc/client/gui/Screen.scala @@ -3,14 +3,12 @@ package li.cil.oc.client.gui import li.cil.oc.client.PacketSender import li.cil.oc.client.renderer.MonospaceFontRenderer import li.cil.oc.client.renderer.gui.BufferRenderer -import li.cil.oc.common.tileentity +import li.cil.oc.common import li.cil.oc.util.RenderState import org.lwjgl.input.Mouse import org.lwjgl.opengl.GL11 -class Screen(val screen: tileentity.Screen) extends Buffer { - protected def buffer = screen.origin.buffer - +class Screen(val buffer: common.component.Buffer, val hasMouse: Boolean, val hasPower: () => Boolean) extends Buffer { private val bufferMargin = BufferRenderer.margin + BufferRenderer.innerMargin private var x, y = 0 @@ -27,14 +25,14 @@ class Screen(val screen: tileentity.Screen) extends Buffer { val (bw, bh) = buffer.resolution if (bx > 0 && by > 0 && bx <= bw && by <= bh) { val scroll = math.signum(Mouse.getEventDWheel) - PacketSender.sendMouseScroll(buffer.owner, bx, by, scroll) + PacketSender.sendMouseScroll(buffer, bx, by, scroll) } } } override protected def mouseClicked(mouseX: Int, mouseY: Int, button: Int) { super.mouseClicked(mouseX, mouseY, button) - if (screen.tier > 0) { + if (hasMouse) { if (button == 0) { clickOrDrag(mouseX, mouseY) } @@ -43,7 +41,7 @@ class Screen(val screen: tileentity.Screen) extends Buffer { protected override def mouseClickMove(mouseX: Int, mouseY: Int, button: Int, timeSinceLast: Long) { super.mouseClickMove(mouseX, mouseY, button, timeSinceLast) - if (screen.tier > 0 && timeSinceLast > 10) { + if (hasMouse && timeSinceLast > 10) { if (button == 0) { clickOrDrag(mouseX, mouseY) } @@ -64,7 +62,7 @@ class Screen(val screen: tileentity.Screen) extends Buffer { val (bw, bh) = buffer.resolution if (bx > 0 && by > 0 && bx <= bw && by <= bh) { if (bx != mx || by != my) { - PacketSender.sendMouseClick(buffer.owner, bx, by, mx > 0 && my > 0) + PacketSender.sendMouseClick(buffer, bx, by, mx > 0 && my > 0) mx = bx my = by } @@ -79,7 +77,7 @@ class Screen(val screen: tileentity.Screen) extends Buffer { def drawBuffer() { GL11.glTranslatef(x, y, 0) BufferRenderer.drawBackground() - if (screen.origin.hasPower) { + if (hasPower()) { GL11.glTranslatef(bufferMargin, bufferMargin, 0) RenderState.makeItBlend() BufferRenderer.drawText() diff --git a/li/cil/oc/client/renderer/block/BlockRenderer.scala b/li/cil/oc/client/renderer/block/BlockRenderer.scala index 141fdf6f0..1b8a30b36 100644 --- a/li/cil/oc/client/renderer/block/BlockRenderer.scala +++ b/li/cil/oc/client/renderer/block/BlockRenderer.scala @@ -103,7 +103,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { val front = rack.facing def renderSide(side: ForgeDirection, lx: Double, lz: Double, hx: Double, hz: Double) { if (side == front) { - for (i <- 0 until 4 if rack.isPresent(i)) { + for (i <- 0 until 4 if rack.isPresent(i).isDefined) { side match { case ForgeDirection.WEST => renderer.setRenderBounds(lx, v2 - (i + 1) * fs, lz + u1, u2, v2 - i * fs, hz - u1) diff --git a/li/cil/oc/common/component/Buffer.scala b/li/cil/oc/common/component/Buffer.scala index 98e7c030f..4ec2ec5e7 100644 --- a/li/cil/oc/common/component/Buffer.scala +++ b/li/cil/oc/common/component/Buffer.scala @@ -8,7 +8,7 @@ import li.cil.oc.{api, Settings} import net.minecraft.nbt.NBTTagCompound import scala.collection.convert.WrapAsScala._ -class Buffer(val owner: tileentity.Buffer) extends api.network.Environment with Persistable { +class Buffer(val owner: Buffer.Owner) extends api.network.Environment with Persistable { val node = api.Network.newNode(this, Visibility.Network). withComponent("screen"). withConnector(). @@ -140,3 +140,30 @@ class Buffer(val owner: tileentity.Buffer) extends api.network.Environment with nbt.setNewCompoundTag("buffer", buffer.save) } } + +object Buffer { + import li.cil.oc.client.gui + + trait Owner { + protected var _currentGui: Option[gui.Buffer] = None + + def currentGui = _currentGui + + def currentGui_=(value: Option[gui.Buffer]) = _currentGui = value + + def tier: Int + + def onScreenColorChange(foreground: Int, background: Int) + + def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) + + def onScreenDepthChange(depth: PackedColor.Depth.Value) + + def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) + + def onScreenResolutionChange(w: Int, h: Int) + + def onScreenSet(col: Int, row: Int, s: String) + } + +} \ No newline at end of file diff --git a/li/cil/oc/common/component/Terminal.scala b/li/cil/oc/common/component/Terminal.scala new file mode 100644 index 000000000..bcd5d699e --- /dev/null +++ b/li/cil/oc/common/component/Terminal.scala @@ -0,0 +1,94 @@ +package li.cil.oc.common.component + +import li.cil.oc.api.network.{Node, Visibility} +import li.cil.oc.common.tileentity +import li.cil.oc.server.component +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.PackedColor.Depth +import li.cil.oc.{Settings, common} +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.nbt.NBTTagCompound + +class Terminal(val rack: tileentity.Rack, val number: Int) extends Buffer.Owner { + val buffer = new common.component.Buffer(this) + val keyboard = if (buffer.node != null) { + buffer.node.setVisibility(Visibility.Neighbors) + new component.Keyboard { + override def isUseableByPlayer(p: EntityPlayer) = true // TODO if player has bound terminal + } + } + else null + + def isServer = rack.isServer + + def connect(node: Node) { + node.connect(buffer.node) + node.connect(keyboard.node) + buffer.node.connect(keyboard.node) + } + + def tier = 1 + + // ----------------------------------------------------------------------- // + + def load(nbt: NBTTagCompound) { + buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) + keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) + } + + def save(nbt: NBTTagCompound) { + nbt.setNewCompoundTag(Settings.namespace + "buffer", buffer.save) + nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save) + } + + // ----------------------------------------------------------------------- // + + def onScreenColorChange(foreground: Int, background: Int) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenColorChange(buffer, foreground, background) + } + else currentGui.foreach(_.recompileDisplayLists()) + } + + def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenCopy(buffer, col, row, w, h, tx, ty) + } + else currentGui.foreach(_.recompileDisplayLists()) + } + + def onScreenDepthChange(depth: Depth.Value) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenDepthChange(buffer, depth) + } + else currentGui.foreach(_.recompileDisplayLists()) + } + + def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenFill(buffer, col, row, w, h, c) + } + else currentGui.foreach(_.recompileDisplayLists()) + } + + def onScreenResolutionChange(w: Int, h: Int) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenResolutionChange(buffer, w, h) + } + else currentGui.foreach(_.recompileDisplayLists()) + } + + def onScreenSet(col: Int, row: Int, s: String) { + if (isServer) { + rack.markAsChanged() + ServerPacketSender.sendScreenSet(buffer, col, row, s) + } + else currentGui.foreach(_.recompileDisplayLists()) + } +} diff --git a/li/cil/oc/common/container/Server.scala b/li/cil/oc/common/container/Server.scala index 3ed7fb800..ccccce67e 100644 --- a/li/cil/oc/common/container/Server.scala +++ b/li/cil/oc/common/container/Server.scala @@ -6,7 +6,7 @@ import net.minecraft.entity.player.{EntityPlayer, InventoryPlayer} class Server(playerInventory: InventoryPlayer, serverInventory: ServerInventory) extends Player(playerInventory, serverInventory) { for (i <- 0 to 1) { - addSlotToContainer(76, 7 + i * slotSize, api.driver.Slot.Card, 1) + addSlotToContainer(76, 7 + i * slotSize, api.driver.Slot.Card, 2 - i) } for (i <- 0 to 3) { diff --git a/li/cil/oc/common/inventory/ServerInventory.scala b/li/cil/oc/common/inventory/ServerInventory.scala index 22e6b8abf..3062b44fe 100644 --- a/li/cil/oc/common/inventory/ServerInventory.scala +++ b/li/cil/oc/common/inventory/ServerInventory.scala @@ -18,7 +18,8 @@ trait ServerInventory extends ItemStackInventory { override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.itemDriverFor(stack)) match { case (_, None) => false // Invalid item. - case (0 | 1, Some(driver)) => driver.slot(stack) == Slot.Card && driver.tier(stack) <= 1 + case (0, Some(driver)) => driver.slot(stack) == Slot.Card && driver.tier(stack) <= 2 + case (1, Some(driver)) => driver.slot(stack) == Slot.Card && driver.tier(stack) <= 1 case (2 | 3 | 4 | 5, Some(driver)) => driver.slot(stack) == Slot.Processor && driver.tier(stack) <= 2 case (6 | 7 | 8 | 9, Some(driver)) => driver.slot(stack) == Slot.Memory && driver.tier(stack) <= 2 case (10 | 11 | 12 | 13, Some(driver)) => driver.slot(stack) == Slot.HardDiskDrive && driver.tier(stack) <= 2 diff --git a/li/cil/oc/common/item/Terminal.scala b/li/cil/oc/common/item/Terminal.scala index cdcde0908..841b382b3 100644 --- a/li/cil/oc/common/item/Terminal.scala +++ b/li/cil/oc/common/item/Terminal.scala @@ -1,5 +1,70 @@ package li.cil.oc.common.item +import cpw.mods.fml.relauncher.{SideOnly, Side} +import java.util +import li.cil.oc.common.{GuiType, tileentity} +import li.cil.oc.util.Tooltip +import li.cil.oc.{OpenComputers, Settings} +import net.minecraft.client.renderer.texture.IconRegister +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.world.World + class Terminal(val parent: Delegator) extends Delegate { val unlocalizedName = "Terminal" + + @SideOnly(Side.CLIENT) + override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { + tooltip.addAll(Tooltip.get(unlocalizedName)) + if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "server")) { + val server = stack.getTagCompound.getString(Settings.namespace + "server") + tooltip.add("§8" + server.substring(0, 13) + "...§7") + } + super.tooltipLines(stack, player, tooltip, advanced) + } + + override def registerIcons(iconRegister: IconRegister) = { + super.registerIcons(iconRegister) + + icon = iconRegister.registerIcon(Settings.resourceDomain + ":terminal") + } + + override def onItemUse(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float) = { + world.getBlockTileEntity(x, y, z) match { + case rack: tileentity.Rack if side == rack.facing.ordinal() => + val l = 2 / 16.0 + val h = 14 / 16.0 + val s = (((1 - hitY) - l) / (h - l) * 4).toInt + if (s >= 0 && s <= 3 && rack.items(s).isDefined) { + if (!world.isRemote) { + rack.servers(s) match { + case Some(server) => + if (!stack.hasTagCompound) { + stack.setTagCompound(new NBTTagCompound("tag")) + } + stack.getTagCompound.setString(Settings.namespace + "server", server.machine.address) + player.inventory.onInventoryChanged() + case _ => // Huh? + } + } + true + } + else false + case _ => super.onItemUseFirst(stack, player, world, x, y, z, side, hitX, hitY, hitZ) + } + } + + override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = { + if (!player.isSneaking && stack.hasTagCompound) { + val address = stack.getTagCompound.getString(Settings.namespace + "server") + if (address != null && !address.isEmpty) { + if (world.isRemote) { + player.openGui(OpenComputers, GuiType.Terminal.id, world, 0, 0, 0) + } + player.swingItem() + } + } + super.onItemRightClick(stack, world, player) + } } diff --git a/li/cil/oc/common/tileentity/Buffer.scala b/li/cil/oc/common/tileentity/Buffer.scala index e6de82e8f..98196e31e 100644 --- a/li/cil/oc/common/tileentity/Buffer.scala +++ b/li/cil/oc/common/tileentity/Buffer.scala @@ -2,29 +2,22 @@ package li.cil.oc.common.tileentity import cpw.mods.fml.relauncher.{Side, SideOnly} import li.cil.oc.api.network.Node -import li.cil.oc.client.gui import li.cil.oc.common.component import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.PackedColor import net.minecraft.nbt.NBTTagCompound -trait Buffer extends Environment { +trait Buffer extends Environment with component.Buffer.Owner { protected val _buffer = new component.Buffer(this) protected var _bufferIsDirty = false - protected var _currentGui = None: Option[gui.Buffer] - lazy val buffer = _buffer def bufferIsDirty = _bufferIsDirty def bufferIsDirty_=(value: Boolean) = _bufferIsDirty = value - def currentGui = _currentGui - - def currentGui_=(value: Option[gui.Buffer]) = _currentGui = value - def node: Node = buffer.node def tier: Int @@ -58,47 +51,47 @@ trait Buffer extends Environment { def onScreenColorChange(foreground: Int, background: Int) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenColorChange(this, foreground, background) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenColorChange(buffer, foreground, background) } } def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenCopy(buffer, col, row, w, h, tx, ty) } else markForRenderUpdate() } def onScreenDepthChange(depth: PackedColor.Depth.Value) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenDepthChange(this, depth) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenDepthChange(buffer, depth) } else markForRenderUpdate() } def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenFill(this, col, row, w, h, c) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenFill(buffer, col, row, w, h, c) } else markForRenderUpdate() } def onScreenResolutionChange(w: Int, h: Int) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenResolutionChange(this, w, h) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenResolutionChange(buffer, w, h) } else markForRenderUpdate() } def onScreenSet(col: Int, row: Int, s: String) { if (isServer) { - world.markTileEntityChunkModified(x, y, z, this.asInstanceOf[net.minecraft.tileentity.TileEntity]) - ServerPacketSender.sendScreenSet(this, col, row, s) + world.markTileEntityChunkModified(x, y, z, this) + ServerPacketSender.sendScreenSet(buffer, col, row, s) } else markForRenderUpdate() } diff --git a/li/cil/oc/common/tileentity/Keyboard.scala b/li/cil/oc/common/tileentity/Keyboard.scala index 3e9af91d8..c5898b620 100644 --- a/li/cil/oc/common/tileentity/Keyboard.scala +++ b/li/cil/oc/common/tileentity/Keyboard.scala @@ -12,7 +12,11 @@ import net.minecraftforge.common.ForgeDirection class Keyboard(isRemote: Boolean) extends Environment with SidedEnvironment with Analyzable with Rotatable with PassiveNode { def this() = this(false) - val keyboard = if (isRemote) null else new component.Keyboard(this) + val keyboard = if (isRemote) null else new component.Keyboard { + def isUseableByPlayer(p: EntityPlayer) = + world.getBlockTileEntity(x, y, z) == Keyboard.this && + p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64 + } def node = if (isClient) null else keyboard.node diff --git a/li/cil/oc/common/tileentity/Rack.scala b/li/cil/oc/common/tileentity/Rack.scala index e4b1a572a..a97bc19ba 100644 --- a/li/cil/oc/common/tileentity/Rack.scala +++ b/li/cil/oc/common/tileentity/Rack.scala @@ -3,12 +3,13 @@ package li.cil.oc.common.tileentity import cpw.mods.fml.common.Optional import cpw.mods.fml.relauncher.{Side, SideOnly} import li.cil.oc.api.network.{Visibility, Node, Analyzable} +import li.cil.oc.common import li.cil.oc.server.{PacketSender => ServerPacketSender, driver, component} import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.{api, Items, Settings} import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.{NBTTagString, NBTTagCompound} import net.minecraftforge.common.ForgeDirection import stargatetech2.api.bus.IBusDevice @@ -19,13 +20,15 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun val sides = Array.fill(servers.length)(ForgeDirection.UNKNOWN) + val terminals = (0 until servers.length).map(new common.component.Terminal(this, _)).toArray + // For client side, where we don't create the component. private val _isRunning = new Array[Boolean](getSizeInventory) private var hasChanged = false // For client side rendering. - var isPresent = new Array[Boolean](getSizeInventory) + var isPresent = Array.fill[Option[String]](getSizeInventory)(None) // ----------------------------------------------------------------------- // @@ -147,8 +150,6 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) - val sidesNbt = nbt.getByteArray(Settings.namespace + "sides").byteArray.map(ForgeDirection.getOrientation(_)) - Array.copy(sidesNbt, 0, sides, 0, math.min(sidesNbt.length, sides.length)) for (slot <- 0 until getSizeInventory) { if (getStackInSlot(slot) != null) { val server = new component.Server(this, slot) @@ -161,10 +162,15 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun case _ => } } + val sidesNbt = nbt.getByteArray(Settings.namespace + "sides").byteArray.map(ForgeDirection.getOrientation(_)) + Array.copy(sidesNbt, 0, sides, 0, math.min(sidesNbt.length, sides.length)) + val terminalsNbt = nbt.getTagList(Settings.namespace + "terminals").iterator[NBTTagCompound].toArray + for (i <- 0 until math.min(terminals.length, terminalsNbt.length)) { + terminals(i).load(terminalsNbt(i)) + } } override def writeToNBT(nbt: NBTTagCompound) { - nbt.setByteArray(Settings.namespace + "sides", sides.map(_.ordinal.toByte)) nbt.setNewTagList(Settings.namespace + "servers", servers map { case Some(server) => val serverNbt = new NBTTagCompound() @@ -173,6 +179,12 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun case _ => new NBTTagCompound() }) super.writeToNBT(nbt) + nbt.setByteArray(Settings.namespace + "sides", sides.map(_.ordinal.toByte)) + nbt.setNewTagList(Settings.namespace + "terminals", terminals.map(t => { + val terminalNbt = new NBTTagCompound() + t.save(terminalNbt) + terminalNbt + })) } @SideOnly(Side.CLIENT) @@ -180,17 +192,26 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun super.readFromNBTForClient(nbt) val isRunningNbt = nbt.getByteArray("isRunning").byteArray.map(_ == 1) Array.copy(isRunningNbt, 0, _isRunning, 0, math.min(isRunningNbt.length, _isRunning.length)) - val isPresentNbt = nbt.getByteArray("isPresent").byteArray.map(_ == 1) + val isPresentNbt = nbt.getTagList("isPresent").iterator[NBTTagString].map(value => if (value.data == "") None else Some(value.data)).toArray Array.copy(isPresentNbt, 0, isPresent, 0, math.min(isPresentNbt.length, isPresent.length)) val sidesNbt = nbt.getByteArray("sides").byteArray.map(ForgeDirection.getOrientation(_)) Array.copy(sidesNbt, 0, sides, 0, math.min(sidesNbt.length, sides.length)) + val terminalsNbt = nbt.getTagList("terminals").iterator[NBTTagCompound].toArray + for (i <- 0 until math.min(terminals.length, terminalsNbt.length)) { + terminals(i).buffer.buffer.load(terminalsNbt(i)) + } } override def writeToNBTForClient(nbt: NBTTagCompound) { super.writeToNBTForClient(nbt) nbt.setByteArray("isRunning", _isRunning.map(value => (if (value) 1 else 0).toByte)) - nbt.setByteArray("isPresent", servers.map(value => (if (value.isDefined) 1 else 0).toByte)) + nbt.setNewTagList("isPresent", servers.map(value => new NBTTagString(null, value.fold("")(_.machine.address)))) nbt.setByteArray("sides", sides.map(_.ordinal.toByte)) + nbt.setNewTagList("terminals", terminals.map(t => { + val terminalNbt = new NBTTagCompound() + t.buffer.buffer.save(terminalNbt) + terminalNbt + })) } // ----------------------------------------------------------------------- // @@ -202,6 +223,7 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun servers(number) match { case Some(server) if toGlobal(serverSide) == plug.side || serverSide == ForgeDirection.UNKNOWN => plug.node.connect(server.machine.node) + terminals(number).connect(server.machine.node) case _ => } } @@ -218,6 +240,7 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun val server = new component.Server(this, slot) servers(slot) = Some(server) reconnectServer(slot, server) + terminals(slot).connect(server.machine.node) } } diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index 6c3a26193..90a4da3ef 100644 --- a/li/cil/oc/common/tileentity/Robot.scala +++ b/li/cil/oc/common/tileentity/Robot.scala @@ -61,7 +61,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w val gpu = new GraphicsCard.Tier1 { override val maxResolution = (48, 14) } - val keyboard = new component.Keyboard(this) { + val keyboard = new component.Keyboard { override def isUseableByPlayer(p: EntityPlayer) = world.getBlockTileEntity(x, y, z) == proxy && p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64 @@ -306,11 +306,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w // ----------------------------------------------------------------------- // override def readFromNBT(nbt: NBTTagCompound) { - if (isServer) { - buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) - gpu.load(nbt.getCompoundTag(Settings.namespace + "gpu")) - keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) - } + buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) + gpu.load(nbt.getCompoundTag(Settings.namespace + "gpu")) + keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) if (nbt.hasKey(Settings.namespace + "owner")) { owner = nbt.getString(Settings.namespace + "owner") } diff --git a/li/cil/oc/common/tileentity/Screen.scala b/li/cil/oc/common/tileentity/Screen.scala index 9da64ec67..1474159ff 100644 --- a/li/cil/oc/common/tileentity/Screen.scala +++ b/li/cil/oc/common/tileentity/Screen.scala @@ -154,7 +154,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable // Convert to absolute coordinates and send the packet to the server. if (world.isRemote) { - ClientPacketSender.sendMouseClick(this, (brx * bw).toInt + 1, (bry * bh).toInt + 1, drag = false) + ClientPacketSender.sendMouseClick(this.buffer, (brx * bw).toInt + 1, (bry * bh).toInt + 1, drag = false) } true } diff --git a/li/cil/oc/server/PacketHandler.scala b/li/cil/oc/server/PacketHandler.scala index 776ea3088..f5f436a80 100644 --- a/li/cil/oc/server/PacketHandler.scala +++ b/li/cil/oc/server/PacketHandler.scala @@ -56,59 +56,68 @@ class PacketHandler extends CommonPacketHandler { } def onKeyDown(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(s: Screen) => + p.readTileEntity[TileEntity]() match { + case Some(t: Screen) => val char = Char.box(p.readChar()) val code = Int.box(p.readInt()) - s.screens.foreach(_.node.sendToNeighbors("keyboard.keyDown", p.player, char, code)) - case Some(e) => e.buffer.node.sendToNeighbors("keyboard.keyDown", p.player, Char.box(p.readChar()), Int.box(p.readInt())) + t.screens.foreach(_.node.sendToNeighbors("keyboard.keyDown", p.player, char, code)) + case Some(t: Buffer) => t.buffer.node.sendToNeighbors("keyboard.keyDown", p.player, Char.box(p.readChar()), Int.box(p.readInt())) + case Some(t: Rack) => t.terminals(p.readInt()).buffer.node.sendToNeighbors("keyboard.keyDown", p.player, Char.box(p.readChar()), Int.box(p.readInt())) case _ => // Invalid packet. } def onKeyUp(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(s: Screen) => + p.readTileEntity[TileEntity]() match { + case Some(t: Screen) => val char = Char.box(p.readChar()) val code = Int.box(p.readInt()) - s.screens.foreach(_.node.sendToNeighbors("keyboard.keyUp", p.player, char, code)) - case Some(e) => e.buffer.node.sendToNeighbors("keyboard.keyUp", p.player, Char.box(p.readChar()), Int.box(p.readInt())) + t.screens.foreach(_.node.sendToNeighbors("keyboard.keyUp", p.player, char, code)) + case Some(t: Buffer) => t.buffer.node.sendToNeighbors("keyboard.keyUp", p.player, Char.box(p.readChar()), Int.box(p.readInt())) + case Some(t: Rack) => t.terminals(p.readInt()).buffer.node.sendToNeighbors("keyboard.keyUp", p.player, Char.box(p.readChar()), Int.box(p.readInt())) case _ => // Invalid packet. } def onClipboard(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(s: Screen) => + p.readTileEntity[TileEntity]() match { + case Some(t: Screen) => val value = p.readUTF() - s.screens.foreach(_.node.sendToNeighbors("keyboard.clipboard", p.player, value)) - case Some(e) => e.buffer.node.sendToNeighbors("keyboard.clipboard", p.player, p.readUTF()) + t.screens.foreach(_.node.sendToNeighbors("keyboard.clipboard", p.player, value)) + case Some(t: Buffer) => t.buffer.node.sendToNeighbors("keyboard.clipboard", p.player, p.readUTF()) + case Some(t: Rack) => t.terminals(p.readInt()).buffer.node.sendToNeighbors("keyboard.clipboard", p.player, p.readUTF()) case _ => // Invalid packet. } - def onMouseClick(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(s: Screen) => p.player match { - case player: EntityPlayer => - val x = p.readInt() - val y = p.readInt() - val what = if (p.readBoolean()) "drag" else "touch" - s.origin.node.sendToReachable("computer.checked_signal", player, what, Int.box(x), Int.box(y), player.getCommandSenderName) - case _ => - } + def onMouseClick(p: PacketParser) { + p.player match { + case player: EntityPlayer => + val node = p.readTileEntity[TileEntity]() match { + case Some(t: Screen) => t.origin.node + case Some(t: Rack) => t.terminals(p.readInt()).buffer.node + case _ => return // Invalid packet. + } + val x = p.readInt() + val y = p.readInt() + val what = if (p.readBoolean()) "drag" else "touch" + node.sendToReachable("computer.checked_signal", player, what, Int.box(x), Int.box(y), player.getCommandSenderName) case _ => // Invalid packet. } + } - def onMouseScroll(p: PacketParser) = - p.readTileEntity[Buffer]() match { - case Some(s: Screen) => p.player match { - case player: EntityPlayer => - val x = p.readInt() - val y = p.readInt() - val scroll = p.readByte() - s.origin.node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(scroll), player.getCommandSenderName) - case _ => - } + def onMouseScroll(p: PacketParser) { + p.player match { + case player: EntityPlayer => + val node = p.readTileEntity[TileEntity]() match { + case Some(t: Screen) => t.origin.node + case Some(t: Rack) => t.terminals(p.readInt()).buffer.node + case _ => return // Invalid packet. + } + val x = p.readInt() + val y = p.readInt() + val scroll = p.readByte() + node.sendToReachable("computer.checked_signal", player, "scroll", Int.box(x), Int.box(y), Int.box(scroll), player.getCommandSenderName) case _ => // Invalid packet. } + } def onServerSide(p: PacketParser) = p.readTileEntity[Rack]() match { diff --git a/li/cil/oc/server/PacketSender.scala b/li/cil/oc/server/PacketSender.scala index 3997a60b6..f1f6ba318 100644 --- a/li/cil/oc/server/PacketSender.scala +++ b/li/cil/oc/server/PacketSender.scala @@ -1,6 +1,7 @@ package li.cil.oc.server import cpw.mods.fml.common.network.Player +import li.cil.oc.common import li.cil.oc.common.PacketBuilder import li.cil.oc.common.PacketType import li.cil.oc.common.tileentity._ @@ -156,20 +157,38 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendScreenColorChange(t: Buffer, foreground: Int, background: Int) { + def sendScreenColorChange(b: common.component.Buffer, foreground: Int, background: Int) { val pb = new PacketBuilder(PacketType.ScreenColorChange) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(foreground) pb.writeInt(background) pb.sendToNearbyPlayers(t) } - def sendScreenCopy(t: Buffer, col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { + def sendScreenCopy(b: common.component.Buffer, col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { val pb = new PacketBuilder(PacketType.ScreenCopy) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(col) pb.writeInt(row) pb.writeInt(w) @@ -180,19 +199,37 @@ object PacketSender { pb.sendToNearbyPlayers(t) } - def sendScreenDepthChange(t: Buffer, value: PackedColor.Depth.Value) { + def sendScreenDepthChange(b: common.component.Buffer, value: PackedColor.Depth.Value) { val pb = new PacketBuilder(PacketType.ScreenDepthChange) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(value.id) pb.sendToNearbyPlayers(t) } - def sendScreenFill(t: Buffer, col: Int, row: Int, w: Int, h: Int, c: Char) { + def sendScreenFill(b: common.component.Buffer, col: Int, row: Int, w: Int, h: Int, c: Char) { val pb = new PacketBuilder(PacketType.ScreenFill) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(col) pb.writeInt(row) pb.writeInt(w) @@ -211,20 +248,38 @@ object PacketSender { pb.sendToNearbyPlayers(t, 64) } - def sendScreenResolutionChange(t: Buffer, w: Int, h: Int) { + def sendScreenResolutionChange(b: common.component.Buffer, w: Int, h: Int) { val pb = new PacketBuilder(PacketType.ScreenResolutionChange) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(w) pb.writeInt(h) pb.sendToNearbyPlayers(t) } - def sendScreenSet(t: Buffer, col: Int, row: Int, s: String) { + def sendScreenSet(b: common.component.Buffer, col: Int, row: Int, s: String) { val pb = new PacketBuilder(PacketType.ScreenSet) - pb.writeTileEntity(t) + val t = b.owner match { + case t: Buffer => + pb.writeTileEntity(t) + t + case t: common.component.Terminal => + pb.writeTileEntity(t.rack) + pb.writeInt(t.number) + t.rack + case _ => return + } pb.writeInt(col) pb.writeInt(row) pb.writeUTF(s) @@ -236,7 +291,13 @@ object PacketSender { val pb = new PacketBuilder(PacketType.ServerPresence) pb.writeTileEntity(t) - t.servers.foreach(server => pb.writeBoolean(server.isDefined)) + t.servers.foreach { + case Some(server) => + pb.writeBoolean(true) + pb.writeUTF(server.machine.address) + case _ => + pb.writeBoolean(false) + } pb.sendToNearbyPlayers(t) } diff --git a/li/cil/oc/server/component/Keyboard.scala b/li/cil/oc/server/component/Keyboard.scala index 26281086c..36fab3a39 100644 --- a/li/cil/oc/server/component/Keyboard.scala +++ b/li/cil/oc/server/component/Keyboard.scala @@ -3,7 +3,6 @@ package li.cil.oc.server.component import cpw.mods.fml.common.IPlayerTracker import li.cil.oc.api.Network import li.cil.oc.api.network.{Node, Visibility, Message} -import li.cil.oc.common.tileentity.Environment import net.minecraft.entity.player.EntityPlayer import net.minecraftforge.common.MinecraftForge import net.minecraftforge.event.{Event, ForgeSubscribe} @@ -12,7 +11,7 @@ import scala.collection.mutable // TODO key up when screen is disconnected from which the key down came // TODO key up after load for anything that was pressed -class Keyboard(owner: Environment) extends ManagedComponent { +abstract class Keyboard extends ManagedComponent { val node = Network.newNode(this, Visibility.Network). withComponent("keyboard"). create() @@ -71,9 +70,7 @@ class Keyboard(owner: Environment) extends ManagedComponent { // ----------------------------------------------------------------------- // - def isUseableByPlayer(p: EntityPlayer) = - owner.world.getBlockTileEntity(owner.x, owner.y, owner.z) == owner && - p.getDistanceSq(owner.x + 0.5, owner.y + 0.5, owner.z + 0.5) <= 64 + def isUseableByPlayer(p: EntityPlayer): Boolean protected def signal(args: AnyRef*) = node.sendToReachable("computer.checked_signal", args: _*) diff --git a/li/cil/oc/server/component/Machine.scala b/li/cil/oc/server/component/Machine.scala index 7ac2294b2..2758f0cb6 100644 --- a/li/cil/oc/server/component/Machine.scala +++ b/li/cil/oc/server/component/Machine.scala @@ -711,6 +711,7 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi switchTo(Machine.State.Stopping) } case result: ExecutionResult.Error => + crash(result.message) } case Machine.State.Paused => state.pop() // Paused diff --git a/li/cil/oc/server/component/Server.scala b/li/cil/oc/server/component/Server.scala index 4d6015efa..668ac93cd 100644 --- a/li/cil/oc/server/component/Server.scala +++ b/li/cil/oc/server/component/Server.scala @@ -29,6 +29,8 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Machine.Owner { override def getInventoryStackLimit = 1 } + // ----------------------------------------------------------------------- // + def installedMemory = inventory.items.foldLeft(0)((sum, stack) => sum + (stack match { case Some(item) => Registry.itemDriverFor(item) match { case Some(driver: driver.Memory) => driver.amount(item) @@ -49,6 +51,8 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Machine.Owner { def markAsChanged() = rack.markAsChanged() + // ----------------------------------------------------------------------- // + override def onConnect(node: Node) = inventory.onConnect(node) override def onDisconnect(node: Node) = inventory.onDisconnect(node)