OS library implementation

Former-commit-id: b4f7f283080ead5e92c273015bfe2559cbe99e47
Former-commit-id: adaa0af80068a916e534f677f6e5ffe1f3072241
This commit is contained in:
Song Minjae
2016-09-29 00:21:42 +09:00
parent db8e46e5c2
commit ae114c53e0
32 changed files with 551 additions and 507 deletions

View File

@@ -93,6 +93,8 @@ constructor() : BasicGameState() {
@Throws(SlickException::class)
override fun init(gameContainer: GameContainer, stateBasedGame: StateBasedGame) {
// state init code. Executed before the game goes into any "state" in states in StateBasedGame.java
Terrarum.gameStarted = true
}
override fun enter(gc: GameContainer, sbg: StateBasedGame) {

View File

@@ -21,7 +21,8 @@ class StateVTTest : BasicGameState() {
// HiRes: 100x64, LoRes: 80x25
val computerInside = BaseTerrarumComputer()
val vt = SimpleTextTerminal(SimpleTextTerminal.BLUE_NOVELTY, 80, 25, computerInside, colour = false, hires = false)
val vt = SimpleTextTerminal(SimpleTextTerminal.WHITE, 80, 25,
computerInside, colour = false, hires = false)
val vtUI = Image(vt.displayW, vt.displayH)

View File

@@ -140,6 +140,8 @@ constructor(gamename: String) : StateBasedGame(gamename) {
var VSYNC = true
val VSYNC_TRIGGER_THRESHOLD = 56
var gameStarted = false
lateinit var ingame: StateInGame
lateinit var gameConfig: GameConfig

View File

@@ -13,7 +13,7 @@ class SetTime : ConsoleCommand {
Terrarum.ingame.world.time.setTime(timeToSet)
Echo().execute("Set time to ${Terrarum.ingame.world.time.elapsedSeconds()} " +
Echo().execute("Set time to ${Terrarum.ingame.world.time.elapsedSeconds} " +
"(${Terrarum.ingame.world.time.hours}h${formatMin(Terrarum.ingame.world.time.minutes)})")
}
else {

View File

@@ -1,50 +1,93 @@
package net.torvald.terrarum.gameworld
/**
* The World Calendar implementation of Dwarven Calendar (we're talking about DF!)
*
* Please see:
* https://en.wikipedia.org/wiki/World_Calendar
* http://dwarffortresswiki.org/index.php/DF2014:Calendar
*
* Normal format for day is
* Tysdag 12th Granite
*
* And there is no AM/PM concept, 22-hour clock is forced.
*
* Created by minjaesong on 16-01-24.
*/
class WorldTime {
internal var seconds: Int
internal var minutes: Int
internal var hours: Int
internal var seconds: Int // 0 - 59
internal var minutes: Int // 0 - 59
internal var hours: Int // 0 - 21
// days on the year
internal var yearlyDays: Int //NOT a calendar day
internal var days: Int
internal var months: Int
internal var years: Int
internal var days: Int // 1 - 31
internal var months: Int // 1 - 12
internal var years: Int // 1+
internal var dayOfWeek: Int //0: Mondag-The first day of weekday
internal var dayOfWeek: Int //0: Mondag-The first day of weekday (0 - 7)
internal var timeDelta = 1
@Transient private var realMillisec: Int
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
"Mondag", "Tysdag", "Midtedag" //From Islenska Miðvikudagur
"Mondag", "Tysdag", "Midvikdag" //From Islenska Miðvikudagur
, "Torsdag", "Fredag", "Laurdag", "Sundag", "Verdag" //From Norsk word 'verd'
)
val DAY_NAMES_SHORT = arrayOf("Mon", "Tys", "Mid", "Tor", "Fre", "Lau", "Sun", "Ver")
val MONTH_NAMES = arrayOf(
"Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite",
"Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone"
)
val MONTH_NAMES_SHORT = arrayOf("Opal", "Obsi", "Gran", "Slat", "Fels", "Hema",
"Mala", "Gale", "Lime", "Sand", "Timb", "Moon")
@Transient val REAL_SEC_IN_MILLI = 1000
companion object {
/** Each day is 22-hour long */
val DAY_LENGTH = 79200 //must be the multiple of 3600
val HOUR_SEC: Int = 3600
val MINUTE_SEC: Int = 60
val HOUR_MIN: Int = 60
val GAME_MIN_TO_REAL_SEC: Float = 60f
fun parseTime(s: String): Int =
if (s.length >= 4) {
s.toLowerCase().substringBefore('h').toInt() * WorldTime.HOUR_SEC +
s.toLowerCase().substringAfter('h').toInt() * WorldTime.MINUTE_SEC
}
else if (s.endsWith("h", true)) {
s.toLowerCase().substring(0, s.length - 1).toInt() * WorldTime.HOUR_SEC
}
else {
s.toInt()
}
}
init {
seconds = 0
minutes = 30
hours = 8
yearlyDays = 1
yearlyDays = 73
days = 12
months = 3
years = 125
dayOfWeek = 0
dayOfWeek = 1 // Tysdag
realMillisec = 0
}
fun update(delta: Int) {
val oldsec = seconds
//time
realMillisec += delta * timeDelta
seconds = Math.round(GAME_MIN_TO_REAL_SEC.toFloat() / REAL_SEC_IN_MILLI.toFloat() * realMillisec.toFloat())
val newsec = Math.round(GAME_MIN_TO_REAL_SEC.toFloat() / REAL_SEC_IN_MILLI.toFloat() * realMillisec.toFloat())
seconds = newsec
if (realMillisec >= REAL_SEC_IN_MILLI)
realMillisec -= REAL_SEC_IN_MILLI
@@ -57,22 +100,23 @@ class WorldTime {
* 0 == 6 AM
* @return
*/
fun elapsedSeconds(): Int {
return (HOUR_SEC * hours + MINUTE_SEC * minutes + seconds) % DAY_LENGTH
}
val elapsedSeconds: Int
get() = (HOUR_SEC * hours + MINUTE_SEC * minutes + seconds) % DAY_LENGTH
val isLeapYear: Boolean
get() = years % 4 == 0 && years % 100 != 0 || years % 400 == 0
/** Sets time of this day. */
fun setTime(t: Int) {
days += t / DAY_LENGTH
hours = t / HOUR_SEC
minutes = (t - HOUR_SEC * hours) / MINUTE_SEC
seconds = t - minutes * MINUTE_SEC
yearlyDays += t / DAY_LENGTH
}
fun addTime(t: Int) {
setTime(elapsedSeconds() + t)
setTime(elapsedSeconds + t)
}
fun setTimeDelta(d: Int) {
@@ -125,41 +169,14 @@ class WorldTime {
if (months > 12) {
months = 1
years++
yearlyDays = 1
}
}
fun getFormattedTime(): String {
fun formatMin(min: Int): String {
return if (min < 10) "0${min.toString()}" else min.toString()
}
fun getFormattedTime() = "${String.format("%02d", hours)}h${String.format("%02d", minutes)}"
return "${hours}h${formatMin(minutes)}"
}
fun getDayNameFull(): String = DAY_NAMES[dayOfWeek]
fun getDayNameShort(): String = DAY_NAMES_SHORT[dayOfWeek]
companion object {
/**
* 22h
*/
val DAY_LENGTH = 79200 //must be the multiple of 3600
val HOUR_SEC: Int = 3600
val MINUTE_SEC: Int = 60
val HOUR_MIN: Int = 60
val GAME_MIN_TO_REAL_SEC: Float = 60f
fun parseTime(s: String): Int =
if (s.length >= 4) {
s.toLowerCase().substringBefore('h').toInt() * WorldTime.HOUR_SEC +
s.toLowerCase().substringAfter('h').toInt() * WorldTime.MINUTE_SEC
}
else if (s.endsWith("h", true)) {
s.toLowerCase().substring(0, s.length - 1).toInt() * WorldTime.HOUR_SEC
}
else {
s.toInt()
}
}
fun getDayNameFull() = DAY_NAMES[dayOfWeek]
fun getDayNameShort() = DAY_NAMES_SHORT[dayOfWeek]
fun getMonthNameFull() = MONTH_NAMES[months - 1]
fun getMonthNameShort() = MONTH_NAMES_SHORT[months - 1]
}

View File

@@ -131,7 +131,7 @@ class BasicDebugInfoWindow : UICanvas {
printLineColumn(g, 2, 1, "VSync $ccG" + Terrarum.appgc.isVSyncRequested)
printLineColumn(g, 2, 2, "Env colour temp $ccG" + MapDrawer.colTemp)
printLineColumn(g, 2, 5, "Time $ccG${Terrarum.ingame.world.time.elapsedSeconds()}" +
printLineColumn(g, 2, 5, "Time $ccG${Terrarum.ingame.world.time.elapsedSeconds}" +
" (${Terrarum.ingame.world.time.getFormattedTime()})")
printLineColumn(g, 2, 6, "Mass $ccG${player.mass}")

View File

@@ -6,10 +6,32 @@
Some codes were taken from OpenComputers, which is distributed under MIT
--]]
-- global functions
_G.runscript = function(s, src, ...)
if s:byte(1) == 27 then error("Bytecode execution is prohibited.") end
local code, reason = load(s, src)
if code then
xpcall(code(...), eprint)
else
print(DLE..tostring(reason)) -- it catches syntax errors
end
end
fs.dofile = function(p, ...)
local f = fs.open(p, "r")
local s = f.readAll()
_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
_G._VERSION = "Luaj-jse 3.0.1 (Lua 5.2.3)"
_G._VERSION = _VERSION.." (Lua 5.2.3)"
_G.EMDASH = string.char(0xC4)
_G.UNCHECKED = string.char(0x9C) -- box unchecked
_G.CHECKED = string.char(0x9D) -- box checked
@@ -969,18 +991,6 @@ sandbox._G = sandbox
-- path for any ingame libraries
package.path = "/net/torvald/terrarum/virtualcomputer/assets/lua/?.lua;" .. package.path
-- global functions
_G.runscript = function(s, src, ...)
if s:byte(1) == 27 then error("Bytecode execution is prohibited.") end
local code, reason = load(s, src)
if code then
xpcall(code(...), eprint)
else
print(DLE..tostring(reason)) -- it catches syntax errors
end
end
_G.__scanMode__ = "UNINIT" -- part of inputstream implementation
local screenbufferdim = term.width() * term.height()
@@ -989,14 +999,15 @@ if term.isCol() then screencolours = 8
elseif term.isTeletype() then screencolours = 1 end
local screenbuffersize = screenbufferdim * screencolours / 8
computer.prompt = DC3.."> "..DC4
computer.verbose = true -- print debug info
computer.loadedCLayer = {} -- list of loaded compatibility layers
computer.bootloader = "/boot/efi"
computer.OEM = ""
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.OEM then computer.OEM = "" end
computer.beep = emittone
computer.totalMemory = _G.totalMemory
computer.bellpitch = 1000
if not computer.bellpitch then computer.bellpitch = 1000 end
local getMemory = function()
collectgarbage()
return collectgarbage("count") * 1024 - 6.5*1048576 + screenbuffersize
@@ -1021,7 +1032,7 @@ print("Rom basic "..DC2.._VERSION..DC4)
print("Copyright (C) 1994-2013 Lua.org, PUC-Rio")
print("Ok")
while not native.isHalted() do
while not machine.isHalted() do
term.setCursorBlink(true)
io.write(computer.prompt)
local s = __scanforline__()
@@ -1039,5 +1050,5 @@ while not native.isHalted() do
end
::quit::
native.closeInputString()
machine.closeInputString()
return

View File

@@ -8,11 +8,11 @@
_G.io = {}
fs.dofile = function(p, ...)
--[[fs.dofile = function(p, ...)
local f = fs.open(p, "r")
local s = f.readAll()
_G.runscript(s, "="..p, ...)
end
end]] -- implementation moved to BOOT.lua
_G.loadstring = _G.load
@@ -46,12 +46,12 @@ override fun keyPressed(key: Int, c: Char) {
and THIS exact part will close the input for this function.
]]
_G.__scanforline__ = function(echo) -- pass '1' to not echo; pass nothing to echo
native.closeInputString()
native.openInput(echo or 0)
machine.closeInputString()
machine.openInput(echo or 0)
_G.__scanMode__ = "line"
local s
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
s = native.getLastStreamInput()
s = machine.getLastStreamInput()
until s
-- input is closed when RETURN is hit. See above comments.
return s
@@ -59,12 +59,12 @@ end
-- use Keys API to identify the keycode
--[[_G.__scanforkey__ = function(echo) -- pass '1' to not echo; pass nothing to echo
native.closeInputString()
native.openInput(echo or 0)
machine.closeInputString()
machine.openInput(echo or 0)
_G.__scanMode__ = "a_key"
local key
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
key = native.getLastKeyPress()
key = machine.getLastKeyPress()
until key
-- input is closed when any key is hit. See above comments.
return key

View File

@@ -1,20 +1,18 @@
package net.torvald.terrarum.virtualcomputer.computer
import com.jme3.math.FastMath
import li.cil.repack.org.luaj.vm2.Globals
import li.cil.repack.org.luaj.vm2.LuaError
import li.cil.repack.org.luaj.vm2.LuaTable
import li.cil.repack.org.luaj.vm2.LuaValue
import li.cil.repack.org.luaj.vm2.lib.TwoArgFunction
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
import li.cil.repack.org.luaj.vm2.lib.jse.JsePlatform
import org.luaj.vm2.Globals
import org.luaj.vm2.LuaError
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.TwoArgFunction
import org.luaj.vm2.lib.ZeroArgFunction
import org.luaj.vm2.lib.jse.JsePlatform
import net.torvald.terrarum.KVHashMap
import net.torvald.terrarum.gameactors.ActorValue
import net.torvald.terrarum.gameactors.roundInt
import net.torvald.terrarum.virtualcomputer.luaapi.*
import net.torvald.terrarum.virtualcomputer.terminal.*
import net.torvald.terrarum.virtualcomputer.worldobject.ComputerPartsCodex
import net.torvald.terrarum.virtualcomputer.worldobject.FixtureComputerBase
import org.lwjgl.BufferUtils
import org.lwjgl.openal.AL
import org.lwjgl.openal.AL10
@@ -73,6 +71,12 @@ class BaseTerrarumComputer() {
lateinit var term: Teletype
private set
// os-related functions. These are called "machine" library-wise.
private val startupTimestamp: Long = System.currentTimeMillis()
/** Time elapsed since the power is on. */
val milliTime: Int
get() = (System.currentTimeMillis() - startupTimestamp).toInt()
init {
computerValue["memslot0"] = 4864 // -1 indicates mem slot is empty
computerValue["memslot1"] = -1 // put index of item here
@@ -96,7 +100,6 @@ class BaseTerrarumComputer() {
// boot device
computerValue["boot"] = computerValue.getAsString("hda")!!
}
fun attachTerminal(term: Teletype) {
@@ -125,6 +128,7 @@ class BaseTerrarumComputer() {
Input(luaJ_globals, this)
Http(luaJ_globals, this)
PcSpeakerDriver(luaJ_globals, this)
WorldInformationProvider(luaJ_globals)
// secure the sandbox
@@ -141,6 +145,7 @@ class BaseTerrarumComputer() {
luaJ_globals["totalMemory"] = LuaFunGetTotalMem(this)
luaJ_globals["computer"] = LuaTable()
// rest of the "computer" APIs should be implemented in BOOT.lua
if (DEBUG) luaJ_globals["emittone"] = ComputerEmitTone(this)
}
@@ -167,8 +172,6 @@ class BaseTerrarumComputer() {
}
driveBeepQueueManager(delta)
}
fun keyPressed(key: Int, c: Char) {
@@ -267,19 +270,19 @@ class BaseTerrarumComputer() {
private var beepQueueFired = false
private fun driveBeepQueueManager(delta: Int) {
// start beep queue
// start emitTone queue
if (beepQueue.size > 0 && beepCursor == -1) {
beepCursor = 0
}
// continue beep queue
// continue emitTone queue
if (beepCursor >= 0 && beepQueueLineExecTimer >= beepQueueGetLenOfPtn(beepCursor)) {
beepQueueLineExecTimer -= beepQueueGetLenOfPtn(beepCursor)
beepCursor += 1
beepQueueFired = false
}
// complete beep queue
// complete emitTone queue
if (beepCursor >= beepQueue.size) {
clearBeepQueue()
if (DEBUG) println("!! Beep queue clear")

View File

@@ -1,9 +1,9 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.*
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
import li.cil.repack.org.luaj.vm2.lib.TwoArgFunction
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
import org.luaj.vm2.*
import org.luaj.vm2.lib.OneArgFunction
import org.luaj.vm2.lib.TwoArgFunction
import org.luaj.vm2.lib.ZeroArgFunction
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
import net.torvald.terrarum.virtualcomputer.luaapi.Term.Companion.checkIBM437

View File

@@ -1,36 +1,35 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.Globals
import li.cil.repack.org.luaj.vm2.LuaFunction
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 org.luaj.vm2.lib.OneArgFunction
import 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
import org.luaj.vm2.*
/**
* Provide Lua an access to computer object that is in Java
*
* The "machine" refers to the computer fixture itself in the game world.
*
* 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["machine"] = LuaTable()
globals["machine"]["println"] = PrintLn()
globals["machine"]["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)
globals["machine"]["closeInputString"] = NativeCloseInputString(computer.term)
globals["machine"]["closeInputKey"] = NativeCloseInputKey(computer.term)
globals["machine"]["openInput"] = NativeOpenInput(computer.term)
globals["machine"]["getLastStreamInput"] = NativeGetLastStreamInput(computer.term)
globals["machine"]["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["machine"]["milliTime"] = NativeGetMilliTime(computer)
globals["machine"]["sleep"] = NativeBusySleep(computer)
globals["__haltsystemexplicit__"] = HaltComputer(computer)
}
@@ -98,4 +97,21 @@ internal class HostAccessProvider(globals: Globals, computer: BaseTerrarumComput
return LuaValue.NONE
}
}
/** Time elapsed since the power is on. */
class NativeGetMilliTime(val computer: BaseTerrarumComputer) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(computer.milliTime)
}
}
class NativeBusySleep(val computer: BaseTerrarumComputer) : OneArgFunction() {
override fun call(mills: LuaValue): LuaValue {
val starttime = computer.milliTime
val sleeptime = mills.checkint()
if (sleeptime > 1000) throw LuaError("Cannot busy-sleep more than a second.")
while (computer.milliTime - starttime < sleeptime) { }
return LuaValue.NONE
}
}
}

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.Globals
import org.luaj.vm2.Globals
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
/**

View File

@@ -1,9 +1,9 @@
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 org.luaj.vm2.Globals
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.OneArgFunction
import net.torvald.terrarum.gamecontroller.Key
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer

View File

@@ -1,10 +1,10 @@
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.TwoArgFunction
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
import org.luaj.vm2.Globals
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.TwoArgFunction
import org.luaj.vm2.lib.ZeroArgFunction
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
/**

View File

@@ -1,8 +1,8 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.Globals
import li.cil.repack.org.luaj.vm2.LuaValue
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
import org.luaj.vm2.Globals
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.OneArgFunction
import net.torvald.terrarum.gameworld.toUint
import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.digest.DigestUtils

View File

@@ -1,14 +1,14 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.*
import li.cil.repack.org.luaj.vm2.lib.*
import org.luaj.vm2.*
import org.luaj.vm2.lib.*
import net.torvald.terrarum.virtualcomputer.terminal.Teletype
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import java.nio.charset.Charset
/**
* Controls terminal as if it was a monitor
* (not sending control sequences but just drives it, as if it was not a terminal @ 9600 baud)
* (not sending control sequences but just drives it directly)
*
* Created by minjaesong on 16-09-12.
*/

View File

@@ -0,0 +1,131 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import org.luaj.vm2.Globals
import org.luaj.vm2.LuaFunction
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameworld.WorldTime
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.ZeroArgFunction
import java.util.*
/**
* Implementation of lua's os.date, to return world info of the game world.
*
* Created by minjaesong on 16-09-28.
*/
class WorldInformationProvider(globals: Globals) {
init {
globals["os"]["time"] = LuaValue.NIL // history is LONG! Our 32-bit Lua's epoch is destined to break down...
globals["os"]["date"] = OsDateImpl()
}
companion object {
fun getWorldTimeInLuaFormat() : LuaTable {
val t = LuaTable()
if (Terrarum.gameStarted) {
val time = Terrarum.ingame.world.time
// 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
}
return t
}
val defaultDateFormat = "%a %d %B %Y %X"
/** 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 acceptedDateFormats = arrayOf("%a", "%A", "%b", "%B", "%c", "%d", "%H", "%I", "%M", "%m", "%p", "%S", "%w", "%x", "%X", "%Y", "%y", "%%" )
}
/**
* Changes: cannot get a representation of arbitrary time.
*/
class OsDateImpl() : LuaFunction() {
// no args
override fun call(): LuaValue {
return call(defaultDateFormat)
}
override fun call(format: LuaValue): LuaValue {
var arg = format.checkjstring()
acceptedDateFormats.forEach {
if (arg.contains(it))
arg = arg.replace(it, it.evalAsDate(), ignoreCase = false)
}
return LuaValue.valueOf(arg)
}
}
}

View File

@@ -1,194 +0,0 @@
/*
* $Id: LuaConsole.java 79 2012-01-08 11:08:32Z andre@naef.com $
* See LICENSE.txt for license terms.
*/
package net.torvald.terrarum.virtualcomputer.terminal;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import li.cil.repack.com.naef.jnlua.LuaException;
import li.cil.repack.com.naef.jnlua.LuaRuntimeException;
import li.cil.repack.com.naef.jnlua.LuaState;
/**
* A simple Lua console.
*
* <p>
* The console collects input until a line with the sole content of the word
* <i>go</i> is encountered. At that point, the collected input is run as a Lua
* chunk. If the Lua chunk loads and runs successfully, the console displays the
* returned values of the chunk as well as the execution time based on a
* <code>System.nanoTime()</code> measurement. Otherwise, the console shows the
* error that has occurred.
* </p>
*
* <p>
* Expressions can be printed by prepending <i>=</i> to the expression at the
* beginning of a chunk. The console translates <i>=</i> into
* <code>return</code> followed by a space and executes the chunk immediately.
* No separate <i>go</i> is required. Therefore, expressions printed this way
* must be entered on a single line.
* </p>
*/
public class LuaConsole {
// -- 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);
}
// -- State
private LuaState luaState;
// -- Construction
/**
* Creates a new instance.
*/
public LuaConsole() {
this(EMPTY_ARGS);
}
/**
* 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 LuaConsole(String[] args) {
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
System.out.println(String.format("JNLua %s Console using Lua %s.",
LuaState.VERSION, LuaState.LUA_VERSION));
System.out.print("Type 'go' on an empty line to evaluate a chunk. ");
System.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) {
System.out.print("IO error: ");
System.out.print(e.getMessage());
System.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) {
System.out.print(", ");
}
switch (luaState.type(i)) {
case BOOLEAN:
System.out.print(Boolean.valueOf(luaState.toBoolean(i)));
break;
case NUMBER:
case STRING:
System.out.print(luaState.toString(i));
break;
default:
System.out.print(luaState.typeName(i));
}
}
System.out.print("\t#msec=");
System.out.print(String.format("%.3f", (stop - start) / 1000000.0));
System.out.println();
} catch (LuaRuntimeException e) {
e.printLuaStackTrace();
} catch (LuaException e) {
System.err.println(e.getMessage());
}
}
}

View File

@@ -223,7 +223,7 @@ open class SimpleTextTerminal(
}
else {
when (c) {
ASCII_BEL -> beep()
ASCII_BEL -> bell(".")
ASCII_BS -> { cursorX -= 1; wrap() }
ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE }
ASCII_LF -> newLine()
@@ -318,13 +318,13 @@ open class SimpleTextTerminal(
* @param duration: milliseconds
* @param freg: Frequency (float)
*/
override fun beep(duration: Int, freq: Float) {
override fun emitTone(duration: Int, freq: Float) {
// println("!! Beep playing row $beepCursor, d ${Math.min(duration, maxDuration)} f $freq")
host.clearBeepQueue()
host.enqueueBeep(duration, freq)
}
/** for "beep code" on modern BIOS. */
/** for "emitTone code" on modern BIOS. */
override fun bell(pattern: String) {
host.clearBeepQueue()
@@ -336,7 +336,7 @@ open class SimpleTextTerminal(
for (c in pattern) {
when (c) {
'.' -> { host.enqueueBeep(50, freq); host.enqueueBeep(50, 0f) }
'.' -> { host.enqueueBeep(80, freq); host.enqueueBeep(50, 0f) }
'-' -> { host.enqueueBeep(200, freq); host.enqueueBeep(50, 0f) }
'=' -> { host.enqueueBeep(500, freq); host.enqueueBeep(50, 0f) }
' ' -> { host.enqueueBeep(200, 0f) }

View File

@@ -61,13 +61,8 @@ interface Terminal : Teletype {
* @param duration: milliseconds
* @param freg: Frequency (float)
*/
fun beep(duration: Int = 80, freq: Float = 1000f)
/**
* Pattern: - .
* . 80 ms
* - 200 ms
* ( ) 80 ms
*/
fun emitTone(duration: Int, freq: Float)
override fun bell(pattern: String)
/** Requires keyPressed() event to be processed.
*

View File

@@ -76,7 +76,7 @@ object WeatherMixer {
fun render(g: Graphics) {
// we will not care for nextSkybox for now
val timeNow = Terrarum.ingame.world.time.elapsedSeconds()
val timeNow = Terrarum.ingame.world.time.elapsedSeconds
val skyboxColourMap = currentWeather.skyboxGradColourMap
val lightColourMap = currentWeather.globalLightColourMap