Skip to content

Commit

Permalink
Merge pull request #5671 from Web-eWorks/game-event-queue
Browse files Browse the repository at this point in the history
Refactor Event Queues
  • Loading branch information
Webster Sheets authored Jan 7, 2024
2 parents 0ddf011 + e8b5327 commit 6821097
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 238 deletions.
126 changes: 87 additions & 39 deletions data/libs/Event.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,80 @@
--

local Engine = require 'Engine'
local utils = require 'utils'

local pending = {}
local callbacks = {}
local do_callback = {}

local do_callback_normal = function (cb, p)
cb(table.unpack(p.event))
local do_callback_normal = function (cb, ev)
cb.func(table.unpack(ev))
end
local do_callback_timed = function (cb, p)
local do_callback_timed = function (cb, ev)
local d = debug.getinfo(cb)

local tstart = Engine.ticks
cb(table.unpack(p.event))
cb.func(table.unpack(ev))
local tend = Engine.ticks

print(string.format("DEBUG: %s %dms %s:%d", p.name, tend-tstart, d.source, d.linedefined))
print(string.format("DEBUG: %s %dms %s:%d", ev.name, tend-tstart, d.source, d.linedefined))
end

---@class EventBase
---@field callbacks table
---@field debugger table
local Event = utils.inherits(nil, "Event")

function Event:Register(name, module, func)

for _, cb in ipairs(self.callbacks[name]) do
-- Update registered callback
if cb.module == module then
cb.func = func
return
end
end

table.insert(self.callbacks[name], { module = module, func = func })
end

function Event:Deregister(name, module, func)
for i, cb in ipairs(self.callbacks[name]) do
if cb.module == module and cb.func == func then
table.remove(self.callbacks[name], i)
return
end
end
end

function Event:_Emit()
while #self > 0 do
local ev = table.remove(self, 1)
local executor = self.debugger[ev.name] or do_callback_normal

for _, cb in ipairs(self.callbacks[ev.name]) do
executor(cb, ev)
end
end
end

