diff --git a/src/apis/computer.lua b/src/apis/computer.lua index fdcb8fb..27b2d64 100644 --- a/src/apis/computer.lua +++ b/src/apis/computer.lua @@ -48,7 +48,6 @@ function env.computer.pushSignal(name, ...) table.insert(machine.signals, {name, ... }) end function env.computer.tmpAddress() - --STUB cprint("computer.tmpAddress") return tmpaddr end @@ -74,7 +73,6 @@ function env.computer.energy() return math.huge end function env.computer.maxEnergy() - --STUB, move to a config cprint("computer.maxEnergy") - return 500 + return config.get("power.buffer.computer",500) end diff --git a/src/apis/system.lua b/src/apis/system.lua index 7691409..a53ec54 100644 --- a/src/apis/system.lua +++ b/src/apis/system.lua @@ -3,12 +3,10 @@ local env = ... env.system = {} function env.system.allowBytecode() - --STUB, move to a config cprint("system.allowBytecode") - return false + return config.get("computer.lua.allowBytecode",false) end function env.system.timeout() - --STUB, move to a config cprint("system.timeout") - return math.huge + return config.get("computer.timeout",5) end diff --git a/src/component/screen_sdl2.lua b/src/component/screen_sdl2.lua index a2f663c..825d475 100644 --- a/src/component/screen_sdl2.lua +++ b/src/component/screen_sdl2.lua @@ -32,6 +32,49 @@ for y = 1,height do end end +local buttons = {[SDL.BUTTON_LEFT] = 0, [SDL.BUTTON_RIGHT] = 1} +local moved, bttndown, lx, ly = false +function elsa.mousebuttondown(event) + local mbevent = ffi.cast("SDL_MouseButtonEvent", event) + if buttons[mbevent.button] then + if not bttndown then + lx, ly = math.floor(mbevent.x/8)+1,math.floor(mbevent.y/16)+1 + table.insert(machine.signals,{"touch",address,lx,ly,buttons[mbevent.button]}) + end + bttndown = buttons[mbevent.button] + end +end + +function elsa.mousebuttonup(event) + local mbevent = ffi.cast("SDL_MouseButtonEvent", event) + if bttndown and buttons[mbevent.button] then + if moved then + moved = false + table.insert(machine.signals,{"drop",address,lx,ly,buttons[mbevent.button]}) + end + bttndown = nil + end +end + +function elsa.mousemotion(event) + local mmevent = ffi.cast("SDL_MouseMotionEvent", event) + if bttndown then + local nx, ny = math.floor(mmevent.x/8)+1,math.floor(mmevent.y/16)+1 + if nx ~= lx or ny ~= ly then + moved = true + table.insert(machine.signals,{"drag",address,nx,ny,bttndown}) + lx, ly = nx, ny + end + end +end + +function elsa.mousewheel(event) + local mwevent = ffi.cast("SDL_MouseWheelEvent", event) + local x,y = ffi.new("int[1]"),ffi.new("int[1]") + SDL.getMouseState(ffi.cast("int*",x), ffi.cast("int*",y)) + table.insert(machine.signals,{"scroll",address,math.floor(x[0]/8)+1,math.floor(y[0]/16)+1,mwevent.y}) +end + local window = SDL.createWindow("OCEmu - screen@" .. address, SDL.WINDOWPOS_CENTERED, SDL.WINDOWPOS_CENTERED, width*8, height*16, SDL.WINDOW_SHOWN) if window == ffi.C.NULL then error(SDL.getError()) diff --git a/src/config.lua b/src/config.lua new file mode 100644 index 0000000..a4e9482 --- /dev/null +++ b/src/config.lua @@ -0,0 +1,154 @@ +-- Configuration api for OCEmu +local _config +local comments = { +[1]="OCEmu configuration. Designed to mimic HOCON syntax, but is not exactly HOCON syntax.", +["computer"]="Computer related settings, concerns server performance and security.", +["computer.lua"]="Settings specific to the Lua architecture.", +["computer.lua.allowBytecode"]="Whether to allow loading precompiled bytecode via Lua's `load` function, or related functions (`loadfile`, `dofile`). Enable this only if you absolutely trust all users on your server and all Lua code you run. This can be a MASSIVE SECURITY RISK, since precompiled code can easily be used for exploits, running arbitrary code on the real server! I cannot stress this enough: only enable this is you know what you're doing.", +["computer.timeout"]="The time in seconds a program may run without yielding before it is forcibly aborted. This is used to avoid stupidly written or malicious programs blocking other computers by locking down the executor threads. Note that changing this won't have any effect on computers that are already running - they'll have to be rebooted for this to take effect.", +} + +local function writeComment(text,file,size) + file:write(string.rep(" ",size) .. "--") + local line = "" + for word in text:gmatch("[%S]+") do + if #line + #word + 1 > 78 then + line = "" + file:write("\n" .. string.rep(" ",size) .. "--") + end + file:write((line == "" and "" or " ") .. word) + line = line .. (line == "" and "" or " ") .. word + end + file:write("\n") +end + +local serialize +function serialize(tbl,key,path,file,size) + file:write(string.rep(" ",size-2) .. key .. " {\n") + local keys = {} + for k,v in pairs(tbl) do + keys[#keys+1] = k + end + table.sort(keys) + for i = 1,#keys do + local k = keys[i] + local v = tbl[k] + local spath = path .. (path == "" and "" or ".") .. k + file:write("\n") + if comments[spath] then + writeComment(comments[spath],file,size) + end + if type(v) == "table" then + local list = true + for k,l in pairs(v) do + if type(l) ~= "number" then + list = false + break + end + end + if list then + file:write(string.rep(" ",size) .. k .. "=[\n") + for i = 1,#v do + file:write(string.rep(" ",size+2) .. v[i] .. (i < #v and "," or "") .. "\n") + end + file:write(string.rep(" ",size) .. "]\n") + else + serialize(v,k,spath,file,size+2) + end + elseif type(v) == "string" then + file:write(string.rep(" ",size) .. k .. "=" .. string.format("%q",v) .. "\n") + else + file:write(string.rep(" ",size) .. k .. "=" .. tostring(v) .. "\n") + end + end + file:write(string.rep(" ",size-2) .. "}\n") +end + +config = {} + +function config.load() + local file, err = io.open(elsa.filesystem.getSaveDirectory() .. "/ocemu.cfg","rb") + if file == nil then + print("Problem opening configuration, using default: " .. err) + _config = {} + return + end + local rawdata = file:read("*a") + file:close() + rawdata = rawdata:gsub("\r\n","\n"):gsub("\r","\n") + rawdata = (rawdata .. "\n"):reverse():match("\n+(.*)"):reverse() + local data = "" + for line in (rawdata .. "\n"):gmatch("(.-)\n") do + if line:sub(-2) == " {" then + line = line:sub(1,-3) .. "={" + end + if line:sub(-1) == "[" then + line = line:sub(1,-2) .. "{" + end + if line:sub(-1) == "]" then + line = line:sub(1,-2) .. "}" + end + if line ~= "" and line:sub(-1) ~= "{" and line:sub(-1) ~= "[" and line:sub(-1) ~= "," then + line = line .. "," + end + if line == "ocemu={" then + line = "return {" + end + data = data .. line .. "\n" + end + data = data:sub(1,-3) + local fn, err = load(data,"=ocemu.cfg","t",{}) + if not fn then + error("Problem loading configuration: " .. err,0) + end + local ok, cfg = pcall(fn) + if not ok then + error("Problem loading configuration: " .. cfg,0) + end + _config = cfg +end + +function config.save() + local file, err = io.open(elsa.filesystem.getSaveDirectory() .. "/ocemu.cfg","wb") + if not file then + error("Problem opening config for saving: " .. err,0) + end + writeComment(comments[1],file,0) + serialize(_config,"ocemu","",file,2) + file:close() +end + +function config.get(key,default) + checkArg(1,key,"string") + if _config == nil then + error("Configuration not loaded",2) + end + local v = _config + for part in key:gmatch("(.-)%.") do + if v[part] == nil then + v[part] = {} + end + v = v[part] + end + local last = ("." .. key):match(".*%.(.+)") + if v[last] == nil then + v[last] = default + end + return v[last] +end + +function config.set(key,value) + checkArg(1,key,"string") + if _config == nil then + error("Configuration not loaded",2) + end + local v = _config + for part in key:gmatch("(.-)%.") do + if v[part] == nil then + v[part] = {} + end + v = v[part] + end + local last = ("." .. key):match(".*%.(.+)") + v[last] = value +end diff --git a/src/main.lua b/src/main.lua index 28e5e12..c4be1be 100644 --- a/src/main.lua +++ b/src/main.lua @@ -3,6 +3,18 @@ if elsa == nil then return end +-- load configuration +elsa.filesystem.load("config.lua")() +config.load() + +elsa.cleanup = {} +function elsa.quit() + config.save() + for k,v in pairs(elsa.cleanup) do + v() + end +end + conf = { -- Format: string:type, (string or number or nil):address, (number or nil):slot, component parameters -- Read component files for parameter documentation