Kiritow
bc189b4951
分离各SDL类的包装代码. 事件分发处理全部转移至Lua Init层. C层只提供获取事件的方法. 这样有助于提高性能,以及今后Coroutine scheduler的添加.
202 lines
5.2 KiB
Lua
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
|