mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-14 09:46:53 -04:00
rudimentary keyboard input is working
This commit is contained in:
parent
48cf012d67
commit
29a79b5ed0
@ -2,25 +2,25 @@
|
||||
driver.gpu = {}
|
||||
|
||||
function driver.gpu.setResolution(gpu, screen, w, h)
|
||||
sendToNode(gpu, "gpu.resolution=", screen, w, h)
|
||||
sendToNode(gpu, "gpu.resolution=", screen, w, h)
|
||||
end
|
||||
|
||||
function driver.gpu.getResolution(gpu, screen)
|
||||
return sendToNode(gpu, "gpu.resolution", screen)
|
||||
return sendToNode(gpu, "gpu.resolution", screen)
|
||||
end
|
||||
|
||||
function driver.gpu.getResolutions(gpu, screen)
|
||||
return sendToNode(gpu, "gpu.resolutions", screen)
|
||||
return sendToNode(gpu, "gpu.resolutions", screen)
|
||||
end
|
||||
|
||||
function driver.gpu.set(gpu, screen, col, row, value)
|
||||
sendToNode(gpu, "gpu.set", screen, col, row, value)
|
||||
sendToNode(gpu, "gpu.set", screen, col, row, value)
|
||||
end
|
||||
|
||||
function driver.gpu.fill(gpu, screen, col, row, w, h, value)
|
||||
sendToNode(gpu, "gpu.fill", screen, col, row, w, h, value:sub(1, 1))
|
||||
sendToNode(gpu, "gpu.fill", screen, col, row, w, h, value:sub(1, 1))
|
||||
end
|
||||
|
||||
function driver.gpu.copy(gpu, screen, col, row, w, h, tx, ty)
|
||||
sendToNode(gpu, "gpu.copy", screen, col, row, w, h, tx, ty)
|
||||
sendToNode(gpu, "gpu.copy", screen, col, row, w, h, tx, ty)
|
||||
end
|
@ -86,12 +86,15 @@ end
|
||||
|
||||
-- Main OS loop, keeps everything else running.
|
||||
while true do
|
||||
local signal, id = os.signal(nil, 2)
|
||||
local signal, param = os.signal(nil, 2)
|
||||
if signal == "component_added" then
|
||||
onInstall(id)
|
||||
onInstall(param)
|
||||
elseif signal == "component_removed" then
|
||||
onUninstall(id)
|
||||
onUninstall(param)
|
||||
elseif signal == "key_down" then
|
||||
write(param)
|
||||
else
|
||||
write("Clock: ")
|
||||
print(os.clock())
|
||||
end
|
||||
write("Clock: ")
|
||||
print(os.clock())
|
||||
end
|
137
assets/opencomputers/lua/keyboard.lua
Normal file
137
assets/opencomputers/lua/keyboard.lua
Normal file
@ -0,0 +1,137 @@
|
||||
--[[ API for keyboards. ]]
|
||||
driver.keyboard = {}
|
||||
|
||||
driver.keyboard.keys = {
|
||||
["1"] = 0x02,
|
||||
["2"] = 0x03,
|
||||
["3"] = 0x04,
|
||||
["4"] = 0x05,
|
||||
["5"] = 0x06,
|
||||
["6"] = 0x07,
|
||||
["7"] = 0x08,
|
||||
["8"] = 0x09,
|
||||
["9"] = 0x0A,
|
||||
["0"] = 0x0B,
|
||||
a = 0x1E,
|
||||
b = 0x30,
|
||||
c = 0x2E,
|
||||
d = 0x20,
|
||||
e = 0x12,
|
||||
f = 0x21,
|
||||
g = 0x22,
|
||||
h = 0x23,
|
||||
i = 0x17,
|
||||
j = 0x24,
|
||||
k = 0x25,
|
||||
l = 0x26,
|
||||
m = 0x32,
|
||||
n = 0x31,
|
||||
o = 0x18,
|
||||
p = 0x19,
|
||||
q = 0x10,
|
||||
r = 0x13,
|
||||
s = 0x1F,
|
||||
t = 0x14,
|
||||
u = 0x16,
|
||||
v = 0x2F,
|
||||
w = 0x11,
|
||||
x = 0x2D,
|
||||
y = 0x15,
|
||||
z = 0x2C,
|
||||
|
||||
apostrophe = 0x28,
|
||||
at = 0x91,
|
||||
back = 0x0E, -- backspace
|
||||
backslash = 0x2B,
|
||||
colon = 0x92,
|
||||
comma = 0x33,
|
||||
enter = 0x1C,
|
||||
equals = 0x0D,
|
||||
grave = 0x29, -- accent grave
|
||||
lbracket = 0x1A,
|
||||
lcontrol = 0x1D,
|
||||
lmenu = 0x38, -- left Alt
|
||||
lshift = 0x2A,
|
||||
minus = 0x0C,
|
||||
numlock = 0x45,
|
||||
pause = 0xC5,
|
||||
period = 0x34,
|
||||
rbracket = 0x1B,
|
||||
rcontrol = 0x9D,
|
||||
rmenu = 0xB8, -- right Alt
|
||||
rshift = 0x36,
|
||||
scroll = 0x46, -- Scroll Lock
|
||||
semicolon = 0x27,
|
||||
slash = 0x35, -- / on main keyboard
|
||||
space = 0x39,
|
||||
stop = 0x95,
|
||||
tab = 0x0F,
|
||||
underline = 0x93,
|
||||
|
||||
-- Keypad (and numpad with numlock off)
|
||||
up = 0xC8,
|
||||
down = 0xD0,
|
||||
left = 0xCB,
|
||||
right = 0xCD,
|
||||
home = 0xC7,
|
||||
["end"] = 0xCF,
|
||||
pageUp = 0xC9,
|
||||
pageDown = 0xD1,
|
||||
insert = 0xD2,
|
||||
delete = 0xD3,
|
||||
|
||||
-- Function keys
|
||||
f1 = 0x3B,
|
||||
f2 = 0x3C,
|
||||
f3 = 0x3D,
|
||||
f4 = 0x3E,
|
||||
f5 = 0x3F,
|
||||
f6 = 0x40,
|
||||
f7 = 0x41,
|
||||
f8 = 0x42,
|
||||
f9 = 0x43,
|
||||
f10 = 0x44,
|
||||
f11 = 0x57,
|
||||
f12 = 0x58,
|
||||
f13 = 0x64,
|
||||
f14 = 0x65,
|
||||
f15 = 0x66,
|
||||
f16 = 0x67,
|
||||
f17 = 0x68,
|
||||
f18 = 0x69,
|
||||
f19 = 0x71,
|
||||
|
||||
-- Japanese keyboards
|
||||
kana = 0x70,
|
||||
kanji = 0x94,
|
||||
convert = 0x79,
|
||||
noconvert = 0x7B,
|
||||
yen = 0x7D,
|
||||
circumflex = 0x90,
|
||||
ax = 0x96,
|
||||
|
||||
-- Numpad
|
||||
numpad0 = 0x52,
|
||||
numpad1 = 0x4F,
|
||||
numpad2 = 0x50,
|
||||
numpad3 = 0x51,
|
||||
numpad4 = 0x4B,
|
||||
numpad5 = 0x4C,
|
||||
numpad6 = 0x4D,
|
||||
numpad7 = 0x47,
|
||||
numpad8 = 0x48,
|
||||
numpad9 = 0x49,
|
||||
numpadmul = 0x37,
|
||||
numpaddiv = 0xB5,
|
||||
numpadsub = 0x4A,
|
||||
numpadadd = 0x4E,
|
||||
numpaddecimal = 0x53,
|
||||
numpadcomma = 0xB3,
|
||||
numpadenter = 0x9C,
|
||||
numpadequals = 0x8D,
|
||||
}
|
||||
|
||||
-- Create inverse mapping for name lookup.
|
||||
for k, v in pairs(driver.keyboard.keys) do
|
||||
driver.keyboard.keys[v] = k
|
||||
end
|
@ -1,15 +1,13 @@
|
||||
package li.cil.oc
|
||||
|
||||
import li.cil.oc.common.block.BlockComputer
|
||||
import li.cil.oc.common.block.BlockMulti
|
||||
import li.cil.oc.common.block.BlockScreen
|
||||
import li.cil.oc.common.block.BlockSpecialMulti
|
||||
import li.cil.oc.common.block._
|
||||
|
||||
object Blocks {
|
||||
var blockSimple: BlockMulti = null
|
||||
var blockSpecial: BlockMulti = null
|
||||
var computer: BlockComputer = null
|
||||
var screen: BlockScreen = null
|
||||
var keyboard: BlockKeyboard = null
|
||||
|
||||
def init() {
|
||||
// IMPORTANT: the multi block must come first, since the sub blocks will
|
||||
@ -20,5 +18,6 @@ object Blocks {
|
||||
|
||||
computer = new BlockComputer(blockSimple)
|
||||
screen = new BlockScreen(blockSimple)
|
||||
keyboard = new BlockKeyboard(blockSpecial)
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package li.cil.oc.api
|
||||
|
||||
import _root_.scala.beans.BeanProperty
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
@ -10,6 +9,9 @@ import net.minecraft.world.World
|
||||
* placed in the world, but cannot be modified to or don't want to have their
|
||||
* `TileEntities` implement `INetworkNode`.
|
||||
* <p/>
|
||||
* A block driver is used by proxy blocks to check its neighbors and whether
|
||||
* those neighbors should be treated as components or not.
|
||||
* <p/>
|
||||
* Note that it is possible to write one driver that supports as many different
|
||||
* blocks as you wish. I'd recommend writing one per device (type), though, to
|
||||
* keep things modular.
|
||||
@ -34,15 +36,17 @@ trait IBlockDriver extends IDriver {
|
||||
/**
|
||||
* Get a reference to the network node wrapping the specified block.
|
||||
* <p/>
|
||||
* This is used to provide context to the driver's methods, for example when
|
||||
* an API method is called this will always be passed as the first parameter.
|
||||
* This is used to connect the component to the component network when it is
|
||||
* detected next to a proxy. Components that are not part of the component
|
||||
* network probably don't make much sense (can't think of any uses at this
|
||||
* time), but you may still opt to not implement this.
|
||||
*
|
||||
* @param world the world in which the block to get the component for lives.
|
||||
* @param x the X coordinate of the block to get the component for.
|
||||
* @param y the Y coordinate of the block to get the component for.
|
||||
* @param z the Z coordinate of the block to get the component for.
|
||||
* @return the block component at that location, controlled by this driver.
|
||||
* @param world the world in which the block to get the node for lives.
|
||||
* @param x the X coordinate of the block to get the node for.
|
||||
* @param y the Y coordinate of the block to get the node for.
|
||||
* @param z the Z coordinate of the block to get the node for.
|
||||
* @return the network node for the block at that location.
|
||||
*/
|
||||
@BeanProperty
|
||||
def node(world: World, x: Int, y: Int, z: Int): INetworkNode
|
||||
def node(world: World, x: Int, y: Int, z: Int): INetworkNode =
|
||||
world.getBlockTileEntity(x, y, z).asInstanceOf[INetworkNode]
|
||||
}
|
@ -10,36 +10,36 @@ import java.io.InputStream
|
||||
* Lua state when the driver is installed, and provide general information used
|
||||
* by the computer.
|
||||
* <p/>
|
||||
* Note that drivers themselves are singletons. They can define a parameter of
|
||||
* type {@link IComputerContext} in their API functions which will hold the
|
||||
* context in which they are called - essentially a representation of the
|
||||
* computer they were called form. This context can be used to get a component
|
||||
* in the computer (e.g. passed as another parameter) and to send signals to the
|
||||
* computer.
|
||||
* <p/>
|
||||
* Do not implement this interface directly; use the {@link IItemDriver} and
|
||||
* {@link IBlockDriver} interfaces for the respective component types.
|
||||
* Do not implement this interface directly; use the `IItemDriver` and
|
||||
* `IBlockDriver` interfaces for the respective component types.
|
||||
*/
|
||||
trait IDriver {
|
||||
/**
|
||||
* Some initialization code that is run when the driver is installed.
|
||||
* <p/>
|
||||
* This is loaded
|
||||
* into the Lua state and run in the global, un-sandboxed environment. This
|
||||
* means your scripts can mess things up bad, so make sure you know what
|
||||
* you're doing and exposing.
|
||||
* These will usually be some functions that generate network messages of
|
||||
* the particular signature the node of the driver handles, but may contain
|
||||
* arbitrary other functions. However, whatever you do, keep in mind that
|
||||
* only certain parts of the global namespace will be made available to the
|
||||
* computer at runtime, so it's best to keep all you declare in the driver
|
||||
* table (global variable `driver`).
|
||||
* <p/>
|
||||
* This can be null to do nothing. Otherwise this is expected to be valid Lua
|
||||
* code (it is simply loaded via <code>load()</code> and then executed).
|
||||
* This is loaded into the Lua state and run in the global, un-sandboxed
|
||||
* environment. This means your scripts can mess things up bad, so make sure
|
||||
* you know what you're doing and exposing.
|
||||
* <p/>
|
||||
* This can be `None` to do nothing. Otherwise this is expected to be valid
|
||||
* Lua code (it is simply loaded via <code>load()</code> and then executed).
|
||||
* <p/>
|
||||
* The stream has to be recreated each time this is called. Normally you will
|
||||
* return something along the lines of
|
||||
* <code>Mod.class.getResourceAsStream("/assets/mod/lua/ocapi.lua")</code>
|
||||
* `Mod.class.getResourceAsStream("/assets/yourmod/lua/ocapi.lua")`
|
||||
* from this method. If you wish to hard-code the returned script, you can use
|
||||
* <code>new ByteArrayInputStream(yourScript.getBytes())</code> instead. Note
|
||||
* that the stream will automatically closed.
|
||||
* `new ByteArrayInputStream(yourScript.getBytes())` instead.
|
||||
* <p/>
|
||||
* IMPORTANT: Note that the stream will automatically closed.
|
||||
*
|
||||
* @return the Lua code to run after installing the API table.
|
||||
* @return the Lua code to run when a computer is started up.
|
||||
*/
|
||||
def api: Option[InputStream] = None
|
||||
}
|
@ -13,7 +13,7 @@ import net.minecraft.item.ItemStack
|
||||
* queried using the drivers' `worksWith` functions. The first driver that
|
||||
* replies positively and whose check against the slot type is successful, i.e.
|
||||
* for which the `componentType` matches the slot, will be used as the
|
||||
* component's driver and the component will be installed. If no driver is found
|
||||
* component's driver and the component will be added. If no driver is found
|
||||
* the item will be rejected and cannot be installed.
|
||||
* <p/>
|
||||
* Note that it is possible to write one driver that supports as many different
|
||||
@ -47,6 +47,11 @@ trait IItemDriver extends IDriver {
|
||||
|
||||
/**
|
||||
* Gets a reference to the network node interfacing the specified item.
|
||||
* <p/>
|
||||
* This is used to connect the component to the component network when it is
|
||||
* added to a computer, for example. Components that are not part of the
|
||||
* component network probably don't make much sense (can't think of any uses
|
||||
* at this time), but you may still opt to not implement this.
|
||||
*
|
||||
* @param item the item instance for which to get the node.
|
||||
* @return the network node for that item.
|
||||
|
@ -27,20 +27,22 @@ object PacketSender {
|
||||
pb.sendToServer()
|
||||
}
|
||||
|
||||
def sendKeyDown[T <: TileEntity with INetworkNode](t: T, c: Char) = {
|
||||
def sendKeyDown[T <: TileEntity with INetworkNode](t: T, char: Char, code: Int) = {
|
||||
val pb = new PacketBuilder(PacketType.KeyDown)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeChar(c)
|
||||
pb.writeChar(char)
|
||||
pb.writeInt(code)
|
||||
|
||||
pb.sendToServer()
|
||||
}
|
||||
|
||||
def sendKeyUp[T <: TileEntity with INetworkNode](t: T, c: Char) = {
|
||||
def sendKeyUp[T <: TileEntity with INetworkNode](t: T, char: Char, code: Int) = {
|
||||
val pb = new PacketBuilder(PacketType.KeyUp)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeChar(c)
|
||||
pb.writeChar(char)
|
||||
pb.writeInt(code)
|
||||
|
||||
pb.sendToServer()
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
package li.cil.oc.client.gui
|
||||
|
||||
import li.cil.oc.client.PacketSender
|
||||
import li.cil.oc.common.tileentity.TileEntityKeyboard
|
||||
import li.cil.oc.common.tileentity.TileEntityScreen
|
||||
import net.minecraft.client.renderer.GLAllocation
|
||||
import net.minecraft.client.renderer.Tessellator
|
||||
import net.minecraft.client.renderer.texture.TextureManager
|
||||
import net.minecraft.util.ResourceLocation
|
||||
import net.minecraftforge.common.ForgeDirection
|
||||
import org.lwjgl.input.Keyboard
|
||||
import org.lwjgl.opengl.GL11
|
||||
|
||||
@ -49,16 +47,15 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
|
||||
/** Must be called whenever the buffer of the underlying screen changes. */
|
||||
def updateText() = GuiScreen.compileText(scale, tileEntity.screen.lines)
|
||||
|
||||
override def handleKeyboardInput() = {
|
||||
// Find all keyboards next to this screen and type on them.
|
||||
for (k <- neighboringKeyboards) {
|
||||
override def keyTyped(char: Char, code: Int) = {
|
||||
super.keyTyped(char, code)
|
||||
if (code != Keyboard.KEY_ESCAPE && code != Keyboard.KEY_F11)
|
||||
if (Keyboard.getEventKeyState) {
|
||||
PacketSender.sendKeyDown(k, Keyboard.getEventCharacter)
|
||||
PacketSender.sendKeyDown(tileEntity, char, code)
|
||||
}
|
||||
else {
|
||||
PacketSender.sendKeyUp(k, Keyboard.getEventCharacter)
|
||||
PacketSender.sendKeyUp(tileEntity, char, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def initGui() = {
|
||||
@ -85,16 +82,6 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
|
||||
}
|
||||
|
||||
override def doesGuiPauseGame = false
|
||||
|
||||
private def neighboringKeyboards =
|
||||
ForgeDirection.VALID_DIRECTIONS.
|
||||
map(d => tileEntity.worldObj.getBlockTileEntity(
|
||||
tileEntity.xCoord + d.offsetX,
|
||||
tileEntity.yCoord + d.offsetY,
|
||||
tileEntity.zCoord + d.offsetZ)).
|
||||
filter(_ != null).
|
||||
filter(_.isInstanceOf[TileEntityKeyboard]).
|
||||
map(_.asInstanceOf[TileEntityKeyboard])
|
||||
}
|
||||
|
||||
/** We cache OpenGL stuff in a singleton to avoid having to re-allocate. */
|
||||
|
@ -30,6 +30,7 @@ class Proxy {
|
||||
NetworkRegistry.instance.registerGuiHandler(OpenComputers, GuiHandler)
|
||||
|
||||
OpenComputersAPI.addDriver(GraphicsCardDriver)
|
||||
OpenComputersAPI.addDriver(KeyboardDriver)
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(ForgeEventHandler)
|
||||
}
|
||||
|
@ -19,14 +19,16 @@ class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with ICo
|
||||
|
||||
private val hasChanged = new AtomicBoolean(true)
|
||||
|
||||
private var isRunning = computer.isRunning
|
||||
private var isRunning = false
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// NetworkNode
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def receive(message: INetworkMessage) = message.data match {
|
||||
case Array() if message.name == "network.connect" =>
|
||||
// The isRunning check is here to avoid network.connect messages being sent
|
||||
// while loading a chunk (thus leading to "false" component_added signals).
|
||||
case Array() if message.name == "network.connect" && isRunning =>
|
||||
computer.signal("component_added", message.source.address); None
|
||||
case Array() if message.name == "network.disconnect" =>
|
||||
computer.signal("component_removed", message.source.address); None
|
||||
|
@ -7,16 +7,16 @@ class TileEntityKeyboard extends TileEntityRotatable with INetworkNode {
|
||||
override def name = "keyboard"
|
||||
|
||||
override def receive(message: INetworkMessage) = message.data match {
|
||||
case Array(name: String, p: Player, c: Character) if name == "keyboard.keyDown" => {
|
||||
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyDown" => {
|
||||
// TODO check if player is close enough and only consume message if so
|
||||
network.sendToAll(this, "signal", "key_down", c)
|
||||
message.cancel()
|
||||
network.sendToAll(this, "signal", "key_down", char.toString, code)
|
||||
message.cancel() // One keyboard is enough.
|
||||
None
|
||||
}
|
||||
case Array(name: String, p: Player, c: Character) if name == "keyboard.keyUp" => {
|
||||
case Array(p: Player, char: Char, code: Int) if message.name == "keyboard.keyUp" => {
|
||||
// TODO check if player is close enough and only consume message if so
|
||||
network.sendToAll(this, "signal", "key_up", c)
|
||||
message.cancel()
|
||||
network.sendToAll(this, "signal", "key_up", char.toString, code)
|
||||
message.cancel() // One keyboard is enough.
|
||||
None
|
||||
}
|
||||
case _ => None
|
||||
|
@ -67,12 +67,12 @@ class PacketHandler extends CommonPacketHandler {
|
||||
def onKeyDown(p: PacketParser) =
|
||||
p.readTileEntity[INetworkNode]() match {
|
||||
case None => // Invalid packet.
|
||||
case Some(n) => n.network.sendToAll(n, "keyboard.keyDown", p.player, p.readChar())
|
||||
case Some(n) => n.network.sendToAll(n, "keyboard.keyDown", p.player, p.readChar(), p.readInt())
|
||||
}
|
||||
|
||||
def onKeyUp(p: PacketParser) =
|
||||
p.readTileEntity[INetworkNode]() match {
|
||||
case None => // Invalid packet.
|
||||
case Some(n) => n.network.sendToAll(n, "keyboard.keyUp", p.player, p.readChar())
|
||||
case Some(n) => n.network.sendToAll(n, "keyboard.keyUp", p.player, p.readChar(), p.readInt())
|
||||
}
|
||||
}
|
@ -660,12 +660,13 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
||||
// resuming the state again.
|
||||
val sleep = (lua.toNumber(2) * 1000).toLong
|
||||
lua.pop(results)
|
||||
state = State.Sleeping
|
||||
future = Some(Executor.pool.
|
||||
schedule(this, sleep, TimeUnit.MILLISECONDS))
|
||||
if (signals.isEmpty) {
|
||||
state = State.Sleeping
|
||||
future = Some(Executor.pool.schedule(this, sleep, TimeUnit.MILLISECONDS))
|
||||
} else future = Some(Executor.pool.submit(this))
|
||||
}
|
||||
else if (results == 1 && lua.isFunction(2)) {
|
||||
// If we get one function it's a wrapper for a driver call.
|
||||
// If we get one function it's a wrapper for a synchronized call.
|
||||
state = State.SynchronizedCall
|
||||
future = None
|
||||
}
|
||||
@ -673,7 +674,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
||||
// Something else, just pop the results and try again.
|
||||
lua.pop(results)
|
||||
state = State.Suspended
|
||||
future = Some(Executor.pool.submit(this))
|
||||
if (signals.isEmpty) future = None
|
||||
else future = Some(Executor.pool.submit(this))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.server.computer
|
||||
|
||||
import li.cil.oc.OpenComputers
|
||||
import li.cil.oc.api.INetwork
|
||||
import li.cil.oc.api.INetworkMessage
|
||||
import li.cil.oc.api.INetworkNode
|
||||
@ -35,10 +36,9 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
|
||||
nodes.values.flatten.foreach(_.data.network = this)
|
||||
|
||||
def connect(nodeA: INetworkNode, nodeB: INetworkNode) = try {
|
||||
def connect(nodeA: INetworkNode, nodeB: INetworkNode) = {
|
||||
if (locked) throw new IllegalStateException(
|
||||
"Cannot modify network while it is already updating its structure.")
|
||||
locked = true
|
||||
|
||||
val containsA = nodes.get(nodeA.address).exists(_.exists(_.data == nodeA))
|
||||
val containsB = nodes.get(nodeB.address).exists(_.exists(_.data == nodeB))
|
||||
@ -66,9 +66,6 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
else if (containsA) add(nodes(nodeA.address).find(_.data == nodeA).get, nodeB)
|
||||
else add(nodes(nodeB.address).find(_.data == nodeB).get, nodeA)
|
||||
}
|
||||
finally {
|
||||
locked = false
|
||||
}
|
||||
|
||||
def remove(node: INetworkNode) = nodes.get(node.address) match {
|
||||
case None => false
|
||||
@ -103,9 +100,14 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
private def send(message: Network.Message, nodes: Iterator[INetworkNode]) = {
|
||||
var result = None: Option[Array[Any]]
|
||||
while (!message.isCanceled && nodes.hasNext) {
|
||||
nodes.next().receive(message) match {
|
||||
case None => // Ignore.
|
||||
case r => result = r
|
||||
try {
|
||||
nodes.next().receive(message) match {
|
||||
case None => // Ignore.
|
||||
case r => result = r
|
||||
}
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
OpenComputers.log.warning("Error in message handler:\n" + e.getStackTraceString)
|
||||
}
|
||||
}
|
||||
result
|
||||
@ -124,7 +126,6 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
newNode
|
||||
}
|
||||
else {
|
||||
val otherNetwork = node.network.asInstanceOf[Network]
|
||||
// We have to merge. First create a copy of the old nodes to have the
|
||||
// list of nodes to which to send "network.connect" messages.
|
||||
val oldNodes = nodes.values.flatten.map(_.data).toArray
|
||||
@ -132,7 +133,12 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
// iteration to merge into this network, used to send "network.reconnect"
|
||||
// messages to old nodes in case we have to change a node's address to
|
||||
// ensure unique addresses in the merged network.
|
||||
val otherNetwork = node.network.asInstanceOf[Network]
|
||||
val otherNodes = otherNetwork.nodes.values.flatten.map(_.data)
|
||||
// Lock this network to avoid message handlers adding nodes, which could
|
||||
// lead to addresses getting taken that we will need for the nodes we are
|
||||
// about to merge into this network.
|
||||
locked = true
|
||||
// Pre-merge step: ensure addresses are unique.
|
||||
for (node <- otherNodes if nodes.contains(node.address)) {
|
||||
val oldAddress = node.address
|
||||
@ -148,6 +154,8 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
||||
node.data.network = this
|
||||
send(new Network.Message(node.data, "network.connect"), oldNodes.iterator)
|
||||
}
|
||||
// Done, unlock again.
|
||||
locked = false
|
||||
// Return the node object of the newly connected node for the next step.
|
||||
nodes(node.address).find(_.data == node).get
|
||||
}
|
||||
|
12
li/cil/oc/server/drivers/KeyboardDriver.scala
Normal file
12
li/cil/oc/server/drivers/KeyboardDriver.scala
Normal file
@ -0,0 +1,12 @@
|
||||
package li.cil.oc.server.drivers
|
||||
|
||||
import li.cil.oc.Blocks
|
||||
import li.cil.oc.api.IBlockDriver
|
||||
import net.minecraft.world.World
|
||||
|
||||
object KeyboardDriver extends IBlockDriver {
|
||||
override def api = Option(getClass.getResourceAsStream("/assets/opencomputers/lua/keyboard.lua"))
|
||||
|
||||
override def worksWith(world: World, x: Int, y: Int, z: Int) =
|
||||
world.getBlockId(x, y, z) == Blocks.keyboard.blockId
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user