mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-14 17:56:34 -04:00
started working on redstone interfacing; improved term.write performance by caching the screen's resolution and added a signal for screen size changes
This commit is contained in:
parent
484dfd6a83
commit
12da32bc6c
@ -125,6 +125,7 @@ end)
|
|||||||
|
|
||||||
--[[ Setup terminal API. ]]
|
--[[ Setup terminal API. ]]
|
||||||
local idGpu, idScreen = 0, 0
|
local idGpu, idScreen = 0, 0
|
||||||
|
local screenWidth, screenHeight = 0, 0
|
||||||
local boundGpu = nil
|
local boundGpu = nil
|
||||||
local cursorX, cursorY = 1, 1
|
local cursorX, cursorY = 1, 1
|
||||||
|
|
||||||
@ -157,22 +158,36 @@ event.listen("component_uninstalled", function(_, id)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
event.listen("screen_resized", function(_, address, w, h)
|
||||||
|
local id = component.id(address)
|
||||||
|
if id == idScreen then
|
||||||
|
screenWidth = w
|
||||||
|
screenHeight = h
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
term = {}
|
term = {}
|
||||||
|
|
||||||
function term.gpu()
|
function term.gpu()
|
||||||
return boundGpu
|
return boundGpu
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function term.screenSize()
|
||||||
|
return screenWidth, screenHeight
|
||||||
|
end
|
||||||
|
|
||||||
local function bindIfPossible()
|
local function bindIfPossible()
|
||||||
if idGpu > 0 and idScreen > 0 then
|
if idGpu > 0 and idScreen > 0 then
|
||||||
if not boundGpu then
|
if not boundGpu then
|
||||||
local function gpu() return component.address(idGpu) end
|
local function gpu() return component.address(idGpu) end
|
||||||
local function screen() return component.address(idScreen) end
|
local function screen() return component.address(idScreen) end
|
||||||
boundGpu = driver.gpu.bind(gpu, screen)
|
boundGpu = driver.gpu.bind(gpu, screen)
|
||||||
|
screenWidth, screenHeight = boundGpu.getResolution()
|
||||||
event.fire("term_available")
|
event.fire("term_available")
|
||||||
end
|
end
|
||||||
elseif boundGpu then
|
elseif boundGpu then
|
||||||
boundGpu = nil
|
boundGpu = nil
|
||||||
|
screenWidth, screenHeight = 0, 0
|
||||||
event.fire("term_unavailable")
|
event.fire("term_unavailable")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -208,18 +223,18 @@ end
|
|||||||
|
|
||||||
function term.write(value, wrap)
|
function term.write(value, wrap)
|
||||||
value = tostring(value)
|
value = tostring(value)
|
||||||
local gpu = term.gpu()
|
local w, h = screenWidth, screenHeight
|
||||||
if not gpu or value:len() == 0 then return end
|
if value:len() == 0 or not boundGpu or w < 1 or h < 1 then
|
||||||
local w, h = gpu.getResolution()
|
return
|
||||||
if not w or not h or w < 1 or h < 1 then return end
|
end
|
||||||
local function checkCursor()
|
local function checkCursor()
|
||||||
if cursorX > w then
|
if cursorX > w then
|
||||||
cursorX = 1
|
cursorX = 1
|
||||||
cursorY = cursorY + 1
|
cursorY = cursorY + 1
|
||||||
end
|
end
|
||||||
if cursorY > h then
|
if cursorY > h then
|
||||||
gpu.copy(1, 1, w, h, 0, -1)
|
boundGpu.copy(1, 1, w, h, 0, -1)
|
||||||
gpu.fill(1, h, w, 1, " ")
|
boundGpu.fill(1, h, w, 1, " ")
|
||||||
cursorY = h
|
cursorY = h
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -227,12 +242,12 @@ function term.write(value, wrap)
|
|||||||
while wrap and line:len() > w - cursorX + 1 do
|
while wrap and line:len() > w - cursorX + 1 do
|
||||||
local partial = line:sub(1, w - cursorX + 1)
|
local partial = line:sub(1, w - cursorX + 1)
|
||||||
line = line:sub(partial:len() + 1)
|
line = line:sub(partial:len() + 1)
|
||||||
gpu.set(cursorX, cursorY, partial)
|
boundGpu.set(cursorX, cursorY, partial)
|
||||||
cursorX = cursorX + partial:len()
|
cursorX = cursorX + partial:len()
|
||||||
checkCursor()
|
checkCursor()
|
||||||
end
|
end
|
||||||
if line:len() > 0 then
|
if line:len() > 0 then
|
||||||
gpu.set(cursorX, cursorY, line)
|
boundGpu.set(cursorX, cursorY, line)
|
||||||
cursorX = cursorX + line:len()
|
cursorX = cursorX + line:len()
|
||||||
end
|
end
|
||||||
if nl:len() == 1 then
|
if nl:len() == 1 then
|
||||||
@ -244,10 +259,8 @@ function term.write(value, wrap)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function term.clear()
|
function term.clear()
|
||||||
local gpu = term.gpu()
|
if not boundGpu then return end
|
||||||
if not gpu then return end
|
boundGpu.fill(1, 1, screenWidth, screenHeight, " ")
|
||||||
local w, h = gpu.getResolution()
|
|
||||||
gpu.fill(1, 1, w, h, " ")
|
|
||||||
cursorX, cursorY = 1, 1
|
cursorX, cursorY = 1, 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -332,7 +345,7 @@ while true do
|
|||||||
if gpu then
|
if gpu then
|
||||||
local x, y = term.getCursor()
|
local x, y = term.getCursor()
|
||||||
if blinkState then
|
if blinkState then
|
||||||
term.gpu().set(x, y, string.char(9608)) -- Solid block.
|
term.gpu().set(x, y, string.char(0x2588)) -- Solid block.
|
||||||
else
|
else
|
||||||
term.gpu().set(x, y, " ")
|
term.gpu().set(x, y, " ")
|
||||||
end
|
end
|
||||||
|
@ -137,5 +137,5 @@ for k, v in pairs(driver.keyboard.keys) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
function driver.keyboard.keys.isControl(char)
|
function driver.keyboard.keys.isControl(char)
|
||||||
return char < 0x20 or (char >= 0x7F and char < 0x9F)
|
return char < 0x20 or (char >= 0x7F and char <= 0x9F)
|
||||||
end
|
end
|
38
assets/opencomputers/lua/redstone.lua
Normal file
38
assets/opencomputers/lua/redstone.lua
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
--[[ API for Redstone Cards. ]]
|
||||||
|
|
||||||
|
driver.redstone = {}
|
||||||
|
|
||||||
|
driver.redstone.sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||||
|
|
||||||
|
-- Add inverse mapping and aliases.
|
||||||
|
for k, v in pairs(sides) do sides[v] = k end
|
||||||
|
sides.up = sides.top
|
||||||
|
sides.down = sides.bottom
|
||||||
|
|
||||||
|
function driver.redstone.getAnalogInput(card, side)
|
||||||
|
checkArg(1, side, "number")
|
||||||
|
sendToNode(card, os.address(), "redstone.input", side)
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.redstone.getAnalogOutput(card, side)
|
||||||
|
checkArg(1, side, "number")
|
||||||
|
sendToNode(card, os.address(), "redstone.output", side)
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.redstone.setAnalogOutput(card, side, value)
|
||||||
|
checkArg(1, side, "number")
|
||||||
|
checkArg(2, side, "number")
|
||||||
|
sendToNode(card, os.address(), "redstone.output=", side, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
function getInput(side)
|
||||||
|
return getAnalogInput(side) > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function getOutput(side)
|
||||||
|
return getAnalogOutput(side) > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function setOutput(side, value)
|
||||||
|
rs.setAnalogOutput(side, value and 15 or 0)
|
||||||
|
end
|
@ -1,25 +0,0 @@
|
|||||||
--[[
|
|
||||||
The Redstone API, provided by Redstone components.
|
|
||||||
]]
|
|
||||||
|
|
||||||
sides = {"top", "bottom", "left", "right", "front", "back"}
|
|
||||||
|
|
||||||
function getSides()
|
|
||||||
return sides
|
|
||||||
end
|
|
||||||
|
|
||||||
function getInput(side)
|
|
||||||
return getAnalogInput(side) > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function getOutput(side)
|
|
||||||
return getAnalogOutput(side) > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function setOutput(side, value)
|
|
||||||
rs.setAnalogOutput(side, value and 15 or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
getAnalogInput = _G.getAnalogInput
|
|
||||||
getAnalogOutput = _G.getAnalogOutput
|
|
||||||
setAnalogOutput = _G.setAnalogOutput
|
|
@ -1,18 +1,20 @@
|
|||||||
package li.cil.oc
|
package li.cil.oc
|
||||||
|
|
||||||
import li.cil.oc.common.items.ItemGraphicsCard
|
import li.cil.oc.common.items.{ItemRedstoneCard, ItemGraphicsCard, ItemHDD}
|
||||||
import li.cil.oc.common.items.ItemHDD
|
|
||||||
import li.cil.oc.common.util.ItemComponentCache
|
import li.cil.oc.common.util.ItemComponentCache
|
||||||
import li.cil.oc.server.components.GraphicsCard
|
import li.cil.oc.server.components.{RedstoneCard, GraphicsCard}
|
||||||
|
|
||||||
object Items {
|
object Items {
|
||||||
var gpu: ItemGraphicsCard = null
|
var gpu: ItemGraphicsCard = null
|
||||||
var hdd: ItemHDD = null
|
var hdd: ItemHDD = null
|
||||||
|
var rs: ItemRedstoneCard = null
|
||||||
|
|
||||||
def init() {
|
def init() {
|
||||||
gpu = new ItemGraphicsCard
|
gpu = new ItemGraphicsCard
|
||||||
hdd = new ItemHDD
|
hdd = new ItemHDD
|
||||||
|
rs = new ItemRedstoneCard
|
||||||
|
|
||||||
ItemComponentCache.register(gpu.itemID, nbt => new GraphicsCard(nbt))
|
ItemComponentCache.register(gpu.itemID, nbt => new GraphicsCard(nbt))
|
||||||
|
ItemComponentCache.register(rs.itemID, nbt => new RedstoneCard(nbt))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -122,9 +122,9 @@ trait INetwork {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Messages should have a unique name to allow differentiating them when
|
* Messages should have a unique name to allow differentiating them when
|
||||||
* handling them in a network node. For example, computers will try to parse
|
* handling them in a network node. For example, computers will try to parse
|
||||||
* messages named "signal" by converting the message data to a signal and
|
* messages named "computer.signal" by converting the message data to a
|
||||||
* inject that signal into the Lua VM, so no message not used for this purpose
|
* signal and inject that signal into the Lua VM, so no message not used for
|
||||||
* should be named "signal".
|
* this purpose should be named "computer.signal".
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that message handlers may also return results. In this case that
|
* Note that message handlers may also return results. In this case that
|
||||||
* result will be returned from this function. In the case that there are
|
* result will be returned from this function. In the case that there are
|
||||||
@ -144,9 +144,9 @@ trait INetwork {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Messages should have a unique name to allow differentiating them when
|
* Messages should have a unique name to allow differentiating them when
|
||||||
* handling them in a network node. For example, computers will try to parse
|
* handling them in a network node. For example, computers will try to parse
|
||||||
* messages named "signal" by converting the message data to a signal and
|
* messages named "computer.signal" by converting the message data to a
|
||||||
* inject that signal into the Lua VM, so no message not used for this purpose
|
* signal and inject that signal into the Lua VM, so no message not used for
|
||||||
* should be named "signal".
|
* this purpose should be named "computer.signal".
|
||||||
*
|
*
|
||||||
* @param source the node that sends the message.
|
* @param source the node that sends the message.
|
||||||
* @param data the message to send.
|
* @param data the message to send.
|
||||||
|
@ -50,11 +50,13 @@ trait IScreenEnvironment extends INetworkNode {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def onScreenResolutionChange(w: Int, h: Int)
|
def onScreenResolutionChange(w: Int, h: Int) = if (network != null) {
|
||||||
|
network.sendToAll(this, "computer.signal", "screen_resized", this.address, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
def onScreenSet(col: Int, row: Int, s: String)
|
def onScreenSet(col: Int, row: Int, s: String) {}
|
||||||
|
|
||||||
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char)
|
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {}
|
||||||
|
|
||||||
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int)
|
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {}
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ import net.minecraft.world.World
|
|||||||
class ItemGraphicsCard extends Item(Config.itemGPUId) {
|
class ItemGraphicsCard extends Item(Config.itemGPUId) {
|
||||||
setMaxStackSize(1)
|
setMaxStackSize(1)
|
||||||
//setHasSubtypes(true)
|
//setHasSubtypes(true)
|
||||||
setUnlocalizedName("oc.gpu")
|
setUnlocalizedName("Graphics Card")
|
||||||
setCreativeTab(CreativeTab)
|
setCreativeTab(CreativeTab)
|
||||||
|
|
||||||
override def shouldPassSneakingClickToBlock(world: World, x: Int, y: Int, z: Int) = true
|
override def shouldPassSneakingClickToBlock(world: World, x: Int, y: Int, z: Int) = true
|
||||||
|
14
li/cil/oc/common/items/ItemRedstoneCard.scala
Normal file
14
li/cil/oc/common/items/ItemRedstoneCard.scala
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package li.cil.oc.common.items
|
||||||
|
|
||||||
|
import li.cil.oc.{CreativeTab, Config}
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.world.World
|
||||||
|
|
||||||
|
class ItemRedstoneCard extends Item(Config.itemGPUId + 1) {
|
||||||
|
setMaxStackSize(1)
|
||||||
|
//setHasSubtypes(true)
|
||||||
|
setUnlocalizedName("Redstone Card")
|
||||||
|
setCreativeTab(CreativeTab)
|
||||||
|
|
||||||
|
override def shouldPassSneakingClickToBlock(world: World, x: Int, y: Int, z: Int) = true
|
||||||
|
}
|
@ -4,13 +4,15 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
import li.cil.oc.api.INetworkMessage
|
import li.cil.oc.api.INetworkMessage
|
||||||
import li.cil.oc.client.computer.{Computer => ClientComputer}
|
import li.cil.oc.client.computer.{Computer => ClientComputer}
|
||||||
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
||||||
|
import li.cil.oc.server.components.RedstoneEnabled
|
||||||
import li.cil.oc.server.computer.IComputerEnvironment
|
import li.cil.oc.server.computer.IComputerEnvironment
|
||||||
import li.cil.oc.server.computer.{Computer => ServerComputer}
|
import li.cil.oc.server.computer.{Computer => ServerComputer}
|
||||||
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
import li.cil.oc.server.{PacketSender => ServerPacketSender}
|
||||||
import net.minecraft.entity.player.EntityPlayer
|
import net.minecraft.entity.player.EntityPlayer
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import net.minecraftforge.common.ForgeDirection
|
||||||
|
|
||||||
class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with IComputerEnvironment with ItemComponentProxy {
|
class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with IComputerEnvironment with ItemComponentProxy with RedstoneEnabled {
|
||||||
def this() = this(false)
|
def this() = this(false)
|
||||||
|
|
||||||
protected val computer =
|
protected val computer =
|
||||||
@ -36,7 +38,7 @@ class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with ICo
|
|||||||
computer.signal("component_removed", message.source.address); None
|
computer.signal("component_removed", message.source.address); None
|
||||||
case Array(oldAddress: Integer) if message.name == "network.reconnect" && isRunning =>
|
case Array(oldAddress: Integer) if message.name == "network.reconnect" && isRunning =>
|
||||||
computer.signal("component_changed", message.source.address, oldAddress); None
|
computer.signal("component_changed", message.source.address, oldAddress); None
|
||||||
case Array(name: String, args@_*) if message.name == "signal" =>
|
case Array(name: String, args@_*) if message.name == "computer.signal" =>
|
||||||
computer.signal(name, args: _*); None
|
computer.signal(name, args: _*); None
|
||||||
case _ => None
|
case _ => None
|
||||||
}
|
}
|
||||||
@ -100,6 +102,15 @@ class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with ICo
|
|||||||
ClientPacketSender.sendComputerStateRequest(this)
|
ClientPacketSender.sendComputerStateRequest(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
// RedstoneEnabled
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
def input(side: ForgeDirection): Int = worldObj.isBlockProvidingPowerTo(
|
||||||
|
xCoord + side.offsetX, yCoord + side.offsetY, zCoord + side.offsetZ, side.getOpposite.ordinal)
|
||||||
|
|
||||||
|
// TODO output
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
// Interfaces and updating
|
// Interfaces and updating
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
@ -12,15 +12,15 @@ class TileEntityKeyboard extends TileEntityRotatable with INetworkNode {
|
|||||||
super.receive(message)
|
super.receive(message)
|
||||||
message.data match {
|
message.data match {
|
||||||
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyDown" => if (isUseableByPlayer(p)) {
|
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyDown" => if (isUseableByPlayer(p)) {
|
||||||
network.sendToAll(this, "signal", "key_down", char, code)
|
network.sendToAll(this, "computer.signal", "key_down", char, code)
|
||||||
message.cancel() // One keyboard is enough.
|
message.cancel() // One keyboard is enough.
|
||||||
}
|
}
|
||||||
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyUp" => if (isUseableByPlayer(p)) {
|
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyUp" => if (isUseableByPlayer(p)) {
|
||||||
network.sendToAll(this, "signal", "key_up", char, code)
|
network.sendToAll(this, "computer.signal", "key_up", char, code)
|
||||||
message.cancel() // One keyboard is enough.
|
message.cancel() // One keyboard is enough.
|
||||||
}
|
}
|
||||||
case Array(p: Player, value: String) if message.name == "keyboard.clipboard" => if (isUseableByPlayer(p)) {
|
case Array(p: Player, value: String) if message.name == "keyboard.clipboard" => if (isUseableByPlayer(p)) {
|
||||||
network.sendToAll(this, "signal", "clipboard", value)
|
network.sendToAll(this, "computer.signal", "clipboard", value)
|
||||||
message.cancel()
|
message.cancel()
|
||||||
}
|
}
|
||||||
case _ => // Ignore.
|
case _ => // Ignore.
|
||||||
|
@ -32,7 +32,8 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
|
|||||||
// IScreenEnvironment
|
// IScreenEnvironment
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
def onScreenResolutionChange(w: Int, h: Int) =
|
override def onScreenResolutionChange(w: Int, h: Int) = {
|
||||||
|
super.onScreenResolutionChange(w, h)
|
||||||
if (worldObj.isRemote) {
|
if (worldObj.isRemote) {
|
||||||
gui.foreach(_.setSize(w, h))
|
gui.foreach(_.setSize(w, h))
|
||||||
}
|
}
|
||||||
@ -40,8 +41,10 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
|
|||||||
markAsChanged()
|
markAsChanged()
|
||||||
ServerPacketSender.sendScreenResolutionChange(this, w, h)
|
ServerPacketSender.sendScreenResolutionChange(this, w, h)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def onScreenSet(col: Int, row: Int, s: String) =
|
override def onScreenSet(col: Int, row: Int, s: String) = {
|
||||||
|
super.onScreenSet(col, row, s)
|
||||||
if (worldObj.isRemote) {
|
if (worldObj.isRemote) {
|
||||||
gui.foreach(_.updateText())
|
gui.foreach(_.updateText())
|
||||||
}
|
}
|
||||||
@ -49,8 +52,10 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
|
|||||||
markAsChanged()
|
markAsChanged()
|
||||||
ServerPacketSender.sendScreenSet(this, col, row, s)
|
ServerPacketSender.sendScreenSet(this, col, row, s)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) =
|
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) = {
|
||||||
|
super.onScreenFill(col, row, w, h, c)
|
||||||
if (worldObj.isRemote) {
|
if (worldObj.isRemote) {
|
||||||
gui.foreach(_.updateText())
|
gui.foreach(_.updateText())
|
||||||
}
|
}
|
||||||
@ -58,8 +63,10 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
|
|||||||
markAsChanged()
|
markAsChanged()
|
||||||
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
|
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) =
|
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) = {
|
||||||
|
super.onScreenCopy(col, row, w, h, tx, ty)
|
||||||
if (worldObj.isRemote) {
|
if (worldObj.isRemote) {
|
||||||
gui.foreach(_.updateText())
|
gui.foreach(_.updateText())
|
||||||
}
|
}
|
||||||
@ -67,6 +74,7 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
|
|||||||
markAsChanged()
|
markAsChanged()
|
||||||
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
|
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private def markAsChanged(): Unit =
|
private def markAsChanged(): Unit =
|
||||||
worldObj.updateTileEntityChunkAndDoNothing(
|
worldObj.updateTileEntityChunkAndDoNothing(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package li.cil.oc.common.util
|
package li.cil.oc.common.util
|
||||||
|
|
||||||
import com.google.common.collect.MapMaker
|
import com.google.common.collect.MapMaker
|
||||||
|
import li.cil.oc.server.components.ItemComponent
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
import scala.collection.{JavaConversions, mutable}
|
import scala.collection.{JavaConversions, mutable}
|
||||||
@ -13,12 +14,12 @@ import scala.collection.{JavaConversions, mutable}
|
|||||||
object ItemComponentCache {
|
object ItemComponentCache {
|
||||||
private val caches = mutable.Map.empty[Int, Cache[_]]
|
private val caches = mutable.Map.empty[Int, Cache[_]]
|
||||||
|
|
||||||
def get[T](item: ItemStack) = caches.get(item.itemID) match {
|
def get[T <: ItemComponent](item: ItemStack) = caches.get(item.itemID) match {
|
||||||
case None => None
|
case None => None
|
||||||
case Some(cache) => cache.asInstanceOf[Cache[T]].get(item)
|
case Some(cache) => cache.asInstanceOf[Cache[T]].get(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
def register[T](id: Int, constructor: (NBTTagCompound) => T): Unit =
|
def register[T <: ItemComponent](id: Int, constructor: (NBTTagCompound) => T): Unit =
|
||||||
caches += id -> new Cache[T](id, constructor)
|
caches += id -> new Cache[T](id, constructor)
|
||||||
|
|
||||||
private class Cache[T](val id: Int, val constructor: (NBTTagCompound) => T) {
|
private class Cache[T](val id: Int, val constructor: (NBTTagCompound) => T) {
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package li.cil.oc.server.components
|
package li.cil.oc.server.components
|
||||||
|
|
||||||
class Disk {
|
import li.cil.oc.api.INetworkNode
|
||||||
|
|
||||||
|
class Disk extends INetworkNode{
|
||||||
|
override def name = "disk"
|
||||||
|
|
||||||
def close() {}
|
def close() {}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,13 @@ package li.cil.oc.server.components
|
|||||||
import li.cil.oc.api.{INetworkNode, INetworkMessage}
|
import li.cil.oc.api.{INetworkNode, INetworkMessage}
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
|
||||||
class GraphicsCard(val nbt: NBTTagCompound) extends INetworkNode {
|
class GraphicsCard(nbt: NBTTagCompound) extends ItemComponent(nbt) {
|
||||||
address = nbt.getInteger("address")
|
|
||||||
|
|
||||||
val supportedResolutions = List(List(40, 24), List(80, 24))
|
val supportedResolutions = List(List(40, 24), List(80, 24))
|
||||||
|
|
||||||
override def name = "gpu"
|
override def name = "gpu"
|
||||||
|
|
||||||
override def address_=(value: Int) = {
|
|
||||||
super.address_=(value)
|
|
||||||
nbt.setInteger("address", address)
|
|
||||||
}
|
|
||||||
|
|
||||||
override def receive(message: INetworkMessage) = {
|
override def receive(message: INetworkMessage) = {
|
||||||
// We don't need onConnect / onDisconnect / onAddressChange yet, so no need to call super.
|
super.receive(message)
|
||||||
// super.receive(message)
|
|
||||||
message.data match {
|
message.data match {
|
||||||
case Array(screen: Double, w: Double, h: Double) if message.name == "gpu.resolution=" =>
|
case Array(screen: Double, w: Double, h: Double) if message.name == "gpu.resolution=" =>
|
||||||
if (supportedResolutions.contains((w.toInt, h.toInt)))
|
if (supportedResolutions.contains((w.toInt, h.toInt)))
|
||||||
|
13
li/cil/oc/server/components/ItemComponent.scala
Normal file
13
li/cil/oc/server/components/ItemComponent.scala
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package li.cil.oc.server.components
|
||||||
|
|
||||||
|
import li.cil.oc.api.INetworkNode
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
|
||||||
|
abstract class ItemComponent(val nbt: NBTTagCompound) extends INetworkNode {
|
||||||
|
address = nbt.getInteger("address")
|
||||||
|
|
||||||
|
override def address_=(value: Int) = {
|
||||||
|
super.address_=(value)
|
||||||
|
nbt.setInteger("address", address)
|
||||||
|
}
|
||||||
|
}
|
46
li/cil/oc/server/components/RedstoneCard.scala
Normal file
46
li/cil/oc/server/components/RedstoneCard.scala
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package li.cil.oc.server.components
|
||||||
|
|
||||||
|
import li.cil.oc.api.INetworkMessage
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import net.minecraft.tileentity.TileEntity
|
||||||
|
import net.minecraftforge.common.ForgeDirection
|
||||||
|
|
||||||
|
class RedstoneCard(nbt: NBTTagCompound) extends ItemComponent(nbt) {
|
||||||
|
override def name = "redstone"
|
||||||
|
|
||||||
|
override def receive(message: INetworkMessage): Option[Array[Any]] = {
|
||||||
|
super.receive(message)
|
||||||
|
message.data match {
|
||||||
|
case Array(target: Double, side: Double) if message.name == "redstone.input" =>
|
||||||
|
input(target.toInt, side.toInt)
|
||||||
|
case Array(target: Double, side: Double) if message.name == "redstone.output" =>
|
||||||
|
output(target.toInt, side.toInt)
|
||||||
|
case Array(target: Double, side: Double, value: Double) if message.name == "redstone.output=" =>
|
||||||
|
output(target.toInt, side.toInt, value.toInt); None
|
||||||
|
case _ => None // Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def input(target: Int, side: Int) = if (side >= 0 && side < 6) network.node(target) match {
|
||||||
|
case Some(r: RedstoneEnabled) => Some(Array(r.input(ForgeDirection.getOrientation(side)).asInstanceOf[Any]))
|
||||||
|
case Some(t: TileEntity) =>
|
||||||
|
val face = ForgeDirection.getOrientation(side.toInt)
|
||||||
|
val power = t.worldObj.isBlockProvidingPowerTo(
|
||||||
|
t.xCoord + face.offsetX, t.yCoord + face.offsetY, t.zCoord + face.offsetZ, face.getOpposite.ordinal)
|
||||||
|
Some(Array(power.asInstanceOf[Any]))
|
||||||
|
case _ => None // Can't work with this node.
|
||||||
|
} else None
|
||||||
|
|
||||||
|
private def output(target: Int, side: Int) = if (side >= 0 && side < 6) network.node(target) match {
|
||||||
|
case Some(r: RedstoneEnabled) => Some(Array(r.output(ForgeDirection.getOrientation(side)).asInstanceOf[Any]))
|
||||||
|
case Some(t: TileEntity) =>
|
||||||
|
val power = t.worldObj.isBlockProvidingPowerTo(t.xCoord, t.yCoord, t.zCoord, side.toInt)
|
||||||
|
Some(Array(power.asInstanceOf[Any]))
|
||||||
|
case _ => None // Can't work with this node.
|
||||||
|
} else None
|
||||||
|
|
||||||
|
private def output(target: Int, side: Int, value: Int) = if (side >= 0 && side < 6) network.node(target) match {
|
||||||
|
case Some(r: RedstoneEnabled) => r.output(ForgeDirection.getOrientation(side)) = value
|
||||||
|
case _ => // Can't work with this node.
|
||||||
|
}
|
||||||
|
}
|
15
li/cil/oc/server/components/RedstoneEnabled.scala
Normal file
15
li/cil/oc/server/components/RedstoneEnabled.scala
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package li.cil.oc.server.components
|
||||||
|
|
||||||
|
import net.minecraftforge.common.ForgeDirection
|
||||||
|
|
||||||
|
trait RedstoneEnabled {
|
||||||
|
protected val _output = Array.fill(6)(0)
|
||||||
|
|
||||||
|
def input(side: ForgeDirection): Int
|
||||||
|
|
||||||
|
def output = new {
|
||||||
|
def apply(side: ForgeDirection) = _output(side.ordinal)
|
||||||
|
|
||||||
|
def update(side: ForgeDirection, value: Int) = _output(side.ordinal) = value
|
||||||
|
}
|
||||||
|
}
|
@ -43,7 +43,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
* resume the computers main thread, if at all, and whether to accept new
|
* resume the computers main thread, if at all, and whether to accept new
|
||||||
* signals or not.
|
* signals or not.
|
||||||
*/
|
*/
|
||||||
private var state = State.Stopped
|
private var state = Computer.State.Stopped
|
||||||
|
|
||||||
/** The internal Lua state. Only set while the computer is running. */
|
/** The internal Lua state. Only set while the computer is running. */
|
||||||
private[computer] var lua: LuaState = null
|
private[computer] var lua: LuaState = null
|
||||||
@ -62,7 +62,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
* means to communicate actively with the computer (passively only message
|
* means to communicate actively with the computer (passively only message
|
||||||
* handlers can interact with the computer by returning some result).
|
* handlers can interact with the computer by returning some result).
|
||||||
*/
|
*/
|
||||||
private val signals = new LinkedBlockingQueue[Signal](100)
|
private val signals = new LinkedBlockingQueue[Computer.Signal](100)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
@ -121,23 +121,23 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
}.toArray
|
}.toArray
|
||||||
stateMonitor.synchronized(state match {
|
stateMonitor.synchronized(state match {
|
||||||
// We don't push new signals when stopped or shutting down.
|
// We don't push new signals when stopped or shutting down.
|
||||||
case State.Stopped | State.Stopping => false
|
case Computer.State.Stopped | Computer.State.Stopping => false
|
||||||
// Currently sleeping. Cancel that and start immediately.
|
// Currently sleeping. Cancel that and start immediately.
|
||||||
case State.Sleeping =>
|
case Computer.State.Sleeping =>
|
||||||
val v = values // Map first, may error.
|
val v = values // Map first, may error.
|
||||||
future.get.cancel(true)
|
future.get.cancel(true)
|
||||||
state = State.Suspended
|
state = Computer.State.Suspended
|
||||||
signals.offer(new Signal(name, v))
|
signals.offer(new Computer.Signal(name, v))
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
true
|
true
|
||||||
// Basically running, but had nothing to do so we stopped. Resume.
|
// Basically running, but had nothing to do so we stopped. Resume.
|
||||||
case State.Suspended if !future.isDefined =>
|
case Computer.State.Suspended if !future.isDefined =>
|
||||||
signals.offer(new Signal(name, values))
|
signals.offer(new Computer.Signal(name, values))
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
true
|
true
|
||||||
// Running or in synchronized call, just push the signal.
|
// Running or in synchronized call, just push the signal.
|
||||||
case _ =>
|
case _ =>
|
||||||
signals.offer(new Signal(name, values))
|
signals.offer(new Computer.Signal(name, values))
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -147,8 +147,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def start() = stateMonitor.synchronized(
|
override def start() = stateMonitor.synchronized(
|
||||||
state == State.Stopped && init() && {
|
state == Computer.State.Stopped && init() && {
|
||||||
state = State.Suspended
|
state = Computer.State.Suspended
|
||||||
|
|
||||||
// Mark state change in owner, to send it to clients.
|
// Mark state change in owner, to send it to clients.
|
||||||
owner.markAsChanged()
|
owner.markAsChanged()
|
||||||
@ -165,8 +165,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
})
|
})
|
||||||
|
|
||||||
override def stop() = saveMonitor.synchronized(stateMonitor.synchronized {
|
override def stop() = saveMonitor.synchronized(stateMonitor.synchronized {
|
||||||
if (state != State.Stopped) {
|
if (state != Computer.State.Stopped) {
|
||||||
if (state != State.Running) {
|
if (state != Computer.State.Running) {
|
||||||
// If the computer is not currently running we can simply close it,
|
// If the computer is not currently running we can simply close it,
|
||||||
// and cancel any pending future - which may already be running and
|
// and cancel any pending future - which may already be running and
|
||||||
// waiting for the stateMonitor, so we do a hard abort.
|
// waiting for the stateMonitor, so we do a hard abort.
|
||||||
@ -178,26 +178,26 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// truly stopped, before switching back to stopped to allow starting
|
// truly stopped, before switching back to stopped to allow starting
|
||||||
// the computer again. The executor will check for this state and
|
// the computer again. The executor will check for this state and
|
||||||
// call close.
|
// call close.
|
||||||
state = State.Stopping
|
state = Computer.State.Stopping
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else false
|
else false
|
||||||
})
|
})
|
||||||
|
|
||||||
override def isRunning = stateMonitor.synchronized(state != State.Stopped)
|
override def isRunning = stateMonitor.synchronized(state != Computer.State.Stopped)
|
||||||
|
|
||||||
override def update() {
|
override def update() {
|
||||||
stateMonitor.synchronized(state match {
|
stateMonitor.synchronized(state match {
|
||||||
case State.Stopped | State.Stopping => return
|
case Computer.State.Stopped | Computer.State.Stopping => return
|
||||||
case State.SynchronizedCall => {
|
case Computer.State.SynchronizedCall => {
|
||||||
assert(lua.getTop == 2)
|
assert(lua.getTop == 2)
|
||||||
assert(lua.isThread(1))
|
assert(lua.isThread(1))
|
||||||
assert(lua.isFunction(2))
|
assert(lua.isFunction(2))
|
||||||
try {
|
try {
|
||||||
lua.call(0, 1)
|
lua.call(0, 1)
|
||||||
lua.checkType(2, LuaType.TABLE)
|
lua.checkType(2, LuaType.TABLE)
|
||||||
state = State.SynchronizedReturn
|
state = Computer.State.SynchronizedReturn
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
} catch {
|
} catch {
|
||||||
@ -212,26 +212,26 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case State.Paused => {
|
case Computer.State.Paused => {
|
||||||
state = State.Suspended
|
state = Computer.State.Suspended
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
}
|
}
|
||||||
case State.SynchronizedReturnPaused => {
|
case Computer.State.SynchronizedReturnPaused => {
|
||||||
state = State.SynchronizedReturn
|
state = Computer.State.SynchronizedReturn
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
}
|
}
|
||||||
case _ => /* Nothing special to do. */
|
case _ => /* Nothing special to do. */
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Update world time for computer threads.
|
||||||
|
worldTime = owner.world.getWorldInfo.getWorldTotalTime
|
||||||
|
|
||||||
// Remember when we started the computer for os.clock(). We do this in the
|
// Remember when we started the computer for os.clock(). We do this in the
|
||||||
// update because only then can we be sure the world is available.
|
// update because only then can we be sure the world is available.
|
||||||
if (timeStarted == 0)
|
if (timeStarted == 0)
|
||||||
timeStarted = owner.world.getWorldInfo.getWorldTotalTime
|
timeStarted = worldTime
|
||||||
|
|
||||||
// Update world time for computer threads.
|
|
||||||
worldTime = owner.world.getWorldInfo.getWorldTotalTime
|
|
||||||
|
|
||||||
// Update last time run to let our executor thread know it doesn't have to
|
// Update last time run to let our executor thread know it doesn't have to
|
||||||
// pause.
|
// pause.
|
||||||
@ -244,13 +244,13 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
saveMonitor.synchronized(this.synchronized {
|
saveMonitor.synchronized(this.synchronized {
|
||||||
// Clear out what we currently have, if anything.
|
// Clear out what we currently have, if anything.
|
||||||
stateMonitor.synchronized {
|
stateMonitor.synchronized {
|
||||||
assert(state != State.Running) // Lock on 'this' should guarantee this.
|
assert(state != Computer.State.Running) // Lock on 'this' should guarantee this.
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
state = State(nbt.getInteger("state"))
|
state = Computer.State(nbt.getInteger("state"))
|
||||||
|
|
||||||
if (state != State.Stopped && init()) {
|
if (state != Computer.State.Stopped && init()) {
|
||||||
// Unlimit memory use while unpersisting.
|
// Unlimit memory use while unpersisting.
|
||||||
val memory = lua.getTotalMemory
|
val memory = lua.getTotalMemory
|
||||||
lua.setTotalMemory(Integer.MAX_VALUE)
|
lua.setTotalMemory(Integer.MAX_VALUE)
|
||||||
@ -264,10 +264,10 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// the save was corrupt (maybe someone modified the Lua files).
|
// the save was corrupt (maybe someone modified the Lua files).
|
||||||
throw new IllegalStateException("Could not restore kernel.")
|
throw new IllegalStateException("Could not restore kernel.")
|
||||||
}
|
}
|
||||||
if (state == State.SynchronizedCall || state == State.SynchronizedReturn) {
|
if (state == Computer.State.SynchronizedCall || state == Computer.State.SynchronizedReturn) {
|
||||||
if (!unpersist(nbt.getByteArray("stack")) ||
|
if (!unpersist(nbt.getByteArray("stack")) ||
|
||||||
(state == State.SynchronizedCall && !lua.isFunction(2)) ||
|
(state == Computer.State.SynchronizedCall && !lua.isFunction(2)) ||
|
||||||
(state == State.SynchronizedReturn && !lua.isTable(2))) {
|
(state == Computer.State.SynchronizedReturn && !lua.isTable(2))) {
|
||||||
// Same as with the above, should not really happen normally, but
|
// Same as with the above, should not really happen normally, but
|
||||||
// could for the same reasons.
|
// could for the same reasons.
|
||||||
throw new IllegalStateException("Could not restore stack.")
|
throw new IllegalStateException("Could not restore stack.")
|
||||||
@ -282,7 +282,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
map(signal => {
|
map(signal => {
|
||||||
val argsTag = signal.getCompoundTag("args")
|
val argsTag = signal.getCompoundTag("args")
|
||||||
val argsLength = argsTag.getInteger("length")
|
val argsLength = argsTag.getInteger("length")
|
||||||
new Signal(signal.getString("name"),
|
new Computer.Signal(signal.getString("name"),
|
||||||
(0 until argsLength).map("arg" + _).map(argsTag.getTag).map {
|
(0 until argsLength).map("arg" + _).map(argsTag.getTag).map {
|
||||||
case tag: NBTTagByte if tag.data == -1 => Unit
|
case tag: NBTTagByte if tag.data == -1 => Unit
|
||||||
case tag: NBTTagByte => tag.data == 1
|
case tag: NBTTagByte => tag.data == 1
|
||||||
@ -300,7 +300,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// Start running our worker thread.
|
// Start running our worker thread.
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
state match {
|
state match {
|
||||||
case State.Suspended | State.Sleeping | State.SynchronizedReturn =>
|
case Computer.State.Suspended | Computer.State.Sleeping | Computer.State.SynchronizedReturn =>
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
case _ => // Wasn't running before.
|
case _ => // Wasn't running before.
|
||||||
}
|
}
|
||||||
@ -320,12 +320,12 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
override def save(nbt: NBTTagCompound): Unit =
|
override def save(nbt: NBTTagCompound): Unit =
|
||||||
saveMonitor.synchronized(this.synchronized {
|
saveMonitor.synchronized(this.synchronized {
|
||||||
stateMonitor.synchronized {
|
stateMonitor.synchronized {
|
||||||
assert(state != State.Running) // Lock on 'this' should guarantee this.
|
assert(state != Computer.State.Running) // Lock on 'this' should guarantee this.
|
||||||
assert(state != State.Stopping) // Only set while executor is running.
|
assert(state != Computer.State.Stopping) // Only set while executor is running.
|
||||||
}
|
}
|
||||||
|
|
||||||
nbt.setInteger("state", state.id)
|
nbt.setInteger("state", state.id)
|
||||||
if (state == State.Stopped) {
|
if (state == Computer.State.Stopped) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,8 +336,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// Try persisting Lua, because that's what all of the rest depends on.
|
// Try persisting Lua, because that's what all of the rest depends on.
|
||||||
// While in a driver call we have one object on the global stack: either
|
// While in a driver call we have one object on the global stack: either
|
||||||
// the function to call the driver with, or the result of the call.
|
// the function to call the driver with, or the result of the call.
|
||||||
if (state == State.SynchronizedCall || state == State.SynchronizedReturn) {
|
if (state == Computer.State.SynchronizedCall || state == Computer.State.SynchronizedReturn) {
|
||||||
assert(if (state == State.SynchronizedCall) lua.isFunction(2) else lua.isTable(2))
|
assert(if (state == Computer.State.SynchronizedCall) lua.isFunction(2) else lua.isTable(2))
|
||||||
nbt.setByteArray("stack", persist(2))
|
nbt.setByteArray("stack", persist(2))
|
||||||
}
|
}
|
||||||
// Save the kernel state (which is always at stack index one).
|
// Save the kernel state (which is always at stack index one).
|
||||||
@ -366,7 +366,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
catch {
|
catch {
|
||||||
case t: Throwable => {
|
case t: Throwable => {
|
||||||
t.printStackTrace()
|
t.printStackTrace()
|
||||||
nbt.setInteger("state", State.Stopped.id)
|
nbt.setInteger("state", Computer.State.Stopped.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -456,6 +456,13 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
}))
|
}))
|
||||||
lua.setField(-2, "romSize")
|
lua.setField(-2, "romSize")
|
||||||
|
|
||||||
|
// Allow the computer to figure out its own id in the component network.
|
||||||
|
lua.pushJavaFunction(ScalaFunction(lua => {
|
||||||
|
lua.pushInteger(owner.address)
|
||||||
|
1
|
||||||
|
}))
|
||||||
|
lua.setField(-2, "address")
|
||||||
|
|
||||||
// Pop the os table.
|
// Pop the os table.
|
||||||
lua.pop(1)
|
lua.pop(1)
|
||||||
|
|
||||||
@ -596,8 +603,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def close(): Unit = stateMonitor.synchronized(
|
private def close(): Unit = stateMonitor.synchronized(
|
||||||
if (state != State.Stopped) {
|
if (state != Computer.State.Stopped) {
|
||||||
state = State.Stopped
|
state = Computer.State.Stopped
|
||||||
lua.setTotalMemory(Integer.MAX_VALUE)
|
lua.setTotalMemory(Integer.MAX_VALUE)
|
||||||
lua.close()
|
lua.close()
|
||||||
lua = null
|
lua = null
|
||||||
@ -616,21 +623,21 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
if (System.currentTimeMillis - lastUpdate > 200)
|
if (System.currentTimeMillis - lastUpdate > 200)
|
||||||
stateMonitor.synchronized {
|
stateMonitor.synchronized {
|
||||||
state =
|
state =
|
||||||
if (state == State.SynchronizedReturn) State.SynchronizedReturnPaused
|
if (state == Computer.State.SynchronizedReturn) Computer.State.SynchronizedReturnPaused
|
||||||
else State.Paused
|
else Computer.State.Paused
|
||||||
future = None
|
future = None
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val callReturn = stateMonitor.synchronized {
|
val callReturn = stateMonitor.synchronized {
|
||||||
if (state == State.Stopped) return
|
if (state == Computer.State.Stopped) return
|
||||||
val oldState = state
|
val oldState = state
|
||||||
state = State.Running
|
state = Computer.State.Running
|
||||||
future = None
|
future = None
|
||||||
oldState
|
oldState
|
||||||
} match {
|
} match {
|
||||||
case State.SynchronizedReturn | State.SynchronizedReturnPaused => true
|
case Computer.State.SynchronizedReturn | Computer.State.SynchronizedReturnPaused => true
|
||||||
case State.Stopped | State.Paused | State.Suspended | State.Sleeping => false
|
case Computer.State.Stopped | Computer.State.Paused | Computer.State.Suspended | Computer.State.Sleeping => false
|
||||||
case s =>
|
case s =>
|
||||||
OpenComputers.log.warning("Running computer from invalid state " + s.toString + "!")
|
OpenComputers.log.warning("Running computer from invalid state " + s.toString + "!")
|
||||||
stateMonitor.synchronized {
|
stateMonitor.synchronized {
|
||||||
@ -678,7 +685,7 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
if (lua.status(1) == LuaState.YIELD) {
|
if (lua.status(1) == LuaState.YIELD) {
|
||||||
// Lua state yielded normally, see what we have.
|
// Lua state yielded normally, see what we have.
|
||||||
stateMonitor.synchronized {
|
stateMonitor.synchronized {
|
||||||
if (state == State.Stopping) {
|
if (state == Computer.State.Stopping) {
|
||||||
// Someone called stop() in the meantime.
|
// Someone called stop() in the meantime.
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
@ -688,25 +695,25 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
val sleep = (lua.toNumber(2) * 1000).toLong
|
val sleep = (lua.toNumber(2) * 1000).toLong
|
||||||
lua.pop(results)
|
lua.pop(results)
|
||||||
if (signals.isEmpty) {
|
if (signals.isEmpty) {
|
||||||
state = State.Sleeping
|
state = Computer.State.Sleeping
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
future = Some(Computer.Executor.pool.schedule(this, sleep, TimeUnit.MILLISECONDS))
|
future = Some(Computer.Executor.pool.schedule(this, sleep, TimeUnit.MILLISECONDS))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state = State.Suspended
|
state = Computer.State.Suspended
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
future = Some(Computer.Executor.pool.submit(this))
|
future = Some(Computer.Executor.pool.submit(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (results == 1 && lua.isFunction(2)) {
|
else if (results == 1 && lua.isFunction(2)) {
|
||||||
// If we get one function it's a wrapper for a synchronized call.
|
// If we get one function it's a wrapper for a synchronized call.
|
||||||
state = State.SynchronizedCall
|
state = Computer.State.SynchronizedCall
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Something else, just pop the results and try again.
|
// Something else, just pop the results and try again.
|
||||||
lua.pop(results)
|
lua.pop(results)
|
||||||
state = State.Suspended
|
state = Computer.State.Suspended
|
||||||
assert(!future.isDefined)
|
assert(!future.isDefined)
|
||||||
if (!signals.isEmpty) future = Some(Computer.Executor.pool.submit(this))
|
if (!signals.isEmpty) future = Some(Computer.Executor.pool.submit(this))
|
||||||
}
|
}
|
||||||
@ -736,6 +743,19 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// If we come here there was an error or we stopped, kill off the state.
|
// If we come here there was an error or we stopped, kill off the state.
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Computer {
|
||||||
|
@ForgeSubscribe
|
||||||
|
def onChunkUnload(e: ChunkEvent.Unload) =
|
||||||
|
onUnload(e.world, e.getChunk.chunkTileEntityMap.values.map(_.asInstanceOf[TileEntity]))
|
||||||
|
|
||||||
|
private def onUnload(w: World, tileEntities: Iterable[TileEntity]) = if (!w.isRemote) {
|
||||||
|
tileEntities.
|
||||||
|
filter(_.isInstanceOf[TileEntityComputer]).
|
||||||
|
map(_.asInstanceOf[TileEntityComputer]).
|
||||||
|
foreach(_.turnOff())
|
||||||
|
}
|
||||||
|
|
||||||
/** Signals are messages sent to the Lua state from Java asynchronously. */
|
/** Signals are messages sent to the Lua state from Java asynchronously. */
|
||||||
private class Signal(val name: String, val args: Array[Any])
|
private class Signal(val name: String, val args: Array[Any])
|
||||||
@ -770,20 +790,6 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
val SynchronizedReturnPaused = Value("SynchronizedReturnPaused")
|
val SynchronizedReturnPaused = Value("SynchronizedReturnPaused")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
object Computer {
|
|
||||||
@ForgeSubscribe
|
|
||||||
def onChunkUnload(e: ChunkEvent.Unload) =
|
|
||||||
onUnload(e.world, e.getChunk.chunkTileEntityMap.values.map(_.asInstanceOf[TileEntity]))
|
|
||||||
|
|
||||||
private def onUnload(w: World, tileEntities: Iterable[TileEntity]) = if (!w.isRemote) {
|
|
||||||
tileEntities.
|
|
||||||
filter(_.isInstanceOf[TileEntityComputer]).
|
|
||||||
map(_.asInstanceOf[TileEntityComputer]).
|
|
||||||
foreach(_.turnOff())
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Singleton for requesting executors that run our Lua states. */
|
/** Singleton for requesting executors that run our Lua states. */
|
||||||
private object Executor {
|
private object Executor {
|
||||||
val pool = Executors.newScheduledThreadPool(Config.threads,
|
val pool = Executors.newScheduledThreadPool(Config.threads,
|
||||||
|
17
li/cil/oc/server/drivers/RedstoneDriver.scala
Normal file
17
li/cil/oc/server/drivers/RedstoneDriver.scala
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package li.cil.oc.server.drivers
|
||||||
|
|
||||||
|
import li.cil.oc.api.{ComponentType, IItemDriver}
|
||||||
|
import li.cil.oc.common.util.ItemComponentCache
|
||||||
|
import li.cil.oc.server.components.RedstoneCard
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import li.cil.oc.Items
|
||||||
|
|
||||||
|
object RedstoneDriver extends IItemDriver {
|
||||||
|
override def api = Option(getClass.getResourceAsStream("/assets/opencomputers/lua/redstone.lua"))
|
||||||
|
|
||||||
|
override def worksWith(item: ItemStack) = item.itemID == Items.rs.itemID
|
||||||
|
|
||||||
|
override def componentType(item: ItemStack) = ComponentType.PCI
|
||||||
|
|
||||||
|
override def node(item: ItemStack) = ItemComponentCache.get[RedstoneCard](item)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user