remote terminal basic stuff. can be bound and used to control servers. servers simply have a neighbor visible built-in screen and keyboard for which the gui can be opened using the terminal item once bound. still missing a couple of checks.

This commit is contained in:
Florian Nücke 2014-01-17 17:34:19 +01:00
parent 125cedeadc
commit 0f067e37c4
23 changed files with 541 additions and 188 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

View File

@ -0,0 +1,6 @@
{
"animation": {
"frametime": 10,
"frames": [ 0, 1 ]
}
}

View File

@ -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
}
}

View File

@ -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.
}
}

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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()

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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())
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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

View File

@ -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)
}
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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: _*)

View File

@ -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

View File

@ -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)