local Event
Event = {
function Event:_Dump()
for ev, list in pairs(self.callbacks) do
print("event: " .. ev)

for _, v in ipairs(list) do
print("\t{module} -> {func}" % v)
end
end
end

-- Note: this function is written this way to preserve the existing
-- interface to Event.Register(name, callback) as well as provide helpers
-- to automatically acquire module names when registering callbacks
Event.New = function()
---@class EventQueue : EventBase
local self = setmetatable({}, Event.meta)
local super = Event

self.callbacks = utils.automagic()
self.debugger = {}

--
-- Function: Register
--
Expand Down Expand Up @@ -76,11 +130,9 @@ Event = {
--
-- stable
--
Register = function (name, cb)
if not callbacks[name] then callbacks[name] = {} end
callbacks[name][cb] = cb;
if not do_callback[name] then do_callback[name] = do_callback_normal end
end,
self.Register = function (name, cb)
super.Register(self, name, package.modulename(2), cb)
end

--
-- Function: Deregister
Expand All @@ -107,10 +159,9 @@ Event = {
--
-- stable
--
Deregister = function (name, cb)
if not callbacks[name] then return end
callbacks[name][cb] = nil
end,
self.Deregister = function (name, cb)
super.Deregister(self, name, package.modulename(2), cb)
end

--
-- Function: Queue
Expand Down Expand Up @@ -138,9 +189,9 @@ Event = {
--
-- stable
--
Queue = function (name, ...)
table.insert(pending, { name = name, event = {...} })
end,
self.Queue = function (name, ...)
table.insert(self, { name = name, ... })
end

--
-- Function: DebugTimer
Expand All @@ -167,27 +218,24 @@ Event = {
-- debug
--

DebugTimer = function (name, enabled)
self.DebugTimer = function (name, enabled)
do_callback[name] = enabled and do_callback_timed or do_callback_normal
end,
end

-- internal method, called from C++
_Clear = function ()
pending = {}
end,
self._Clear = function ()
for i = #self, 1, -1 do
self[i] = nil
end
end

-- internal method, called from C++
_Emit = function ()
while #pending > 0 do
local p = table.remove(pending, 1)
if callbacks[p.name] then
for cb,_ in pairs(callbacks[p.name]) do
do_callback[p.name](cb, p)
end
end
end
self._Emit = function ()
super._Emit(self)
end
}

return self
end

--
-- Event: onGameStart
Expand Down Expand Up @@ -854,4 +902,4 @@ Event = {
-- experimental
--

return Event
return Event.New()
4 changes: 2 additions & 2 deletions data/libs/autoload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ string.interp = function (s, t)
local i = 0
return (s:gsub('(%b{})', function(w)
if #w > 2 then
return t[w:sub(2, -2)] or w
return tostring(t[w:sub(2, -2)]) or w
else
i = i + 1; return t[i] or w
i = i + 1; return tostring(t[i]) or w
end
end))
end
Expand Down
11 changes: 11 additions & 0 deletions data/meta/_Core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ package.core = {}
---@param name string? dot-qualified name of the package to trigger reimport for
package.reimport = function(name) end

--- Get the module name of the file where this function is called
---@return string moduleName
package.thisModule = function() end

--- Get the module name of the function N stack levels above package.modulename
--- in the execution stack. Note: tail calls may affect the accuracy of this
--- function.
---@param index integer number of stack levels above package.modulename(), minimum 1
---@return string moduleName
package.modulename = function(index) end

--- Log the specified string at the Warning semantic level
function logWarning(string) end

Expand Down
3 changes: 3 additions & 0 deletions data/pigui/baseui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ local pigui = Engine.pigui
local ui = require 'pigui.libs.forwarded'
ui.rescaleUI = require 'pigui.libs.rescale-ui'

---@type EventQueue
ui.Events = pigui.event_queue

--
-- Function: ui.rescaleFraction
--
Expand Down
3 changes: 3 additions & 0 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "galaxy/Economy.h"
#include "lua/LuaEvent.h"
#include "lua/LuaSerializer.h"
#include "pigui/LuaPiGui.h"
#if WITH_OBJECTVIEWER
#include "ObjectViewerView.h"
#endif
Expand Down Expand Up @@ -880,9 +881,11 @@ void Game::EmitPauseState(bool paused)
if (paused) {
// Notify UI that time is paused.
LuaEvent::Queue("onGamePaused");
LuaEvent::Queue(PiGui::GetEventQueue(), "onGamePaused");
} else {
// Notify the UI that time is running again.
LuaEvent::Queue("onGameResumed");
LuaEvent::Queue(PiGui::GetEventQueue(), "onGameResumed");
}
LuaEvent::Emit();
}
Expand Down
6 changes: 6 additions & 0 deletions src/Pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ void StartupScreen::Update(float deltaTime)
}

Pi::pigui->NewFrame();
PiGui::EmitEvents();
PiGui::RunHandler(GetProgress(), "init");
Pi::pigui->Render();
}
Expand Down Expand Up @@ -684,6 +685,7 @@ void MainMenu::Update(float deltaTime)
Pi::intro->Draw(deltaTime);

Pi::pigui->NewFrame();
PiGui::EmitEvents();
PiGui::RunHandler(deltaTime, "mainMenu");

perfInfoDisplay->Update(deltaTime);
Expand Down Expand Up @@ -1037,6 +1039,7 @@ void GameLoop::Update(float deltaTime)
Pi::luaConsole->Draw();
else {
Pi::GetView()->DrawPiGui();
PiGui::EmitEvents();
PiGui::RunHandler(deltaTime, "game");
}
}
Expand Down Expand Up @@ -1101,6 +1104,9 @@ void GameLoop::Update(float deltaTime)

void GameLoop::End()
{
// Process any pending UI events
PiGui::EmitEvents();

// When Pi::game goes, so too goes the death view.
Pi::SetView(0);

Expand Down
1 change: 1 addition & 0 deletions src/Ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Lang.h"
#include "Missile.h"
#include "NavLights.h"
#include "Pi.h"
#include "Planet.h"
#include "Player.h" // <-- Here only for 1 occurrence of "Pi::player" in Ship::Explode
#include "Sensors.h"
Expand Down
4 changes: 4 additions & 0 deletions src/lua/Lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ namespace Lua {
LuaObject<LuaSerializer>::RegisterClass();
LuaObject<LuaTimer>::RegisterClass();

LuaEvent::Init();

LuaConstants::Register(Lua::manager->GetLuaState());
LuaLang::Register();
LuaEconomy::Register();
Expand Down Expand Up @@ -139,6 +141,8 @@ namespace Lua {

void UninitModules()
{
LuaEvent::Uninit();

delete Pi::luaNameGen;

delete Pi::luaSerializer;
Expand Down
48 changes: 29 additions & 19 deletions src/lua/LuaEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,52 @@
#include "LuaObject.h"
#include "LuaUtils.h"

#include "core/Log.h"

namespace LuaEvent {

static LuaRef s_eventTable;

static bool _get_method_onto_stack(lua_State *l, const char *method)
{
LUA_DEBUG_START(l);

int top = lua_gettop(l);

if (!pi_lua_import(l, "Event"))
if (!s_eventTable.IsValid())
return false;

s_eventTable.PushCopyToStack();

lua_getfield(l, -1, method);
if (!lua_isfunction(l, -1)) {
lua_pop(l, 2);
LUA_DEBUG_END(l, 0);
return false;
}

lua_insert(l, top + 1);
lua_settop(l, top + 1);

lua_replace(l, -2);
LUA_DEBUG_END(l, 1);

return true;
}

void Init()
{
lua_State *l = Lua::manager->GetLuaState();

if (!pi_lua_import(l, "Event")) {
Log::Error("Could not load lua Event queue implementation!");
return;
}

s_eventTable = LuaRef(l, -1);

lua_pop(l, 1);
}

void Uninit()
{
s_eventTable.Unref();
}

void Clear()
{
lua_State *l = Lua::manager->GetLuaState();
Expand All @@ -52,19 +72,9 @@ namespace LuaEvent {
LUA_DEBUG_END(l, 0);
}

void QueueInternal(const char *event, const ArgsBase &args)
LuaRef &GetEventQueue()
{
lua_State *l = Lua::manager->GetLuaState();

LUA_DEBUG_START(l);
if (!_get_method_onto_stack(l, "Queue")) return;

int top = lua_gettop(l);
lua_pushstring(l, event);
args.PrepareStack(l);
pi_lua_protected_call(l, lua_gettop(l) - top, 0);

LUA_DEBUG_END(l, 0);
return s_eventTable;
}

} // namespace LuaEvent
Loading

0 comments on commit 6821097

Please sign in to comment.