mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-14 15:46:06 +09:00
virtualcomputer: unix-like operation system [WIP]
Former-commit-id: 68bb33337b78c7357d16a5a3ca47ad5f834f3d08 Former-commit-id: 6c8931a114682d2b1414414484597f5e0d0ca095
This commit is contained in:
@@ -21,7 +21,7 @@ class StateVTTest : BasicGameState() {
|
||||
|
||||
// HiRes: 100x64, LoRes: 80x25
|
||||
val computerInside = BaseTerrarumComputer(8)
|
||||
val vt = SimpleTextTerminal(SimpleTextTerminal.GREEN, 80, 25,
|
||||
val vt = SimpleTextTerminal(SimpleTextTerminal.AMETHYST_NOVELTY, 80, 25,
|
||||
computerInside, colour = false, hires = false)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
local args = {...}
|
||||
fs.cp(os.expandPath(args[1]), os.expandPath(args[2]))
|
||||
@@ -0,0 +1,245 @@
|
||||
local args = {...}
|
||||
|
||||
os.dshenv = {}
|
||||
|
||||
--[[
|
||||
DUMBSHELL: semi sh-compatible language interpreter
|
||||
|
||||
SYNOPSIS
|
||||
dsh [option] [file]
|
||||
sh [option] [file]
|
||||
|
||||
OPTIONS
|
||||
-c string If the -c option is present, then commands are read from
|
||||
string. If there are arguments after the string, they are
|
||||
assigned to the positional parameters, starting with $0.
|
||||
|
||||
|
||||
]]
|
||||
|
||||
-- returns full path. if p starts with "/", only the p is returned
|
||||
local function expandPath(p)
|
||||
return (p:byte(1) == 47) and p or os.expandPath(p)
|
||||
end
|
||||
|
||||
local function startsFromRoot(p)
|
||||
return p:byte(1) == 47
|
||||
end
|
||||
|
||||
local function endsWithSlash(p)
|
||||
return p:byte(#p) == 47
|
||||
end
|
||||
|
||||
local function errorCmdNotFound(cmd)
|
||||
print(cmd..": command not found")
|
||||
end
|
||||
|
||||
local function errorNoSuchFile(cmd)
|
||||
print(cmd..": No such file")
|
||||
end
|
||||
|
||||
local function errorNoSuchFileOrDir(cmd)
|
||||
print(cmd..": No such file or directory")
|
||||
end
|
||||
|
||||
--local __DSHDEBUG__ = 0x51621D
|
||||
|
||||
local function debug(msg)
|
||||
if __DSHDEBUG__ then print("DEBUG", msg) end
|
||||
end
|
||||
|
||||
-- BUILTINS -------------------------------------------------------------------
|
||||
|
||||
local function cd(args)
|
||||
local dir = args[1]
|
||||
|
||||
if (dir == nil or #dir < 1) then return end
|
||||
|
||||
-- check if the directory exists
|
||||
|
||||
local chkdir = expandPath(dir)
|
||||
|
||||
if not fs.exists(chkdir) then
|
||||
errorNoSuchFileOrDir("cd: "..dir)
|
||||
return
|
||||
end
|
||||
|
||||
-- parse dir by delimeter '/'
|
||||
if (dir:byte(1) == 47) then -- if dir begins with '/'
|
||||
os.workingDir = {""}
|
||||
end
|
||||
|
||||
for word in string.gmatch(dir, "[^/]+") do
|
||||
-- 'execute' directory
|
||||
-- Rules: '..' pops os.workingDir
|
||||
-- if dir begins with '/', re-build os.workingDir
|
||||
-- otherwise, push the 'word' to os.workingDir
|
||||
if (word == "..") then
|
||||
if (#os.workingDir > 1) then
|
||||
os.workingDir[#os.workingDir] = nil -- pops an element to oblivion
|
||||
end
|
||||
elseif (word == ".") then
|
||||
-- pass
|
||||
else
|
||||
table.insert(os.workingDir, word)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function exit(args)
|
||||
exitshell = true
|
||||
end
|
||||
|
||||
local function exec(args)
|
||||
--debug("EXEC\t"..table.concat(args, " "))
|
||||
|
||||
if (args[1] == nil or #args[1] < 1) then return end
|
||||
|
||||
local filePath = args[1]
|
||||
local fullFilePath = expandPath(args[1])
|
||||
local execArgs = {}
|
||||
for i, v in ipairs(args) do
|
||||
if (i >= 2) then table.insert(execArgs, v) end
|
||||
end
|
||||
local execByPathFileExists = false
|
||||
local execByPathArg = ""
|
||||
|
||||
--fs.dofile(fullFilePath, execArgs)
|
||||
-- do some sophisticated file-matching
|
||||
-- step 1: exact file
|
||||
if fs.isFile(fullFilePath) then shell.run(fullFilePath, execArgs)
|
||||
-- step 2: try appending ".lua"
|
||||
elseif fs.isFile(fullFilePath..".lua") then shell.run(fullFilePath..".lua", execArgs)
|
||||
-- step 3: parse os.path (just like $PATH)
|
||||
-- step 3.1: exact file; step 3.2: append ".lua"
|
||||
elseif not startsFromRoot(filePath) then
|
||||
for path in string.gmatch(os.path, "[^;]+") do
|
||||
-- check if 'path' ends with '/'
|
||||
if not endsWithSlash(path) then path = path.."/" end
|
||||
|
||||
debug(path..filePath)
|
||||
|
||||
if fs.isFile(path..filePath) then
|
||||
execByPathArg = path..filePath
|
||||
execByPathFileExists = true
|
||||
break
|
||||
elseif fs.isFile(path..filePath..".lua") then
|
||||
execByPathArg = path..filePath..".lua"
|
||||
execByPathFileExists = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- step else: file not found
|
||||
if execByPathFileExists then
|
||||
shell.run(execByPathArg, execArgs)
|
||||
return EXIT_SUCCESS
|
||||
else
|
||||
if filePath:byte(1) == 46 or filePath:byte(1) == 47 then
|
||||
errorNoSuchFile(filePath)
|
||||
else
|
||||
errorCmdNotFound(filePath)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- SYNTAX PARSER --------------------------------------------------------------
|
||||
|
||||
-- tables with functions
|
||||
local builtins = {
|
||||
cd = cd,
|
||||
exit = exit,
|
||||
exec = exec,
|
||||
clear = term.clear
|
||||
}
|
||||
|
||||
local function runcommand(str)
|
||||
if #str < 1 then return end
|
||||
|
||||
-- simple cmd parse: WORD ARG1 ARG2 ARG3 ...
|
||||
local args = {}
|
||||
local command = ""
|
||||
for word in string.gmatch(str, "[^ ]+") do
|
||||
if #command < 1 then command = word -- first word will be a name of command
|
||||
else table.insert(args, word) end
|
||||
end
|
||||
|
||||
if builtins[command] then -- try for builtins table
|
||||
builtins[command](args)
|
||||
return EXIT_SUCCESS
|
||||
else
|
||||
-- try for os.dshenv.aliases
|
||||
if os.dshenv.aliases[command] then
|
||||
--builtins[os.dshenv.aliases[command]](args)
|
||||
runcommand(os.dshenv.aliases[command])
|
||||
return EXIT_SUCCESS
|
||||
else
|
||||
-- try to launch as program
|
||||
table.insert(args, 1, command)
|
||||
exec(args)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- END OF SYNTAX PARSER -------------------------------------------------------
|
||||
-- INIT SHELL -----------------------------------------------------------------
|
||||
|
||||
exitshell = false
|
||||
|
||||
-- load up aliases
|
||||
if fs.exists("/etc/.dshrc") then fs.dofile("/etc/.dshrc") end
|
||||
|
||||
|
||||
-- END OF INIT SHELL ----------------------------------------------------------
|
||||
|
||||
-- run interpreter and quit
|
||||
if (args[1]) then
|
||||
local f = fs.open(args[1], "r")
|
||||
local line = ""
|
||||
local s = ""
|
||||
|
||||
-- treat interpreter key (#!) properly
|
||||
-- I'm assuming I was called because I'm the right one
|
||||
-- I have a full trust on "shell.run()" that it rightfully redirected to me
|
||||
--
|
||||
-- NOTE: shell redirection should only apply in interactive mode AND the input
|
||||
-- was like "./filename", or else I'm the right one. Period.
|
||||
-- (and that's how BASH works)
|
||||
repeat
|
||||
line = f.readLine()
|
||||
if line == nil then break end
|
||||
if line:sub(1,2) ~= "#!" then -- ignore line that contains hashbang
|
||||
s = s.." "..line
|
||||
end
|
||||
until line == nil
|
||||
|
||||
f.close()
|
||||
|
||||
runcommand(s)
|
||||
|
||||
exitshell = true
|
||||
end
|
||||
|
||||
|
||||
function getPromptText()
|
||||
--return DC4..os.workingDir[#os.workingDir]..DC3.."# "..DC4 -- we're root! omgwtf
|
||||
return DC4..os.fullWorkPath()..DC3.."# "..DC4 -- we're root! omgwtf
|
||||
end
|
||||
|
||||
-- interactive mode
|
||||
local time = os.date()
|
||||
print(time)
|
||||
|
||||
repeat
|
||||
io.write(getPromptText())
|
||||
local s = input.readLine()
|
||||
runcommand(s)
|
||||
until exitshell
|
||||
|
||||
::terminate::
|
||||
collectgarbage()
|
||||
return EXIT_SUCCESS
|
||||
@@ -0,0 +1,68 @@
|
||||
--[[
|
||||
LESS IS MORE
|
||||
|
||||
SYNOPSIS:
|
||||
lessismore [filename]
|
||||
less [filename]
|
||||
more [filename]
|
||||
]]
|
||||
local args = {...}
|
||||
local prompt = function()
|
||||
term.setForeCol(3)
|
||||
term.emitString("scroll", 4, term.height())
|
||||
term.emitString("quit", 15, term.height())
|
||||
term.setForeCol(1)
|
||||
term.emit(18, 1, term.height())
|
||||
term.emit(29, 2, term.height())
|
||||
term.emit(81, 13, term.height())
|
||||
term.setForeCol(3)
|
||||
end
|
||||
|
||||
local function printUsage()
|
||||
print("More: no file specified.")
|
||||
print("Usage: more [filename]")
|
||||
end
|
||||
|
||||
if args[1] == nil or #args[1] <= 0 then printUsage() return end
|
||||
|
||||
----------------
|
||||
-- fetch text --
|
||||
----------------
|
||||
local lines = {}
|
||||
local displayHeight = term.height() - 1 -- bottom one line for prompt
|
||||
|
||||
local file = fs.open(args[1], "r")
|
||||
local line = ""
|
||||
repeat
|
||||
line = file.readLine()
|
||||
table.insert(lines, line)
|
||||
until line == nil
|
||||
|
||||
-------------
|
||||
-- display --
|
||||
-------------
|
||||
if term.isTeletype() then
|
||||
for _, l in ipairs(line) do
|
||||
term.print(l)
|
||||
end
|
||||
else
|
||||
term.clear()
|
||||
term.setCursorBlink(false)
|
||||
|
||||
local key = 0
|
||||
repeat
|
||||
prompt()
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
if (i > displayHeight) then break end
|
||||
|
||||
term.emitString(line, 1, i)
|
||||
end
|
||||
|
||||
term.setCursor(1, term.height())
|
||||
if input.isKeyDown(keys.q) then break end
|
||||
until false
|
||||
end
|
||||
|
||||
term.newLine()
|
||||
return
|
||||
@@ -0,0 +1,76 @@
|
||||
local args = {...}
|
||||
local _APPVERSION = 0.3
|
||||
--[[
|
||||
MOONSHELL: basically just lua.lua
|
||||
|
||||
SYNOPSIS
|
||||
msh [file]
|
||||
|
||||
msh: Runs shell in interactive mode
|
||||
msh [file]: Try to execute file as Lua script
|
||||
|
||||
]]
|
||||
|
||||
-- run interpreter and quit
|
||||
if (args[1]) then
|
||||
local f = fs.open(args[1], "r")
|
||||
local line = ""
|
||||
local s = ""
|
||||
|
||||
-- treat interpreter key (#!) properly
|
||||
-- I'm assuming I was called because I'm the right one
|
||||
-- I have a full trust on "shell.run()" that it rightfully redirected to me
|
||||
repeat
|
||||
line = f.readLine()
|
||||
if line == nil then break end
|
||||
if line:sub(1,2) ~= "#!" then -- ignore line that contains hashbang
|
||||
s = s.." "..line
|
||||
end
|
||||
until line == nil
|
||||
|
||||
f.close()
|
||||
|
||||
xpcall(
|
||||
function() _G.runscript(s, "="..args[1]) end,
|
||||
function(err) print(DLE..err) end
|
||||
)
|
||||
|
||||
goto terminate
|
||||
end
|
||||
|
||||
-- interactive mode. This is a copy of BOOT.lua
|
||||
run = shell.run
|
||||
|
||||
print("Moonshell "..DC2.._APPVERSION..DC4..", running "..DC2.._VERSION..DC4)
|
||||
print("Lua is copyrighted (C) 1994-2013 Lua.org, PUC-Rio")
|
||||
print("Run run(path) to execute program on 'path'.")
|
||||
print("Run exit() to quit.")
|
||||
|
||||
while not machine.isHalted() do
|
||||
term.setCursorBlink(true)
|
||||
|
||||
io.write(DC3.."lua"..computer.prompt)
|
||||
|
||||
local s = input.readLine()
|
||||
|
||||
if s == "exit()" then break end
|
||||
|
||||
xpcall(
|
||||
function()
|
||||
if s:byte(1) == 61 then -- print out value
|
||||
s1 = string.sub(s, 2)
|
||||
_G.runscript("print(tostring("..s1.."))\n", "=stdin")
|
||||
else
|
||||
_G.runscript(s, "=stdin")
|
||||
end
|
||||
end,
|
||||
function(err) print(DLE..err) end -- it catches logical errors
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
::terminate::
|
||||
collectgarbage()
|
||||
return EXIT_SUCCESS
|
||||
@@ -0,0 +1,2 @@
|
||||
local args = {...}
|
||||
fs.mv(os.expandPath(args[1]), os.expandPath(args[2]))
|
||||
@@ -0,0 +1 @@
|
||||
fs.dofile("/etc/_boot.lua")
|
||||
@@ -0,0 +1,8 @@
|
||||
-- dsh aliases
|
||||
os.dshenv.aliases = {
|
||||
lua = "exec msh",
|
||||
sh = "dsh",
|
||||
shutdown = "exit",
|
||||
less = "exec lessismore",
|
||||
more = "exec lessismore"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
--[[
|
||||
Bootloader for Operation System
|
||||
|
||||
Created by minjaesong on 16-09-21
|
||||
]]
|
||||
|
||||
-- check directories
|
||||
dirlist = {
|
||||
"/boot",
|
||||
"/bin", -- crucial binaries (e.g. cat, ls, sh(ell), cp, rm, mkdir), it's loosely an UNIX system
|
||||
"/usr",
|
||||
"/usr/bin", -- more utilities and binaries (e.g. less/more, nano)
|
||||
"/home", -- home directory for user
|
||||
"/home/bin" -- user-installed apps
|
||||
}
|
||||
-- just make them if they don't exist
|
||||
for _, dir in ipairs(dirlist) do
|
||||
fs.mkdir(dir)
|
||||
end
|
||||
|
||||
|
||||
if not _G.os then _G.os = {} end
|
||||
os.version = "0.0"
|
||||
os.EXIT_SUCCESS = 0
|
||||
os.workingDir = {"", "home"} -- index 1 must be ""!
|
||||
os.path = "home/bin/;/usr/bin/;/bin/" -- infamous $path
|
||||
|
||||
-- @param "path/of/arbitrary"
|
||||
-- @return /working/dir/path/of/arbitrary
|
||||
-- input path's trailing '/' is PRESERVED.
|
||||
os.expandPath = function(p)
|
||||
-- not applicable if the path starts with /
|
||||
if p:byte(1) == 47 or p:byte(1) == 92 then
|
||||
return p
|
||||
end
|
||||
|
||||
return table.concat(os.workingDir, "/").."/"..p
|
||||
end
|
||||
os.fullWorkPath = function()
|
||||
return table.concat(os.workingDir, "/")
|
||||
end
|
||||
os.defaultshell = "/bin/dsh.lua"
|
||||
os.clock = function() return machine.milliTime() / 1000 end -- uptime of the computer, in seconds
|
||||
|
||||
|
||||
|
||||
-- run default shell
|
||||
fs.dofile(os.defaultshell)
|
||||
|
||||
-- quit properly
|
||||
shell.status = shell.halt
|
||||
@@ -0,0 +1,12 @@
|
||||
NAME
|
||||
msh - the Moonshell
|
||||
|
||||
SYNOPSIS
|
||||
msh [file]
|
||||
|
||||
COPYRIGHT
|
||||
See copyright information for the game you are actually playing.
|
||||
|
||||
DESCRIPTION
|
||||
Moonshell is a Lua prompt that reads lua script from the user, or execute
|
||||
a file user had put as an argument.
|
||||
@@ -6,6 +6,8 @@
|
||||
Some codes were taken from OpenComputers, which is distributed under MIT
|
||||
--]]
|
||||
|
||||
_G._TERRARUM = true -- for multi-env programs
|
||||
|
||||
-- global functions
|
||||
_G.runscript = function(s, src, ...)
|
||||
if s:byte(1) == 27 then error("Bytecode execution is prohibited.") end -- untested; it's Lua 5.1 code and we're 5.2
|
||||
@@ -25,9 +27,6 @@ fs.dofile = function(p, ...)
|
||||
_G.runscript(s, "="..p, ...)
|
||||
end
|
||||
|
||||
-- EFI is expected to locate in "boot/efi"
|
||||
if fs.exists("boot/efi") then fs.dofile("boot/efi") end
|
||||
|
||||
computer.realTime = function() return 0 end
|
||||
|
||||
-- global variables
|
||||
@@ -77,7 +76,7 @@ local function checkArg(n, have, ...)
|
||||
end
|
||||
end
|
||||
if not check(...) then
|
||||
local msg = string.format("bad argument #%d (%s expected, got %s)",
|
||||
local msg = string.format("BAD argument #%d (%s expected, got %s)",
|
||||
n, table.concat({...}, " or "), have)
|
||||
error(msg, 3)
|
||||
end
|
||||
@@ -99,7 +98,7 @@ do
|
||||
local SHORT_STRING = 500 -- use native implementations for short strings
|
||||
|
||||
local string_find, string_lower, string_match, string_gmatch, string_gsub =
|
||||
string.find, string.lower, string.match, string.gmatch, string.gsub
|
||||
string.find, string.lower, string.match, string.gmatch, string.gsub
|
||||
|
||||
local match -- forward declaration
|
||||
|
||||
@@ -1002,33 +1001,34 @@ if not computer.prompt then computer.prompt = DC3.."> "..DC4 end
|
||||
if not computer.verbose then computer.verbose = true end -- print debug info
|
||||
if not computer.loadedCLayer then computer.loadedCLayer = {} end -- list of loaded compatibility layers
|
||||
-- if no bootloader is pre-defined via EFI, use default one
|
||||
if not computer.bootloader then computer.bootloader = "/boot/bootloader" end
|
||||
if not computer.bootloader then computer.bootloader = "/boot/efi" end
|
||||
if not computer.OEM then computer.OEM = "" end
|
||||
computer.totalMemory = _G.totalMemory
|
||||
if not computer.bellpitch then computer.bellpitch = 1000 end
|
||||
machine.totalMemory = _G.totalMemory
|
||||
if not computer.bellpitch then computer.bellpitch = 950 end
|
||||
local getMemory = function()
|
||||
collectgarbage()
|
||||
return collectgarbage("count") * 1024 - 6.5*1048576 + screenbuffersize
|
||||
end -- that magic number: how much basic system takes
|
||||
-- totalMemory: implemented in Kotlin class
|
||||
computer.freeMemory = function() return totalMemory() - getMemory() end
|
||||
machine.freeMemory = function() return totalMemory() - getMemory() end
|
||||
|
||||
-- load libraries that coded in Lua
|
||||
require("ROMLIB")
|
||||
|
||||
-- POST passed, initialise beeper
|
||||
speaker.enqueue(80, 1000) -- term.bell sometimes get squelched
|
||||
speaker.enqueue(80, computer.bellpitch) -- term.bell sometimes get squelched
|
||||
|
||||
-- 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__() goto quit end
|
||||
|
||||
-- load Lua prompt, if bios is not found
|
||||
print("Rom basic "..DC2.._VERSION..DC4)
|
||||
print("Copyright (C) 1994-2013 Lua.org, PUC-Rio")
|
||||
print("Ok")
|
||||
print("Lua is copyrighted (C) 1994-2013 Lua.org, PUC-Rio")
|
||||
print()
|
||||
|
||||
while not machine.isHalted() do
|
||||
term.setCursorBlink(true)
|
||||
|
||||
@@ -191,10 +191,11 @@ class BaseTerrarumComputer(peripheralSlots: Int) {
|
||||
fun update(gc: GameContainer, delta: Int) {
|
||||
input = gc.input
|
||||
|
||||
|
||||
if (currentExecutionThread.state == Thread.State.TERMINATED)
|
||||
unsetThreadRun()
|
||||
|
||||
|
||||
|
||||
// time the execution time of the thread
|
||||
if (threadRun) {
|
||||
threadTimer += delta
|
||||
@@ -205,9 +206,15 @@ class BaseTerrarumComputer(peripheralSlots: Int) {
|
||||
//currentExecutionThread.interrupt()
|
||||
unsetThreadRun()
|
||||
}
|
||||
|
||||
driveBeepQueueManager(delta)
|
||||
}
|
||||
|
||||
driveBeepQueueManager(delta)
|
||||
|
||||
|
||||
if (isHalted) {
|
||||
currentExecutionThread.interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(key: Int, c: Char) {
|
||||
@@ -240,8 +247,6 @@ class BaseTerrarumComputer(peripheralSlots: Int) {
|
||||
|
||||
class ThreadRunCommand : Runnable {
|
||||
|
||||
val DEBUGTHRE = true
|
||||
|
||||
val mode: Int
|
||||
val arg1: Any
|
||||
val arg2: String
|
||||
@@ -276,7 +281,7 @@ class BaseTerrarumComputer(peripheralSlots: Int) {
|
||||
}
|
||||
catch (e: LuaError) {
|
||||
lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}")
|
||||
if (DEBUGTHRE) e.printStackTrace(System.err)
|
||||
e.printStackTrace(System.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ import java.util.*
|
||||
* media/hda/ -> .../computers/<uuid for the hda>/
|
||||
*
|
||||
* Created by minjaesong on 16-09-17.
|
||||
*
|
||||
*
|
||||
* NOTE: Don't convert '\' to '/'! Rev-slash is used for escape character in sh, and we're sh-compatible!
|
||||
*/
|
||||
internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
|
||||
@@ -102,8 +105,6 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
// remove first '/' in path
|
||||
var path = luapath.checkIBM437()
|
||||
if (path.startsWith('/')) path = path.substring(1)
|
||||
// replace '\' with '/'
|
||||
path.replace('\\', '/')
|
||||
|
||||
if (path.startsWith("media/")) {
|
||||
val device = path.substring(6, 9)
|
||||
@@ -116,7 +117,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
}
|
||||
|
||||
fun combinePath(base: String, local: String) : String {
|
||||
return "$base$local".replace("//", "/").replace("\\\\", "\\")
|
||||
return "$base$local".replace("//", "/")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,11 +356,11 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
var pathSB = StringBuilder(path.checkIBM437())
|
||||
|
||||
// backward travel, drop chars until '/' has encountered
|
||||
while (!pathSB.endsWith('/') && !pathSB.endsWith('\\'))
|
||||
while (!pathSB.endsWith('/'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
// drop trailing '/'
|
||||
if (pathSB.endsWith('/') || pathSB.endsWith('\\'))
|
||||
if (pathSB.endsWith('/'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
return LuaValue.valueOf(pathSB.toString())
|
||||
|
||||
@@ -24,29 +24,17 @@ class WorldInformationProvider(globals: Globals) {
|
||||
companion object {
|
||||
fun getWorldTimeInLuaFormat() : LuaTable {
|
||||
val t = LuaTable()
|
||||
if (Terrarum.gameStarted) {
|
||||
val time = Terrarum.ingame.world.time
|
||||
val time = if (Terrarum.gameStarted) Terrarum.ingame.world.time else WorldTime()
|
||||
|
||||
// int Terrarum World Time format
|
||||
t["hour"] = time.hours
|
||||
t["min"] = time.minutes
|
||||
t["wday"] = time.dayOfWeek
|
||||
t["year"] = time.years
|
||||
t["yday"] = time.yearlyDays
|
||||
t["month"] = time.months
|
||||
t["sec"] = time.seconds
|
||||
t["day"] = time.days
|
||||
}
|
||||
else {
|
||||
t["hour"] = 0
|
||||
t["min"] = 0
|
||||
t["wday"] = 1
|
||||
t["year"] = 0
|
||||
t["yday"] = 1
|
||||
t["month"] = 1
|
||||
t["sec"] = 0
|
||||
t["day"] = 1
|
||||
}
|
||||
// int Terrarum World Time format
|
||||
t["hour"] = time.hours
|
||||
t["min"] = time.minutes
|
||||
t["wday"] = time.dayOfWeek
|
||||
t["year"] = time.years
|
||||
t["yday"] = time.yearlyDays
|
||||
t["month"] = time.months
|
||||
t["sec"] = time.seconds
|
||||
t["day"] = time.days
|
||||
|
||||
return t
|
||||
}
|
||||
@@ -55,52 +43,27 @@ class WorldInformationProvider(globals: Globals) {
|
||||
|
||||
/** evaluate single C date format */
|
||||
fun String.evalAsDate(): String {
|
||||
if (Terrarum.gameStarted) {
|
||||
val time = Terrarum.ingame.world.time
|
||||
return when (this) {
|
||||
"%a" -> time.getDayNameShort()
|
||||
"%A" -> time.getDayNameFull()
|
||||
"%b" -> time.getMonthNameShort()
|
||||
"%B" -> time.getMonthNameFull()
|
||||
"%c" -> "%x".evalAsDate() + " " + "%X".evalAsDate()
|
||||
"%d" -> time.days.toString()
|
||||
"%H" -> time.hours.toString()
|
||||
"%I" -> throw IllegalArgumentException("%I: AM/PM concept does not exists.")
|
||||
"%M" -> time.minutes.toString()
|
||||
"%m" -> time.months.toString()
|
||||
"%p" -> throw IllegalArgumentException("%p: AM/PM concept does not exists.")
|
||||
"%S" -> time.seconds.toString()
|
||||
"%w" -> time.dayOfWeek.toString()
|
||||
"%x" -> "${String.format("%02d", time.years)}-${String.format("%02d", time.months)}-${String.format("%02d", time.days)}"
|
||||
"%X" -> "${String.format("%02d", time.hours)}:${String.format("%02d", time.minutes)}:${String.format("%02d", time.seconds)}"
|
||||
"%Y" -> time.years.toString()
|
||||
"%y" -> time.years.mod(100).toString()
|
||||
"%%" -> "%"
|
||||
else -> throw IllegalArgumentException("Unknown format string: $this")
|
||||
}
|
||||
}
|
||||
else {
|
||||
return when (this) {
|
||||
"%a" -> "---"
|
||||
"%A" -> "------"
|
||||
"%b" -> "----"
|
||||
"%B" -> "--------"
|
||||
"%c" -> "%x".evalAsDate() + " " + "%X".evalAsDate()
|
||||
"%d" -> "0"
|
||||
"%H" -> "0"
|
||||
"%I" -> throw IllegalArgumentException("%I: AM/PM concept does not exists.")
|
||||
"%M" -> "0"
|
||||
"%m" -> "0"
|
||||
"%p" -> throw IllegalArgumentException("%p: AM/PM concept does not exists.")
|
||||
"%S" -> "0"
|
||||
"%w" -> "0"
|
||||
"%x" -> "00-00-00"
|
||||
"%X" -> "00:00:00"
|
||||
"%Y" -> "0"
|
||||
"%y" -> "00"
|
||||
"%%" -> "%"
|
||||
else -> throw IllegalArgumentException("Unknown format string: $this")
|
||||
}
|
||||
val time = if (Terrarum.gameStarted) Terrarum.ingame.world.time else WorldTime()
|
||||
return when (this) {
|
||||
"%a" -> time.getDayNameShort()
|
||||
"%A" -> time.getDayNameFull()
|
||||
"%b" -> time.getMonthNameShort()
|
||||
"%B" -> time.getMonthNameFull()
|
||||
"%c" -> "%x".evalAsDate() + " " + "%X".evalAsDate()
|
||||
"%d" -> time.days.toString()
|
||||
"%H" -> time.hours.toString()
|
||||
"%I" -> throw IllegalArgumentException("%I: AM/PM concept does not exists.")
|
||||
"%M" -> time.minutes.toString()
|
||||
"%m" -> time.months.toString()
|
||||
"%p" -> throw IllegalArgumentException("%p: AM/PM concept does not exists.")
|
||||
"%S" -> time.seconds.toString()
|
||||
"%w" -> time.dayOfWeek.toString()
|
||||
"%x" -> "${String.format("%02d", time.years)}-${String.format("%02d", time.months)}-${String.format("%02d", time.days)}"
|
||||
"%X" -> "${String.format("%02d", time.hours)}:${String.format("%02d", time.minutes)}:${String.format("%02d", time.seconds)}"
|
||||
"%Y" -> time.years.toString()
|
||||
"%y" -> time.years.mod(100).toString()
|
||||
"%%" -> "%"
|
||||
else -> throw IllegalArgumentException("Unknown format string: $this")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user