LuaYard/code/init.lua
Kiritow bc189b4951 完整重构
分离各SDL类的包装代码.
事件分发处理全部转移至Lua Init层. C层只提供获取事件的方法.
这样有助于提高性能,以及今后Coroutine scheduler的添加.
2019-08-25 00:09:28 +08:00

202 lines
5.2 KiB
Lua

local engine = require("engine")
------------------------- Events -------------------------
local event = {}
local timers = {}
local listeners = {}
local callbacks = {}
local window_map = {}
function event.window_listen(wnd, event_name, cb)
local window_id = wnd:getid()
window_map[window_id] = wnd
if not listeners[window_id] then
listeners[window_id] = {}
end
if not listeners[window_id][event_name] then
listeners[window_id][event_name] = {}
end
listeners[window_id][event_name][cb] = true
end
function event.listen(event_name, cb)
if not listeners[event_name] then
listeners[event_name] = {}
end
listeners[event_name][cb] = true
end
------------------------- Utils -------------------------
local utils = {}
function utils.ConvertMusic(from, target, cb)
table.insert(callbacks, cb)
engine.convertMusic(from, target, #callbacks)
end
function utils.setInterval(cb, ms)
local tid = engine.setInterval(ms)
timers[tid] = cb
end
function utils.setTimeout(cb, ms)
local tid = engine.setTimeout(ms)
timers[tid] = cb
end
package.loaded["utils"] = utils
------------------------- Tweaks -------------------------
local plainRenderer = require("renderer")
package.loaded["renderer"] = function(...)
local r = plainRenderer(...)
local mt = getmetatable(r)
local oldFunc = mt.__index.loadTexture
local textureWatcher = setmetatable({}, {__mode="k"})
local lastCallTime = os.time()
mt.__index.loadTexture = function(...)
print("loadTexture invoked.")
local text = oldFunc(...)
textureWatcher[text] = true
if os.time() - lastCallTime > 3 then
local cnt = 0
for t, b in pairs(textureWatcher) do
cnt = cnt + 1
end
print("Total weak texture: ", cnt)
if cnt > 100 then
collectgarbage()
end
lastCallTime = os.time()
end
return text
end
package.loaded["renderer"] = plainRenderer
return r
end
local plainWindow = require("window")
package.loaded["window"] = function(...)
local w = plainWindow(...)
local mt = getmetatable(w)
mt.__index["on"] = function(wnd, event_name, cb)
if event_name == "quit" then
event.listen("quit", cb)
else
event.window_listen(wnd, event_name, cb)
end
end
package.loaded["window"] = plainWindow
return w
end
------------------------- Promise, Async/Await Helpers -------------------------
function Promise(cb)
local p = {
__waiting = {},
__status = 0
}
p.resolve = function(...)
p.__ret = table.pack(...)
p.__status = 1
while #p.__waiting > 0 do
local co = p.__waiting[1]
table.remove(p.__waiting, 1)
coroutine.resume(co)
end
end
p.reject = function(err)
p.__ret = err
p.__status = 2
while #p.__waiting > 0 do
local co = p.__waiting[1]
table.remove(p.__waiting, 1)
coroutine.resume(co)
end
end
cb(p.resolve, p.reject)
return p
end
function await(p)
if p.__status ~= 0 then
if p.__status == 1 then
return table.unpack(p.__ret)
else
error(p.__ret)
end
else
local current = coroutine.running()
table.insert(p.__waiting, current)
coroutine.yield(p)
end
end
function async(fn)
return function()
local co = coroutine.create(fn)
local ret = table.pack(coroutine.resume(fn))
if coroutine.status(co) == "dead" then
local success = table.remove(ret, 1)
ret.n = ret.n - 1
local p = {}
if success then
p.__status = 1 -- resolved
p.__ret = ret
else
p.__status = 2 -- rejected
p.__ret = ret[1]
end
return p
else
return ret[2]
end
end
end
------------------------- Load & run game -------------------------
local gameMain, err = loadfile("code/game.lua")
if not gameMain then
print("Lua compile error:")
print(err)
error("Abort")
else
if not xpcall(gameMain, function(err)
print("Uncaught Exception from LuaMain: ", err)
print(debug.traceback())
end) then
error("Abort")
end
end
------------------------- Event handling -------------------------
local engineState = true
local function DispatchEvent(e)
if e.windowID then
if listeners[e.windowID] and listeners[e.windowID][e.type] then
for k in pairs(listeners[e.windowID][e.type]) do
k(e)
end
end
elseif e.type == "general" then
callbacks[e.ticket]()
elseif e.type == "quit" then
for k in pairs(listeners["quit"]) do
local ret = k()
if ret or ret == nil then
engineState = false
end
end
else
if listeners[e.type] then
for k in pairs(listeners[e.type]) do
k(e)
end
end
end
end
while engineState do
local e = engine.waitEvent()
DispatchEvent(e)
end