mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
Working line-of-text and single key input
Former-commit-id: 339650979ff2cb5ec18b52a9f3f38b281c7862c9 Former-commit-id: d5ebd860afc8d569ba9ab741b6ca7872380af949
This commit is contained in:
@@ -19,7 +19,7 @@ import org.newdawn.slick.state.StateBasedGame
|
||||
*/
|
||||
class StateVTTest : BasicGameState() {
|
||||
|
||||
val vt = SimpleTextTerminal(SimpleTextTerminal.WHITE, 80, 25, colour = true)
|
||||
val vt = SimpleTextTerminal(SimpleTextTerminal.IBM_GREEN, 80, 25, colour = false)
|
||||
val computerInside = BaseTerrarumComputer(vt)
|
||||
|
||||
val vtUI = Image(vt.displayW, vt.displayH)
|
||||
@@ -29,7 +29,7 @@ class StateVTTest : BasicGameState() {
|
||||
}
|
||||
|
||||
override fun init(container: GameContainer, game: StateBasedGame) {
|
||||
vt.openInput()
|
||||
//vt.openInput()
|
||||
}
|
||||
|
||||
override fun update(container: GameContainer, game: StateBasedGame, delta: Int) {
|
||||
@@ -57,15 +57,13 @@ class StateVTTest : BasicGameState() {
|
||||
super.keyPressed(key, c)
|
||||
vt.keyPressed(key, c)
|
||||
|
||||
if (key == Key.RETURN) {
|
||||
val input = vt.closeInput()
|
||||
|
||||
computerInside.runCommand(input, "=prompt")
|
||||
|
||||
vt.openInput()
|
||||
|
||||
if (!computerInside.isHalted)
|
||||
computerInside.runCommand("io.write(_COMPUTER.prompt)", "=prompt")
|
||||
if (!computerInside.isHalted) {
|
||||
if (key == Key.RETURN && computerInside.luaJ_globals["__scanMode__"].checkjstring() == "line") {
|
||||
vt.closeInputString() // cut input by pressing Key.RETURN
|
||||
}
|
||||
else if (computerInside.luaJ_globals["__scanMode__"].checkjstring() == "a_key") {
|
||||
vt.closeInputKey(key) // cut input by pressing any key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua
Normal file
74
src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
--[[
|
||||
Must be loaded VERY FIRST!
|
||||
|
||||
Created by minjaesong on 16-09-13.
|
||||
--]]
|
||||
|
||||
-- path for any ingame libraries
|
||||
package.path = "/net/torvald/terrarum/virtualcomputer/assets/lua/?.lua;" .. package.path
|
||||
|
||||
-- global variables
|
||||
_G._VERSION = "Luaj-jse 5.2"
|
||||
_G.MONEYSYM = string.char(0x9D) -- currency sign
|
||||
_G.MIDDOT = string.char(0xFA) -- middle dot sign
|
||||
_G.DC1 = string.char(17) -- black
|
||||
_G.DC2 = string.char(18) -- white
|
||||
_G.DC3 = string.char(19) -- dim grey
|
||||
_G.DC4 = string.char(20) -- light grey
|
||||
_G.DLE = string.char(16) -- default error colour
|
||||
_G.getMem = function() collectgarbage() return collectgarbage("count") * 1024 end
|
||||
-- getTotalMem: implemented in Kotlin class
|
||||
_G.getFreeMem = function() return getTotalMem() - getMem() end
|
||||
_G.runscript = function(s, env)
|
||||
local code, reason = load(s, env)
|
||||
|
||||
if _G.getFreeMem() <= 0 then
|
||||
print("out of memory")
|
||||
__haltsystemexplicit__()
|
||||
return
|
||||
end
|
||||
|
||||
if code then
|
||||
xpcall(code, eprint)
|
||||
else
|
||||
print(DLE..tostring(reason))
|
||||
end
|
||||
end
|
||||
_G.__scanMode__ = "UNINIT" -- part of inputstream implementation
|
||||
|
||||
_COMPUTER = {} -- standard console colours
|
||||
_COMPUTER.prompt = DC3.."> "..DC4
|
||||
_COMPUTER.verbose = true -- print debug info
|
||||
_COMPUTER.loadedCLayer = {} -- list of loaded compatibility layers
|
||||
_COMPUTER.bootloader = "/boot/efi"
|
||||
_COMPUTER.OEM = ""
|
||||
|
||||
-- failsafe
|
||||
if getTotalMem() == 0 then print("no RAM installed") __haltsystemexplicit__() return end
|
||||
if _G.getFreeMem() <= 0 then print("out of memory") __haltsystemexplicit__() return end
|
||||
|
||||
-- load libraries that coded in Lua
|
||||
require("ROMLIB")
|
||||
|
||||
-- load bios, if any
|
||||
if fs.exists(_COMPUTER.bootloader) then shell.run(_COMPUTER.bootloader) end
|
||||
-- halt/run luaprompt upon the termination of bios.
|
||||
-- Valid BIOS should load OS and modify 'shell.status' to 'shell.halt' before terminating itself.
|
||||
if shell.status == shell.halt then
|
||||
__haltsystemexplicit__()
|
||||
end
|
||||
|
||||
-- load Lua prompt, if bios is not found
|
||||
if (#_COMPUTER.OEM > 0) then print(_COMPUTER.OEM) end
|
||||
print("Rom basic "..DC2.._VERSION..DC4)
|
||||
print(DC2..tostring(math.floor(getFreeMem()/1024+0.5))..DC4.." Kbytes free")
|
||||
print("Ok")
|
||||
|
||||
while not native.isHalted() do
|
||||
io.write(_COMPUTER.prompt)
|
||||
local s = io.read()
|
||||
runscript(s, "=stdin")
|
||||
end
|
||||
|
||||
native.closeInputString()
|
||||
return
|
||||
@@ -55,7 +55,9 @@ colors.yellow = 0x10
|
||||
colors.lime = 0x20
|
||||
colors.pink = 0x40
|
||||
colors.gray = 0x80
|
||||
colors.grey = 0x80
|
||||
colors.lightGray = 0x100
|
||||
colors.lightGrey = 0x100
|
||||
colors.cyan = 0x200
|
||||
colors.purple = 0x400
|
||||
colors.blue = 0x800
|
||||
@@ -64,28 +66,6 @@ colors.green = 0x2000
|
||||
colors.red = 0x4000
|
||||
colors.black = 0x8000
|
||||
|
||||
colors.combine = function(...)
|
||||
local ret = 0
|
||||
for _, c in ipairs(...) do
|
||||
ret = bor(ret, c)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function containsCol(target, cccol)
|
||||
return bit32.band(target, cccol) > 0
|
||||
end
|
||||
|
||||
colors.subtract = function(cccol, ...)
|
||||
for _, c in ipairs(...) do
|
||||
if not containsCol(cccol, c) then
|
||||
cccol = bit32.bxor(cccol, c)
|
||||
end
|
||||
end
|
||||
return cccol
|
||||
end
|
||||
|
||||
|
||||
local function normaliseCCcol(cccol)
|
||||
if cccol >= 0x1 and cccol <= 0xFFFF then
|
||||
return intLog2(cccol)
|
||||
@@ -95,6 +75,9 @@ local function normaliseCCcol(cccol)
|
||||
end
|
||||
|
||||
|
||||
_G.colours = _G.colors
|
||||
|
||||
|
||||
--------------
|
||||
-- TERM API --
|
||||
--------------
|
||||
@@ -172,6 +155,7 @@ fs.copy = function(a, b) fs.cp(a, b) end
|
||||
fs.delete = function(p) fs.rm(p) end
|
||||
fs.combine = function(a, b) return fs.concat(a, b) end
|
||||
fs.getDir = function(p) return fs.parent(p) end
|
||||
fs.run = function(p) fs.dofile(p) end
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
--[[
|
||||
Must be loaded VERY FIRST!
|
||||
|
||||
Created by minjaesong on 16-09-13.
|
||||
--]]
|
||||
|
||||
-- path for any ingame libraries
|
||||
package.path = "/net/torvald/terrarum/virtualcomputer/assets/lua/?.lua;" .. package.path
|
||||
|
||||
-- global variables
|
||||
_G.MONEYSYM = string.char(0x9D) -- currency sign
|
||||
_G.MIDDOT = string.char(0xFA) -- middle dot sign
|
||||
_COMPUTER = {} -- standard console colours
|
||||
_COMPUTER.DC1 = string.char(17) -- black
|
||||
_COMPUTER.DC2 = string.char(18) -- white
|
||||
_COMPUTER.DC3 = string.char(19) -- dim grey
|
||||
_COMPUTER.DC4 = string.char(20) -- light grey
|
||||
_COMPUTER.prompt = function()
|
||||
io.write(_COMPUTER.DC3.."> ".._COMPUTER.DC4)
|
||||
end
|
||||
_COMPUTER.verbose = true -- print debug info
|
||||
_COMPUTER.loadedCLayer = {} -- list of loaded compatibility layers
|
||||
_COMPUTER.bootloader = "/boot/efi"
|
||||
_COMPUTER.OEM = ""
|
||||
|
||||
-- load libraries that coded in Lua
|
||||
require("ROMLIB")
|
||||
|
||||
-- load bios, if any
|
||||
if fs.exists(_COMPUTER.bootloader) then shell.run(_COMPUTER.bootloader) end
|
||||
-- halt/run luaprompt upon the termination of bios.
|
||||
-- Valid BIOS should load OS and modify 'shell.status' to 'shell.halt' before terminated.
|
||||
if shell.status == shell.halt then
|
||||
__haltsystemexplicit__()
|
||||
else
|
||||
-- load Lua prompt, if bios is not found
|
||||
if (#_COMPUTER.OEM > 0) then print(_COMPUTER.OEM) end
|
||||
print("Rom basic ".._COMPUTER.DC2.._VERSION.._COMPUTER.DC4)
|
||||
-- print(_COMPUTER.DC2..freemem.._COMPUTER.DC4.." bytes free"
|
||||
print("Ok")
|
||||
end
|
||||
@@ -6,16 +6,108 @@
|
||||
-- ALIASES --
|
||||
-------------
|
||||
|
||||
fs.run = function(p)
|
||||
fs.dofile = function(p)
|
||||
local f = fs.open(p, "r")
|
||||
local s = f.readAll()
|
||||
load(s)()
|
||||
_G.runscript(s, "="..p)
|
||||
end
|
||||
|
||||
_G.loadstring = _G.load
|
||||
|
||||
_G.print = term.print
|
||||
|
||||
--_G.dofile = function(f) fs.dofile(f) end
|
||||
|
||||
|
||||
-----------------------------------------
|
||||
-- INPUTSTREAM AND SCANNER (java-like) --
|
||||
-----------------------------------------
|
||||
--[[
|
||||
In whatever code that actually runs everything (computer),
|
||||
there must be:
|
||||
|
||||
override fun keyPressed(key: Int, c: Char) {
|
||||
super.keyPressed(key, c)
|
||||
vt.keyPressed(key, c)
|
||||
|
||||
if (key == Key.RETURN) {
|
||||
val input = vt.closeInputString()
|
||||
}
|
||||
}
|
||||
|
||||
...it basically says to close the input if RETURN is hit,
|
||||
and THIS exact part will close the input for this function.
|
||||
]]
|
||||
_G.__scanForLine__ = function()
|
||||
native.closeInputString()
|
||||
native.openInput()
|
||||
_G.__scanMode__ = "line"
|
||||
local s
|
||||
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
|
||||
s = native.getLastStreamInput()
|
||||
until s
|
||||
-- input is closed when RETURN is hit. See above comments.
|
||||
return s
|
||||
end
|
||||
|
||||
-- use Keys API to identify the keycode
|
||||
_G.__scanForChar__ = function()
|
||||
native.closeInputString()
|
||||
native.openInput()
|
||||
_G.__scanMode__ = "a_key"
|
||||
local key
|
||||
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
|
||||
key = native.getLastKeyPress()
|
||||
until key
|
||||
-- input is closed when any key is hit. See above comments.
|
||||
return key
|
||||
end
|
||||
|
||||
io.read = _G.__scanForLine__
|
||||
|
||||
|
||||
-----------------
|
||||
-- PRINTSTREAM --
|
||||
-----------------
|
||||
|
||||
io.write = function(...)
|
||||
local args = {...}
|
||||
for _, v in ipairs(args) do
|
||||
local s = tostring(v)
|
||||
term.write(s)
|
||||
end
|
||||
end
|
||||
-- for some reason, inputstream above kills 'print' function.
|
||||
-- So we rewrite it.
|
||||
_G.print = function(...)
|
||||
local args = {...}
|
||||
|
||||
io.write(args[1])
|
||||
|
||||
if (#args > 1) then
|
||||
for i = 2, #args do
|
||||
io.write("\t")
|
||||
io.write(args[i])
|
||||
end
|
||||
end
|
||||
|
||||
io.write("\n")
|
||||
end
|
||||
|
||||
|
||||
---------------
|
||||
-- SHELL API --
|
||||
---------------
|
||||
|
||||
_G.shell = {}
|
||||
shell.status = shell.ok
|
||||
|
||||
shell.run = function(p) fs.dofile(p) end
|
||||
|
||||
|
||||
shell.ok = 0
|
||||
shell.halt = 127
|
||||
|
||||
|
||||
--------------
|
||||
-- HEXUTILS --
|
||||
@@ -62,20 +154,6 @@ _G.hexutils.toHexString = function(byteString)
|
||||
end
|
||||
|
||||
|
||||
---------------
|
||||
-- SHELL API --
|
||||
---------------
|
||||
|
||||
_G.shell = {}
|
||||
shell.status = shell.ok
|
||||
|
||||
shell.run = function(p) fs.run(p) end
|
||||
|
||||
|
||||
shell.ok = 0
|
||||
shell.halt = 127
|
||||
|
||||
|
||||
--------------
|
||||
-- KEYS API --
|
||||
--------------
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// TODO Fill in from work_files/romapidoc/romapidoc.tex
|
||||
@@ -3,13 +3,16 @@ package net.torvald.terrarum.virtualcomputer.computer
|
||||
import li.cil.repack.org.luaj.vm2.Globals
|
||||
import li.cil.repack.org.luaj.vm2.LuaError
|
||||
import li.cil.repack.org.luaj.vm2.LuaValue
|
||||
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
|
||||
import li.cil.repack.org.luaj.vm2.lib.jse.JsePlatform
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
import net.torvald.terrarum.gameactors.ActorValue
|
||||
import net.torvald.terrarum.virtualcomputer.luaapi.Filesystem
|
||||
import net.torvald.terrarum.virtualcomputer.luaapi.HostAccessProvider
|
||||
import net.torvald.terrarum.virtualcomputer.luaapi.Security
|
||||
import net.torvald.terrarum.virtualcomputer.luaapi.Term
|
||||
import net.torvald.terrarum.virtualcomputer.terminal.*
|
||||
import net.torvald.terrarum.virtualcomputer.worldobject.ComputerPartsCodex
|
||||
import net.torvald.terrarum.virtualcomputer.worldobject.FixtureComputerBase
|
||||
import org.newdawn.slick.GameContainer
|
||||
import java.io.*
|
||||
@@ -22,7 +25,9 @@ import java.io.*
|
||||
* @param term : terminal that is connected to the computer fixtures, null if not connected any.
|
||||
* Created by minjaesong on 16-09-10.
|
||||
*/
|
||||
class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
class BaseTerrarumComputer(val term: Teletype? = null) {
|
||||
|
||||
val DEBUG_UNLIMITED_MEM = false
|
||||
|
||||
val luaJ_globals: Globals = JsePlatform.standardGlobals()
|
||||
|
||||
@@ -33,6 +38,20 @@ class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
var termIn: InputStream? = null
|
||||
private set
|
||||
|
||||
val processorCycle: Int // number of Lua statement to process per tick (1/100 s)
|
||||
get() = ComputerPartsCodex.getProcessorCycles(computerValue.getAsInt("processor") ?: 0)
|
||||
val memSize: Int // max: 8 GB
|
||||
get() {
|
||||
if (DEBUG_UNLIMITED_MEM) return 1.shl(30)// 1 GB
|
||||
|
||||
var size = 0
|
||||
for (i in 0..3)
|
||||
size += ComputerPartsCodex.getRamSize(computerValue.getAsInt("memSlot$i") ?: 0)
|
||||
|
||||
return 16.shl(20)
|
||||
return size
|
||||
}
|
||||
|
||||
val UUID = java.util.UUID.randomUUID().toString()
|
||||
|
||||
val computerValue = KVHashMap()
|
||||
@@ -40,7 +59,7 @@ class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
var isHalted = false
|
||||
|
||||
init {
|
||||
computerValue["memslot0"] = -1 // -1 indicates mem slot is empty
|
||||
computerValue["memslot0"] = 4864 // -1 indicates mem slot is empty
|
||||
computerValue["memslot1"] = -1 // put index of item here
|
||||
computerValue["memslot2"] = -1 // ditto.
|
||||
computerValue["memslot3"] = -1 // do.
|
||||
@@ -77,11 +96,15 @@ class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
Term(luaJ_globals, term)
|
||||
Security(luaJ_globals)
|
||||
Filesystem(luaJ_globals, this)
|
||||
HostAccessProvider(luaJ_globals, this)
|
||||
}
|
||||
|
||||
// ROM BASIC
|
||||
val inputStream = javaClass.getResourceAsStream("/net/torvald/terrarum/virtualcomputer/assets/lua/ROMBASIC.lua")
|
||||
runCommand(InputStreamReader(inputStream), "rombasic")
|
||||
val inputStream = javaClass.getResourceAsStream("/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua")
|
||||
runCommand(InputStreamReader(inputStream), "=boot")
|
||||
|
||||
// computer-related global functions
|
||||
luaJ_globals["getTotalMem"] = LuaFunGetTotalMem(this)
|
||||
}
|
||||
|
||||
var threadTimer = 0
|
||||
@@ -104,6 +127,10 @@ class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(key: Int, c: Char) {
|
||||
|
||||
}
|
||||
|
||||
var currentExecutionThread = Thread()
|
||||
var threadRun = false
|
||||
|
||||
@@ -165,10 +192,14 @@ class BaseTerrarumComputer(term: Teletype? = null) {
|
||||
lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}")
|
||||
if (DEBUGTHRE) e.printStackTrace(System.err)
|
||||
}
|
||||
|
||||
lua.load("_COMPUTER.prompt()").call()
|
||||
}
|
||||
|
||||
val DEBUGTHRE = true
|
||||
}
|
||||
|
||||
class LuaFunGetTotalMem(val computer: BaseTerrarumComputer) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(computer.memSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,25 +24,28 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["fs"] = LuaValue.tableOf()
|
||||
globals["fs"]["list"] = ListFiles(computer)
|
||||
globals["fs"]["exists"] = FileExists(computer)
|
||||
globals["fs"]["isDir"] = IsDirectory(computer)
|
||||
globals["fs"]["list"] = ListFiles(computer) // CC compliant
|
||||
globals["fs"]["exists"] = FileExists(computer) // CC/OC compliant
|
||||
globals["fs"]["isDir"] = IsDirectory(computer) // CC compliant
|
||||
globals["fs"]["isFile"] = IsFile(computer)
|
||||
globals["fs"]["isReadOnly"] = IsReadOnly(computer)
|
||||
globals["fs"]["getSize"] = GetSize(computer)
|
||||
globals["fs"]["listFiles"] = ListFiles(computer)
|
||||
globals["fs"]["isReadOnly"] = IsReadOnly(computer) // CC compliant
|
||||
globals["fs"]["getSize"] = GetSize(computer) // CC compliant
|
||||
globals["fs"]["mkdir"] = Mkdir(computer)
|
||||
globals["fs"]["mv"] = Mv(computer)
|
||||
globals["fs"]["cp"] = Cp(computer)
|
||||
globals["fs"]["rm"] = Rm(computer)
|
||||
globals["fs"]["concat"] = ConcatPath(computer)
|
||||
globals["fs"]["open"] = OpenFile(computer)
|
||||
globals["fs"]["concat"] = ConcatPath(computer) // OC compliant
|
||||
globals["fs"]["open"] = OpenFile(computer) //CC compliant
|
||||
globals["fs"]["parent"] = GetParentDir(computer)
|
||||
globals["__haltsystemexplicit__"] = HaltComputer(computer)
|
||||
// fs.run defined in ROMLIB
|
||||
// fs.dofile defined in ROMLIB
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun ensurePathSanity(path: LuaValue) {
|
||||
if (path.checkIBM437().contains(Regex("""\.\.""")))
|
||||
throw LuaError("'..' on path is not supported.")
|
||||
}
|
||||
|
||||
val isCaseInsensitive: Boolean
|
||||
get() {
|
||||
// TODO add: force case insensitive in config
|
||||
@@ -72,7 +75,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
|
||||
fun isValidFilename(name: String) = !name.contains(invalidChars)
|
||||
|
||||
fun validatePath(path: String): String {
|
||||
fun validatePath(path: String) : String {
|
||||
if (!isValidFilename(path)) {
|
||||
throw IOException("path contains invalid characters")
|
||||
}
|
||||
@@ -82,7 +85,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
/** actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
* directs media/ directory to /<uuid> directory
|
||||
*/
|
||||
fun BaseTerrarumComputer.getRealPath(luapath: LuaValue): String {
|
||||
fun BaseTerrarumComputer.getRealPath(luapath: LuaValue) : String {
|
||||
// direct mounted paths to real path
|
||||
val computerDir = Terrarum.currentSaveDir.absolutePath + "/computers/"
|
||||
/* if not begins with "(/?)media/", direct to boot
|
||||
@@ -96,7 +99,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
*/
|
||||
|
||||
// remove first '/' in path
|
||||
var path = luapath.checkjstring()
|
||||
var path = luapath.checkIBM437()
|
||||
if (path.startsWith('/')) path = path.substring(1)
|
||||
// replace '\' with '/'
|
||||
path.replace('\\', '/')
|
||||
@@ -111,7 +114,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
fun combinePath(base: String, local: String): String {
|
||||
fun combinePath(base: String, local: String) : String {
|
||||
return "$base$local".replace("//", "/").replace("\\\\", "\\")
|
||||
}
|
||||
}
|
||||
@@ -121,8 +124,10 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
*
|
||||
* actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
*/
|
||||
class ListFiles(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class ListFiles(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
val table = LuaTable()
|
||||
val file = File(computer.getRealPath(path))
|
||||
file.list().forEachIndexed { i, s -> table.insert(i, LuaValue.valueOf(s)) }
|
||||
@@ -130,33 +135,43 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
class FileExists(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class FileExists(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).exists())
|
||||
}
|
||||
}
|
||||
|
||||
class IsDirectory(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class IsDirectory(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).isDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
class IsFile(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class IsFile(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).isFile)
|
||||
}
|
||||
}
|
||||
|
||||
class IsReadOnly(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class IsReadOnly(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(!File(computer.getRealPath(path)).canWrite())
|
||||
}
|
||||
}
|
||||
|
||||
/** we have 4GB file size limit */
|
||||
class GetSize(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class GetSize(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).length().toInt())
|
||||
}
|
||||
}
|
||||
@@ -166,8 +181,10 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Mkdir(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class Mkdir(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).mkdir())
|
||||
}
|
||||
}
|
||||
@@ -175,14 +192,17 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
/**
|
||||
* moves a directory, overwrites the target
|
||||
*/
|
||||
class Mv(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue): LuaValue {
|
||||
class Mv(val computer: BaseTerrarumComputer) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(from)
|
||||
Filesystem.ensurePathSanity(to)
|
||||
|
||||
val fromFile = File(computer.getRealPath(from))
|
||||
fromFile.copyRecursively(
|
||||
var success = fromFile.copyRecursively(
|
||||
File(computer.getRealPath(to)), overwrite = true
|
||||
)
|
||||
fromFile.deleteRecursively()
|
||||
return LuaValue.NONE
|
||||
) // ignore IntelliJ's observation; it's opposite from redundant
|
||||
success = fromFile.deleteRecursively()
|
||||
return LuaValue.valueOf(success)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,8 +210,11 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
* copies a directory, overwrites the target
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Cp(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue): LuaValue {
|
||||
class Cp(val computer: BaseTerrarumComputer) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(from)
|
||||
Filesystem.ensurePathSanity(to)
|
||||
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(from)).copyRecursively(
|
||||
File(computer.getRealPath(to)), overwrite = true
|
||||
@@ -203,17 +226,22 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Rm(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
class Rm(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(path)).deleteRecursively()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ConcatPath(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(base: LuaValue, local: LuaValue): LuaValue {
|
||||
val combinedPath = combinePath(base.checkjstring(), local.checkjstring())
|
||||
class ConcatPath(val computer: BaseTerrarumComputer) : TwoArgFunction() {
|
||||
override fun call(base: LuaValue, local: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(base)
|
||||
Filesystem.ensurePathSanity(local)
|
||||
|
||||
val combinedPath = combinePath(base.checkIBM437(), local.checkIBM437())
|
||||
return LuaValue.valueOf(combinedPath)
|
||||
}
|
||||
}
|
||||
@@ -244,9 +272,13 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
* writeBytes = function(string as bytearray)
|
||||
* }
|
||||
*/
|
||||
class OpenFile(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(path: LuaValue, mode: LuaValue): LuaValue {
|
||||
val mode = mode.checkjstring().toLowerCase()
|
||||
class OpenFile(val computer: BaseTerrarumComputer) : TwoArgFunction() {
|
||||
override fun call(path: LuaValue, mode: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
|
||||
|
||||
val mode = mode.checkIBM437().toLowerCase()
|
||||
val luaClass = LuaTable()
|
||||
val file = File(computer.getRealPath(path))
|
||||
|
||||
@@ -255,6 +287,9 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
"${if (mode.startsWith('w')) "read" else "append"} mode" +
|
||||
": is readonly.")
|
||||
|
||||
|
||||
|
||||
|
||||
when (mode) {
|
||||
"r" -> {
|
||||
try {
|
||||
@@ -312,9 +347,11 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
class GetParentDir(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
var pathSB = StringBuilder(path.checkjstring())
|
||||
class GetParentDir(val computer: BaseTerrarumComputer) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
Filesystem.ensurePathSanity(path)
|
||||
|
||||
var pathSB = StringBuilder(path.checkIBM437())
|
||||
|
||||
// backward travel, drop chars until '/' has encountered
|
||||
while (!pathSB.endsWith('/') && !pathSB.endsWith('\\'))
|
||||
@@ -328,22 +365,13 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
class HaltComputer(val computer: BaseTerrarumComputer): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
computer.isHalted = true
|
||||
computer.luaJ_globals.load("""print("system halted.")""", "=").call()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// OpenFile implementations //
|
||||
//////////////////////////////
|
||||
|
||||
private class FileClassClose(val fo: Any): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
private class FileClassClose(val fo: Any) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.close()
|
||||
else if (fo is FileWriter)
|
||||
@@ -359,16 +387,16 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteByte(val fos: FileOutputStream): OneArgFunction() {
|
||||
override fun call(byte: LuaValue): LuaValue {
|
||||
private class FileClassWriteByte(val fos: FileOutputStream) : OneArgFunction() {
|
||||
override fun call(byte: LuaValue) : LuaValue {
|
||||
fos.write(byte.checkint())
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteBytes(val fos: FileOutputStream): OneArgFunction() {
|
||||
override fun call(byteString: LuaValue): LuaValue {
|
||||
private class FileClassWriteBytes(val fos: FileOutputStream) : OneArgFunction() {
|
||||
override fun call(byteString: LuaValue) : LuaValue {
|
||||
val byteString = byteString.checkIBM437()
|
||||
val bytearr = ByteArray(byteString.length, { byteString[it].toByte() })
|
||||
fos.write(bytearr)
|
||||
@@ -377,24 +405,24 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintText(val fw: FileWriter): OneArgFunction() {
|
||||
override fun call(string: LuaValue): LuaValue {
|
||||
private class FileClassPrintText(val fw: FileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437()
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintlnText(val fw: FileWriter): OneArgFunction() {
|
||||
override fun call(string: LuaValue): LuaValue {
|
||||
private class FileClassPrintlnText(val fw: FileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437() + "\n"
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassFlush(val fo: Any): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
private class FileClassFlush(val fo: Any) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.flush()
|
||||
else if (fo is FileWriter)
|
||||
@@ -406,31 +434,31 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadByte(val fis: FileInputStream): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
private class FileClassReadByte(val fis: FileInputStream) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
val readByte = fis.read()
|
||||
return if (readByte == -1) LuaValue.NIL else LuaValue.valueOf(readByte)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAllBytes(val path: Path): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
private class FileClassReadAllBytes(val path: Path) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
val byteArr = Files.readAllBytes(path)
|
||||
val s: String = java.lang.String(byteArr, "IBM437").toString()
|
||||
return LuaValue.valueOf(s)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAll(val path: Path): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
private class FileClassReadAll(val path: Path) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
return FileClassReadAllBytes(path).call()
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadLine(val fr: FileReader): ZeroArgFunction() {
|
||||
private class FileClassReadLine(val fr: FileReader) : ZeroArgFunction() {
|
||||
val scanner = Scanner(fr.readText()) // no closing; keep the scanner status persistent
|
||||
|
||||
override fun call(): LuaValue {
|
||||
override fun call() : LuaValue {
|
||||
return if (scanner.hasNextLine()) LuaValue.valueOf(scanner.nextLine())
|
||||
else LuaValue.NIL
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package net.torvald.terrarum.virtualcomputer.luaapi
|
||||
|
||||
import li.cil.repack.org.luaj.vm2.Globals
|
||||
import li.cil.repack.org.luaj.vm2.LuaTable
|
||||
import li.cil.repack.org.luaj.vm2.LuaValue
|
||||
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
|
||||
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
|
||||
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
|
||||
import net.torvald.terrarum.virtualcomputer.luaapi.Term.Companion.checkIBM437
|
||||
import net.torvald.terrarum.virtualcomputer.terminal.Teletype
|
||||
|
||||
/**
|
||||
* Provide Lua an access to computer object that is in Java
|
||||
*
|
||||
* Created by minjaesong on 16-09-19.
|
||||
*/
|
||||
internal class HostAccessProvider(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
|
||||
init {
|
||||
globals["native"] = LuaTable()
|
||||
globals["native"]["println"] = PrintLn()
|
||||
globals["native"]["isHalted"] = IsHalted(computer)
|
||||
|
||||
globals["native"]["closeInputString"] = NativeCloseInputString(computer.term!!)
|
||||
globals["native"]["closeInputKey"] = NativeCloseInputKey(computer.term!!)
|
||||
globals["native"]["openInput"] = NativeOpenInput(computer.term!!)
|
||||
globals["native"]["getLastStreamInput"] = NativeGetLastStreamInput(computer.term!!)
|
||||
globals["native"]["getLastKeyPress"] = NativeGetLastKeyPress(computer.term!!)
|
||||
|
||||
// while lua's dofile/require is fixiated to fs, this command allows
|
||||
// libraries in JAR to be loaded.
|
||||
//globals["native"]["loadBuiltInLib"] = NativeLoadBuiltInLib()
|
||||
|
||||
globals["__haltsystemexplicit__"] = HaltComputer(computer)
|
||||
}
|
||||
|
||||
class PrintLn(): OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
println(p0.checkIBM437())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class IsHalted(val computer: BaseTerrarumComputer): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(computer.isHalted)
|
||||
}
|
||||
}
|
||||
|
||||
class NativeCloseInputString(val term: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.closeInputString()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class NativeCloseInputKey(val term: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
//term.closeInputKey()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class NativeOpenInput(val term: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.openInput()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class NativeGetLastStreamInput(val term: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return if (term.lastStreamInput == null) LuaValue.NIL
|
||||
else LuaValue.valueOf(term.lastStreamInput)
|
||||
}
|
||||
}
|
||||
|
||||
class NativeGetLastKeyPress(val term: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return if (term.lastKeyPress == null) LuaValue.NIL
|
||||
else LuaValue.valueOf(term.lastKeyPress!!)
|
||||
}
|
||||
}
|
||||
|
||||
class HaltComputer(val computer: BaseTerrarumComputer) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
computer.isHalted = true
|
||||
computer.luaJ_globals.load("""print("system halted")""").call()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ internal class Term(globals: Globals, term: Teletype) {
|
||||
globals["term"]["resetColour"] = Term.ResetColour(term)
|
||||
globals["term"]["clear"] = Term.Clear(term)
|
||||
globals["term"]["clearLine"] = Term.ClearLine(term)
|
||||
globals["term"]["moveCursor"] = Term.SetCursorPos(term)
|
||||
globals["term"]["getCursor"] = Term.GetCursorPos(term)
|
||||
globals["term"]["getX"] = Term.GetCursorX(term)
|
||||
globals["term"]["getY"] = Term.GetCursorY(term)
|
||||
@@ -141,10 +140,10 @@ internal class Term(globals: Globals, term: Teletype) {
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorPos(number x, number y) */
|
||||
/** term.setCursorPos(number x, number y), One-based */
|
||||
class SetCursorPos(val term: Terminal) : TwoArgFunction() {
|
||||
override fun call(x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.setCursor(x.checkint(), y.checkint())
|
||||
term.setCursor(x.checkint() - 1, y.checkint() - 1)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
@@ -158,22 +157,23 @@ internal class Term(globals: Globals, term: Teletype) {
|
||||
}
|
||||
}
|
||||
|
||||
/** One-based */
|
||||
class GetCursorPos(val term: Terminal) : VarArgFunction() {
|
||||
override fun invoke(args: Varargs?): Varargs {
|
||||
val ret = arrayOf(LuaValue.valueOf(term.cursorX), LuaValue.valueOf(term.cursorY))
|
||||
val ret = arrayOf(LuaValue.valueOf(term.cursorX + 1), LuaValue.valueOf(term.cursorY + 1))
|
||||
return LuaValue.varargsOf(ret)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorX(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorX)
|
||||
return LuaValue.valueOf(term.cursorX + 1)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorY(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorY)
|
||||
return LuaValue.valueOf(term.cursorY + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ open class SimpleTextTerminal(
|
||||
Color(0x00, 0x00, 0x00), // 0 black
|
||||
Color(0xff, 0xff, 0xff), // 1 white
|
||||
Color(0x55, 0x55, 0x55), // 2 dim grey
|
||||
Color(0xaa, 0xaa, 0xaa), // 3 light grey
|
||||
Color(0xaa, 0xaa, 0xaa), // 3 bright grey
|
||||
|
||||
Color(0xff, 0xff, 0x00), // 4 yellow
|
||||
Color(0xff, 0x66, 0x00), // 5 orange
|
||||
@@ -39,7 +39,7 @@ open class SimpleTextTerminal(
|
||||
Color(0x33, 0x00, 0x99), // 8 purple
|
||||
Color(0x00, 0x00, 0xcc), // 9 blue
|
||||
Color(0x00, 0x99, 0xff), //10 cyan
|
||||
Color(0x66, 0xff, 0x33), //11 lime
|
||||
Color(0x55, 0xff, 0x00), //11 lime
|
||||
|
||||
Color(0x00, 0xaa, 0x00), //12 green
|
||||
Color(0x00, 0x66, 0x00), //13 dark green
|
||||
@@ -83,7 +83,7 @@ open class SimpleTextTerminal(
|
||||
override val displayH = fontH * height
|
||||
|
||||
|
||||
private val TABSIZE = 4
|
||||
var TABSIZE = 4
|
||||
|
||||
private var cursorBlinkTimer = 0
|
||||
private val cursorBlinkLen = 250
|
||||
@@ -185,6 +185,7 @@ open class SimpleTextTerminal(
|
||||
|
||||
}
|
||||
|
||||
/** Unlike lua function, this one in Zero-based. */
|
||||
override fun setCursor(x: Int, y: Int) {
|
||||
cursorX = x
|
||||
cursorY = y
|
||||
@@ -387,18 +388,31 @@ open class SimpleTextTerminal(
|
||||
/**
|
||||
* Technically, this is different from Java's InputStream
|
||||
*/
|
||||
fun openInput() {
|
||||
override fun openInput() {
|
||||
lastStreamInput = null
|
||||
lastKeyPress = null
|
||||
inputOpen = true
|
||||
if (DEBUG) println("[SimpleTextTerminal] openInput()")
|
||||
}
|
||||
|
||||
fun closeInput(): String {
|
||||
override fun closeInputKey(keyFromUI: Int): Int {
|
||||
inputOpen = false
|
||||
val ret = sb.toString()
|
||||
lastKeyPress = keyFromUI
|
||||
|
||||
if (DEBUG) println("[SimpleTextTerminal] closeInputKey(), $keyFromUI")
|
||||
return keyFromUI
|
||||
}
|
||||
|
||||
override var lastStreamInput: String? = null
|
||||
override var lastKeyPress: Int? = null
|
||||
|
||||
override fun closeInputString(): String {
|
||||
inputOpen = false
|
||||
lastStreamInput = sb.toString()
|
||||
sb = StringBuilder()
|
||||
|
||||
if (DEBUG) println("[SimpleTextTerminal] closeInput(), $ret")
|
||||
return ret
|
||||
if (DEBUG) println("[SimpleTextTerminal] closeInputString(), $lastStreamInput")
|
||||
return lastStreamInput!!
|
||||
}
|
||||
|
||||
override fun keyPressed(key: Int, c: Char) {
|
||||
|
||||
@@ -34,5 +34,12 @@ interface Teletype {
|
||||
fun newLine()
|
||||
fun scroll(amount: Int = 1)
|
||||
|
||||
fun openInput()
|
||||
fun closeInputKey(keyFromUI: Int): Int
|
||||
fun closeInputString(): String
|
||||
|
||||
fun bell(pattern: String = ".")
|
||||
|
||||
var lastStreamInput: String?
|
||||
var lastKeyPress: Int?
|
||||
}
|
||||
@@ -134,18 +134,31 @@ class TeletypeTerminal : Teletype {
|
||||
/**
|
||||
* Technically, this is different from Java's InputStream
|
||||
*/
|
||||
fun openInput() {
|
||||
override fun openInput() {
|
||||
lastStreamInput = null
|
||||
lastKeyPress = null
|
||||
inputOpen = true
|
||||
if (DEBUG) println("[SimpleTextTerminal] openInput()")
|
||||
if (DEBUG) println("[TeletypeTerminal] openInput()")
|
||||
}
|
||||
|
||||
fun closeInput(): String {
|
||||
override fun closeInputKey(keyFromUI: Int): Int {
|
||||
inputOpen = false
|
||||
val ret = sb.toString()
|
||||
lastKeyPress = keyFromUI
|
||||
|
||||
if (DEBUG) println("[TeletypeTerminal] closeInputKey(), $keyFromUI")
|
||||
return keyFromUI
|
||||
}
|
||||
|
||||
override var lastStreamInput: String? = null
|
||||
override var lastKeyPress: Int? = null
|
||||
|
||||
override fun closeInputString(): String {
|
||||
inputOpen = false
|
||||
lastStreamInput = sb.toString()
|
||||
sb = StringBuilder()
|
||||
|
||||
if (DEBUG) println("[SimpleTextTerminal] closeInput(), $ret")
|
||||
return ret
|
||||
if (DEBUG) println("[TeletypeTerminal] closeInputString(), $lastStreamInput")
|
||||
return lastStreamInput!!
|
||||
}
|
||||
|
||||
override fun keyPressed(key: Int, c: Char) {
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
package net.torvald.terrarum.virtualcomputer.terminal;
|
||||
|
||||
import li.cil.repack.com.naef.jnlua.LuaException;
|
||||
import li.cil.repack.com.naef.jnlua.LuaRuntimeException;
|
||||
import li.cil.repack.com.naef.jnlua.LuaState;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-09-10.
|
||||
*/
|
||||
public class TerminalLuaConsole {
|
||||
// -- Static
|
||||
private static final String[] EMPTY_ARGS = new String[0];
|
||||
|
||||
/**
|
||||
* Main routine.
|
||||
*
|
||||
* @param args
|
||||
* the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LuaConsole luaConsole = new LuaConsole(args);
|
||||
luaConsole.run();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private PrintStream out;
|
||||
|
||||
// -- State
|
||||
private LuaState luaState;
|
||||
|
||||
// -- Construction
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public TerminalLuaConsole(Terminal term) {
|
||||
this(EMPTY_ARGS, term);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the specified command line arguments. The
|
||||
* arguments are passed to Lua as the <code>argv</code> global variable.
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public TerminalLuaConsole(String[] args, Terminal term) {
|
||||
out = new TerminalPrintStream(term);
|
||||
|
||||
luaState = new LuaState();
|
||||
|
||||
// Process arguments
|
||||
luaState.newTable(args.length, 0);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
luaState.pushString(args[i]);
|
||||
luaState.rawSet(-2, i + 1);
|
||||
}
|
||||
luaState.setGlobal("argv");
|
||||
|
||||
// Open standard libraries
|
||||
luaState.openLibs();
|
||||
|
||||
// Set buffer mode
|
||||
luaState.load("io.stdout:setvbuf(\"no\")", "=consoleInitStdout");
|
||||
luaState.call(0, 0);
|
||||
luaState.load("io.stderr:setvbuf(\"no\")", "=consoleInitStderr");
|
||||
luaState.call(0, 0);
|
||||
}
|
||||
|
||||
// -- Properties
|
||||
/**
|
||||
* Returns the Lua state of this console.
|
||||
*
|
||||
* @return the Lua state
|
||||
*/
|
||||
public LuaState getLuaState() {
|
||||
return luaState;
|
||||
}
|
||||
|
||||
// -- Operations
|
||||
/**
|
||||
* Runs the console.
|
||||
*/
|
||||
public void run() {
|
||||
// Banner
|
||||
out.println(String.format("JNLua %s Console using Lua %s.",
|
||||
LuaState.VERSION, LuaState.LUA_VERSION));
|
||||
out.print("Type 'go' on an empty line to evaluate a chunk. ");
|
||||
out.println("Type =<expression> to print an expression.");
|
||||
|
||||
// Prepare reader
|
||||
BufferedReader bufferedReader = new BufferedReader(
|
||||
new InputStreamReader(System.in));
|
||||
try {
|
||||
// Process chunks
|
||||
chunk: while (true) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
OutputStreamWriter outWriter = new OutputStreamWriter(out,
|
||||
"UTF-8");
|
||||
boolean firstLine = true;
|
||||
|
||||
// Process lines
|
||||
while (true) {
|
||||
String line = bufferedReader.readLine();
|
||||
if (line == null) {
|
||||
break chunk;
|
||||
}
|
||||
if (line.equals("go")) {
|
||||
outWriter.flush();
|
||||
InputStream in = new ByteArrayInputStream(out
|
||||
.toByteArray());
|
||||
runChunk(in);
|
||||
continue chunk;
|
||||
}
|
||||
if (firstLine && line.startsWith("=")) {
|
||||
outWriter.write("return " + line.substring(1));
|
||||
outWriter.flush();
|
||||
InputStream in = new ByteArrayInputStream(out
|
||||
.toByteArray());
|
||||
runChunk(in);
|
||||
continue chunk;
|
||||
}
|
||||
outWriter.write(line);
|
||||
outWriter.write('\n');
|
||||
firstLine = false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
out.print("IO error: ");
|
||||
out.print(e.getMessage());
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a chunk of Lua code from an input stream.
|
||||
*/
|
||||
protected void runChunk(InputStream in) throws IOException {
|
||||
try {
|
||||
long start = System.nanoTime();
|
||||
luaState.setTop(0);
|
||||
luaState.load(in, "=console", "t");
|
||||
luaState.call(0, LuaState.MULTRET);
|
||||
long stop = System.nanoTime();
|
||||
for (int i = 1; i <= luaState.getTop(); i++) {
|
||||
if (i > 1) {
|
||||
out.print(", ");
|
||||
}
|
||||
switch (luaState.type(i)) {
|
||||
case BOOLEAN:
|
||||
out.print(Boolean.valueOf(luaState.toBoolean(i)));
|
||||
break;
|
||||
case NUMBER:
|
||||
case STRING:
|
||||
out.print(luaState.toString(i));
|
||||
break;
|
||||
default:
|
||||
out.print(luaState.typeName(i));
|
||||
}
|
||||
}
|
||||
out.print("\t#msec=");
|
||||
out.print(String.format("%.3f", (stop - start) / 1000000.0));
|
||||
out.println();
|
||||
} catch (LuaRuntimeException e) {
|
||||
e.printLuaStackTrace();
|
||||
} catch (LuaException e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,14 @@ object ComputerPartsCodex {
|
||||
|
||||
init {
|
||||
// in kilobytes
|
||||
rams.put(4864, 128.KiB()) // 64k is not enough for Lua, so we start here.
|
||||
rams.put(4865, 192.KiB())
|
||||
rams.put(4866, 256.KiB())
|
||||
rams.put(4867, 320.KiB()) // 320 * 2 = "640k ought to be enough for anybody" --Someone that is NOT Bill Gates
|
||||
rams.put(4868, 480.KiB())
|
||||
rams.put(4869, 512.KiB())
|
||||
rams.put(4870, 1024.KiB()) // server ops hate it
|
||||
rams.put(4871, 2048.KiB()) // wait, we can multiplayer?
|
||||
rams.put(4864, 16.MiB())
|
||||
rams.put(4865, 24.MiB())
|
||||
rams.put(4866, 32.MiB())
|
||||
rams.put(4867, 64.MiB())
|
||||
rams.put(4868, 96.MiB())
|
||||
rams.put(4869, 128.MiB())
|
||||
rams.put(4870, 160.MiB())
|
||||
rams.put(4871, 256.MiB())
|
||||
|
||||
processors.put(4872, 1000)
|
||||
processors.put(4873, 2000)
|
||||
@@ -52,4 +52,5 @@ object ComputerPartsCodex {
|
||||
private fun Int.MB() = this * 1000000 // 1 MB == 1 000 000 bytes, bitches!
|
||||
private fun Int.kB() = this * 1000
|
||||
private fun Int.KiB() = this.shr(10)
|
||||
private fun Int.MiB() = this.shr(20)
|
||||
}
|
||||
@@ -14,17 +14,6 @@ import java.util.*
|
||||
*/
|
||||
open class FixtureComputerBase() : FixtureBase() {
|
||||
|
||||
val processorCycle: Int // number of Lua statement to process per tick (1/100 s)
|
||||
get() = ComputerPartsCodex.getProcessorCycles(computerInside!!.computerValue.getAsInt("processor") ?: -1)
|
||||
val memSize: Int // max: 8 GB
|
||||
get() {
|
||||
var size = 0
|
||||
for (i in 0..3)
|
||||
size += ComputerPartsCodex.getRamSize(computerInside!!.computerValue.getAsInt("memSlot$i") ?: -1)
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
/** Connected terminal */
|
||||
var terminal: FixtureBasicTerminal? = null
|
||||
|
||||
@@ -70,6 +59,7 @@ open class FixtureComputerBase() : FixtureBase() {
|
||||
fun keyPressed(key: Int, c: Char) {
|
||||
if (terminal != null) {
|
||||
terminal!!.vt.keyPressed(key, c)
|
||||
computerInside!!.keyPressed(key, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user