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 = {}
|
driver.gpu = {}
|
||||||
|
|
||||||
function driver.gpu.setResolution(gpu, screen, w, h)
|
function driver.gpu.setResolution(gpu, screen, w, h)
|
||||||
sendToNode(gpu, "gpu.resolution=", screen, w, h)
|
sendToNode(gpu, "gpu.resolution=", screen, w, h)
|
||||||
end
|
end
|
||||||
|
|
||||||
function driver.gpu.getResolution(gpu, screen)
|
function driver.gpu.getResolution(gpu, screen)
|
||||||
return sendToNode(gpu, "gpu.resolution", screen)
|
return sendToNode(gpu, "gpu.resolution", screen)
|
||||||
end
|
end
|
||||||
|
|
||||||
function driver.gpu.getResolutions(gpu, screen)
|
function driver.gpu.getResolutions(gpu, screen)
|
||||||
return sendToNode(gpu, "gpu.resolutions", screen)
|
return sendToNode(gpu, "gpu.resolutions", screen)
|
||||||
end
|
end
|
||||||
|
|
||||||
function driver.gpu.set(gpu, screen, col, row, value)
|
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
|
end
|
||||||
|
|
||||||
function driver.gpu.fill(gpu, screen, col, row, w, h, value)
|
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
|
end
|
||||||
|
|
||||||
function driver.gpu.copy(gpu, screen, col, row, w, h, tx, ty)
|
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
|
end
|
@ -86,12 +86,15 @@ end
|
|||||||
|
|
||||||
-- Main OS loop, keeps everything else running.
|
-- Main OS loop, keeps everything else running.
|
||||||
while true do
|
while true do
|
||||||
local signal, id = os.signal(nil, 2)
|
local signal, param = os.signal(nil, 2)
|
||||||
if signal == "component_added" then
|
if signal == "component_added" then
|
||||||
onInstall(id)
|
onInstall(param)
|
||||||
elseif signal == "component_removed" then
|
elseif signal == "component_removed" then
|
||||||
onUninstall(id)
|
onUninstall(param)
|
||||||
|
elseif signal == "key_down" then
|
||||||
|
write(param)
|
||||||
|
else
|
||||||
|
write("Clock: ")
|
||||||
|
print(os.clock())
|
||||||
end
|
end
|
||||||
write("Clock: ")
|
|
||||||
print(os.clock())
|
|
||||||
end
|
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
|
package li.cil.oc
|
||||||
|
|
||||||
import li.cil.oc.common.block.BlockComputer
|
import li.cil.oc.common.block._
|
||||||
import li.cil.oc.common.block.BlockMulti
|
|
||||||
import li.cil.oc.common.block.BlockScreen
|
|
||||||
import li.cil.oc.common.block.BlockSpecialMulti
|
|
||||||
|
|
||||||
object Blocks {
|
object Blocks {
|
||||||
var blockSimple: BlockMulti = null
|
var blockSimple: BlockMulti = null
|
||||||
var blockSpecial: BlockMulti = null
|
var blockSpecial: BlockMulti = null
|
||||||
var computer: BlockComputer = null
|
var computer: BlockComputer = null
|
||||||
var screen: BlockScreen = null
|
var screen: BlockScreen = null
|
||||||
|
var keyboard: BlockKeyboard = null
|
||||||
|
|
||||||
def init() {
|
def init() {
|
||||||
// IMPORTANT: the multi block must come first, since the sub blocks will
|
// IMPORTANT: the multi block must come first, since the sub blocks will
|
||||||
@ -20,5 +18,6 @@ object Blocks {
|
|||||||
|
|
||||||
computer = new BlockComputer(blockSimple)
|
computer = new BlockComputer(blockSimple)
|
||||||
screen = new BlockScreen(blockSimple)
|
screen = new BlockScreen(blockSimple)
|
||||||
|
keyboard = new BlockKeyboard(blockSpecial)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package li.cil.oc.api
|
package li.cil.oc.api
|
||||||
|
|
||||||
import _root_.scala.beans.BeanProperty
|
|
||||||
import net.minecraft.world.World
|
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
|
* placed in the world, but cannot be modified to or don't want to have their
|
||||||
* `TileEntities` implement `INetworkNode`.
|
* `TileEntities` implement `INetworkNode`.
|
||||||
* <p/>
|
* <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
|
* 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
|
* blocks as you wish. I'd recommend writing one per device (type), though, to
|
||||||
* keep things modular.
|
* keep things modular.
|
||||||
@ -34,15 +36,17 @@ trait IBlockDriver extends IDriver {
|
|||||||
/**
|
/**
|
||||||
* Get a reference to the network node wrapping the specified block.
|
* Get a reference to the network node wrapping the specified block.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is used to provide context to the driver's methods, for example when
|
* This is used to connect the component to the component network when it is
|
||||||
* an API method is called this will always be passed as the first parameter.
|
* 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 world the world in which the block to get the node for lives.
|
||||||
* @param x the X coordinate of the block to get the component for.
|
* @param x the X coordinate of the block to get the node for.
|
||||||
* @param y the Y coordinate of the block to get the component 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 component for.
|
* @param z the Z coordinate of the block to get the node for.
|
||||||
* @return the block component at that location, controlled by this driver.
|
* @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
|
* Lua state when the driver is installed, and provide general information used
|
||||||
* by the computer.
|
* by the computer.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that drivers themselves are singletons. They can define a parameter of
|
* Do not implement this interface directly; use the `IItemDriver` and
|
||||||
* type {@link IComputerContext} in their API functions which will hold the
|
* `IBlockDriver` interfaces for the respective component types.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
trait IDriver {
|
trait IDriver {
|
||||||
/**
|
/**
|
||||||
* Some initialization code that is run when the driver is installed.
|
* Some initialization code that is run when the driver is installed.
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is loaded
|
* These will usually be some functions that generate network messages of
|
||||||
* into the Lua state and run in the global, un-sandboxed environment. This
|
* the particular signature the node of the driver handles, but may contain
|
||||||
* means your scripts can mess things up bad, so make sure you know what
|
* arbitrary other functions. However, whatever you do, keep in mind that
|
||||||
* you're doing and exposing.
|
* 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/>
|
* <p/>
|
||||||
* This can be null to do nothing. Otherwise this is expected to be valid Lua
|
* This is loaded into the Lua state and run in the global, un-sandboxed
|
||||||
* code (it is simply loaded via <code>load()</code> and then executed).
|
* 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/>
|
* <p/>
|
||||||
* The stream has to be recreated each time this is called. Normally you will
|
* The stream has to be recreated each time this is called. Normally you will
|
||||||
* return something along the lines of
|
* 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
|
* from this method. If you wish to hard-code the returned script, you can use
|
||||||
* <code>new ByteArrayInputStream(yourScript.getBytes())</code> instead. Note
|
* `new ByteArrayInputStream(yourScript.getBytes())` instead.
|
||||||
* that the stream will automatically closed.
|
* <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
|
def api: Option[InputStream] = None
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ import net.minecraft.item.ItemStack
|
|||||||
* queried using the drivers' `worksWith` functions. The first driver that
|
* queried using the drivers' `worksWith` functions. The first driver that
|
||||||
* replies positively and whose check against the slot type is successful, i.e.
|
* 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
|
* 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.
|
* the item will be rejected and cannot be installed.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that it is possible to write one driver that supports as many different
|
* 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.
|
* 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.
|
* @param item the item instance for which to get the node.
|
||||||
* @return the network node for that item.
|
* @return the network node for that item.
|
||||||
|
@ -27,20 +27,22 @@ object PacketSender {
|
|||||||
pb.sendToServer()
|
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)
|
val pb = new PacketBuilder(PacketType.KeyDown)
|
||||||
|
|
||||||
pb.writeTileEntity(t)
|
pb.writeTileEntity(t)
|
||||||
pb.writeChar(c)
|
pb.writeChar(char)
|
||||||
|
pb.writeInt(code)
|
||||||
|
|
||||||
pb.sendToServer()
|
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)
|
val pb = new PacketBuilder(PacketType.KeyUp)
|
||||||
|
|
||||||
pb.writeTileEntity(t)
|
pb.writeTileEntity(t)
|
||||||
pb.writeChar(c)
|
pb.writeChar(char)
|
||||||
|
pb.writeInt(code)
|
||||||
|
|
||||||
pb.sendToServer()
|
pb.sendToServer()
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package li.cil.oc.client.gui
|
package li.cil.oc.client.gui
|
||||||
|
|
||||||
import li.cil.oc.client.PacketSender
|
import li.cil.oc.client.PacketSender
|
||||||
import li.cil.oc.common.tileentity.TileEntityKeyboard
|
|
||||||
import li.cil.oc.common.tileentity.TileEntityScreen
|
import li.cil.oc.common.tileentity.TileEntityScreen
|
||||||
import net.minecraft.client.renderer.GLAllocation
|
import net.minecraft.client.renderer.GLAllocation
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.Tessellator
|
||||||
import net.minecraft.client.renderer.texture.TextureManager
|
import net.minecraft.client.renderer.texture.TextureManager
|
||||||
import net.minecraft.util.ResourceLocation
|
import net.minecraft.util.ResourceLocation
|
||||||
import net.minecraftforge.common.ForgeDirection
|
|
||||||
import org.lwjgl.input.Keyboard
|
import org.lwjgl.input.Keyboard
|
||||||
import org.lwjgl.opengl.GL11
|
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. */
|
/** Must be called whenever the buffer of the underlying screen changes. */
|
||||||
def updateText() = GuiScreen.compileText(scale, tileEntity.screen.lines)
|
def updateText() = GuiScreen.compileText(scale, tileEntity.screen.lines)
|
||||||
|
|
||||||
override def handleKeyboardInput() = {
|
override def keyTyped(char: Char, code: Int) = {
|
||||||
// Find all keyboards next to this screen and type on them.
|
super.keyTyped(char, code)
|
||||||
for (k <- neighboringKeyboards) {
|
if (code != Keyboard.KEY_ESCAPE && code != Keyboard.KEY_F11)
|
||||||
if (Keyboard.getEventKeyState) {
|
if (Keyboard.getEventKeyState) {
|
||||||
PacketSender.sendKeyDown(k, Keyboard.getEventCharacter)
|
PacketSender.sendKeyDown(tileEntity, char, code)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PacketSender.sendKeyUp(k, Keyboard.getEventCharacter)
|
PacketSender.sendKeyUp(tileEntity, char, code)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def initGui() = {
|
override def initGui() = {
|
||||||
@ -85,16 +82,6 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
|
|||||||
}
|
}
|
||||||
|
|
||||||
override def doesGuiPauseGame = false
|
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. */
|
/** We cache OpenGL stuff in a singleton to avoid having to re-allocate. */
|
||||||
|
@ -30,6 +30,7 @@ class Proxy {
|
|||||||
NetworkRegistry.instance.registerGuiHandler(OpenComputers, GuiHandler)
|
NetworkRegistry.instance.registerGuiHandler(OpenComputers, GuiHandler)
|
||||||
|
|
||||||
OpenComputersAPI.addDriver(GraphicsCardDriver)
|
OpenComputersAPI.addDriver(GraphicsCardDriver)
|
||||||
|
OpenComputersAPI.addDriver(KeyboardDriver)
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.register(ForgeEventHandler)
|
MinecraftForge.EVENT_BUS.register(ForgeEventHandler)
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,16 @@ class TileEntityComputer(isClient: Boolean) extends TileEntityRotatable with ICo
|
|||||||
|
|
||||||
private val hasChanged = new AtomicBoolean(true)
|
private val hasChanged = new AtomicBoolean(true)
|
||||||
|
|
||||||
private var isRunning = computer.isRunning
|
private var isRunning = false
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
// NetworkNode
|
// NetworkNode
|
||||||
// ----------------------------------------------------------------------- //
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
override def receive(message: INetworkMessage) = message.data match {
|
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
|
computer.signal("component_added", message.source.address); None
|
||||||
case Array() if message.name == "network.disconnect" =>
|
case Array() if message.name == "network.disconnect" =>
|
||||||
computer.signal("component_removed", message.source.address); None
|
computer.signal("component_removed", message.source.address); None
|
||||||
|
@ -7,16 +7,16 @@ class TileEntityKeyboard extends TileEntityRotatable with INetworkNode {
|
|||||||
override def name = "keyboard"
|
override def name = "keyboard"
|
||||||
|
|
||||||
override def receive(message: INetworkMessage) = message.data match {
|
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
|
// TODO check if player is close enough and only consume message if so
|
||||||
network.sendToAll(this, "signal", "key_down", c)
|
network.sendToAll(this, "signal", "key_down", char.toString, code)
|
||||||
message.cancel()
|
message.cancel() // One keyboard is enough.
|
||||||
None
|
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
|
// TODO check if player is close enough and only consume message if so
|
||||||
network.sendToAll(this, "signal", "key_up", c)
|
network.sendToAll(this, "signal", "key_up", char.toString, code)
|
||||||
message.cancel()
|
message.cancel() // One keyboard is enough.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
case _ => None
|
case _ => None
|
||||||
|
@ -67,12 +67,12 @@ class PacketHandler extends CommonPacketHandler {
|
|||||||
def onKeyDown(p: PacketParser) =
|
def onKeyDown(p: PacketParser) =
|
||||||
p.readTileEntity[INetworkNode]() match {
|
p.readTileEntity[INetworkNode]() match {
|
||||||
case None => // Invalid packet.
|
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) =
|
def onKeyUp(p: PacketParser) =
|
||||||
p.readTileEntity[INetworkNode]() match {
|
p.readTileEntity[INetworkNode]() match {
|
||||||
case None => // Invalid packet.
|
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.
|
// resuming the state again.
|
||||||
val sleep = (lua.toNumber(2) * 1000).toLong
|
val sleep = (lua.toNumber(2) * 1000).toLong
|
||||||
lua.pop(results)
|
lua.pop(results)
|
||||||
state = State.Sleeping
|
if (signals.isEmpty) {
|
||||||
future = Some(Executor.pool.
|
state = State.Sleeping
|
||||||
schedule(this, sleep, TimeUnit.MILLISECONDS))
|
future = Some(Executor.pool.schedule(this, sleep, TimeUnit.MILLISECONDS))
|
||||||
|
} else future = Some(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 driver call.
|
// If we get one function it's a wrapper for a synchronized call.
|
||||||
state = State.SynchronizedCall
|
state = State.SynchronizedCall
|
||||||
future = None
|
future = None
|
||||||
}
|
}
|
||||||
@ -673,7 +674,8 @@ class Computer(val owner: IComputerEnvironment) extends IComputer with Runnable
|
|||||||
// 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 = 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
|
package li.cil.oc.server.computer
|
||||||
|
|
||||||
|
import li.cil.oc.OpenComputers
|
||||||
import li.cil.oc.api.INetwork
|
import li.cil.oc.api.INetwork
|
||||||
import li.cil.oc.api.INetworkMessage
|
import li.cil.oc.api.INetworkMessage
|
||||||
import li.cil.oc.api.INetworkNode
|
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)
|
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(
|
if (locked) throw new IllegalStateException(
|
||||||
"Cannot modify network while it is already updating its structure.")
|
"Cannot modify network while it is already updating its structure.")
|
||||||
locked = true
|
|
||||||
|
|
||||||
val containsA = nodes.get(nodeA.address).exists(_.exists(_.data == nodeA))
|
val containsA = nodes.get(nodeA.address).exists(_.exists(_.data == nodeA))
|
||||||
val containsB = nodes.get(nodeB.address).exists(_.exists(_.data == nodeB))
|
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 if (containsA) add(nodes(nodeA.address).find(_.data == nodeA).get, nodeB)
|
||||||
else add(nodes(nodeB.address).find(_.data == nodeB).get, nodeA)
|
else add(nodes(nodeB.address).find(_.data == nodeB).get, nodeA)
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
locked = false
|
|
||||||
}
|
|
||||||
|
|
||||||
def remove(node: INetworkNode) = nodes.get(node.address) match {
|
def remove(node: INetworkNode) = nodes.get(node.address) match {
|
||||||
case None => false
|
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]) = {
|
private def send(message: Network.Message, nodes: Iterator[INetworkNode]) = {
|
||||||
var result = None: Option[Array[Any]]
|
var result = None: Option[Array[Any]]
|
||||||
while (!message.isCanceled && nodes.hasNext) {
|
while (!message.isCanceled && nodes.hasNext) {
|
||||||
nodes.next().receive(message) match {
|
try {
|
||||||
case None => // Ignore.
|
nodes.next().receive(message) match {
|
||||||
case r => result = r
|
case None => // Ignore.
|
||||||
|
case r => result = r
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
case e: Throwable =>
|
||||||
|
OpenComputers.log.warning("Error in message handler:\n" + e.getStackTraceString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
@ -124,7 +126,6 @@ class Network private(private val nodes: mutable.Map[Int, ArrayBuffer[Network.No
|
|||||||
newNode
|
newNode
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val otherNetwork = node.network.asInstanceOf[Network]
|
|
||||||
// We have to merge. First create a copy of the old nodes to have the
|
// 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.
|
// list of nodes to which to send "network.connect" messages.
|
||||||
val oldNodes = nodes.values.flatten.map(_.data).toArray
|
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"
|
// 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
|
// messages to old nodes in case we have to change a node's address to
|
||||||
// ensure unique addresses in the merged network.
|
// ensure unique addresses in the merged network.
|
||||||
|
val otherNetwork = node.network.asInstanceOf[Network]
|
||||||
val otherNodes = otherNetwork.nodes.values.flatten.map(_.data)
|
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.
|
// Pre-merge step: ensure addresses are unique.
|
||||||
for (node <- otherNodes if nodes.contains(node.address)) {
|
for (node <- otherNodes if nodes.contains(node.address)) {
|
||||||
val oldAddress = 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
|
node.data.network = this
|
||||||
send(new Network.Message(node.data, "network.connect"), oldNodes.iterator)
|
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.
|
// Return the node object of the newly connected node for the next step.
|
||||||
nodes(node.address).find(_.data == node).get
|
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