Skip to content

Commit 8fad0ec

Browse files
committed
Added defered events to standard sys
1 parent c963f7f commit 8fad0ec

7 files changed

Lines changed: 151 additions & 30 deletions

File tree

examples/Asteroid/application.cpp

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ StandardSystemImpl* createPlayerSystem()
3333
.onEvent("OnSDLScanCode", "res/asteroid/move_player.pg")
3434
.onEvent("OnSDLScanCodeReleased", "res/asteroid/release_player.pg")
3535
.onEvent("PlayerHit", "res/asteroid/handle_player_hit.pg")
36-
.onEvent("RespawnPlayer", "res/asteroid/respawn_player.pg")
36+
.onProcessEvent("RespawnPlayer", "res/asteroid/respawn_player.pg")
3737
.onDelta("res/asteroid/update_player.pg") // Update physics every frame
3838
.build();
3939
}
@@ -46,38 +46,11 @@ StandardSystemImpl* createAsteroidSpawnTimerSystem()
4646
LOG_MILE(DOM, "AsteroidSpawnTimer initialized");
4747
sys->setData("spawnTimer", 0.0f);
4848
})
49-
// .onDelta([](StandardSystemHandle* sys, float deltaTime)
50-
// {
51-
// float timer = sys->getData("spawnTimer").get<float>();
52-
// timer += deltaTime;
53-
54-
// if (timer > 10.0f)
55-
// {
56-
// timer -= 10.0f;
57-
// // for (int i = 0; i < 10; i++)
58-
// sys->sendEvent("SpawnAsteroid");
59-
// }
60-
61-
// sys->setData("spawnTimer", timer);
62-
// })
6349
.onEvent("GameOver", "res/asteroid/clear_asteroids.pg")
6450
.onDelta("res/asteroid/spawn_asteroid_timer.pg")
6551
.build();
6652
}
6753

68-
// StandardSystemImpl* createAsteroidSystem()
69-
// {
70-
// return createStandardSystem("AsteroidSystem")
71-
// .onInit([](StandardSystemHandle* sys)
72-
// {
73-
// LOG_MILE(DOM, "AsteroidSystem initialized");
74-
// })
75-
// .ownComponent("Asteroid")
76-
// .onEvent("SpawnAsteroid", "res/asteroid/spawn_single_asteroid.pg")
77-
// .onDelta("res/asteroid/update_asteroids.pg")
78-
// .build();
79-
// }
80-
8154
StandardSystemImpl* createBulletSystem()
8255
{
8356
return createStandardSystem("BulletSystem")

src/Engine/ECS/ecsnativemodule.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,46 @@ namespace pg
280280
return vm->retainValue(args[0]);
281281
});
282282

283+
// onProcessEvent(eventName, scriptPath) - sets a script for a specific event
284+
vm->addNativeMethod(klass, "onProcessEvent", [](VM* vm, int argCount, Value* args) -> Value {
285+
if (argCount < 3)
286+
{
287+
throw std::runtime_error("onEvent expects 2 arguments (eventName, scriptPath)");
288+
}
289+
290+
ObjInstance* self = vm->asInstance(args[0]);
291+
292+
if (not IS_STRING(args[1]))
293+
{
294+
throw std::runtime_error("onEvent expects event name to be a string");
295+
}
296+
297+
if (not IS_STRING(args[2]))
298+
{
299+
throw std::runtime_error("onEvent expects a string script path");
300+
}
301+
302+
auto eventName = vm->asString(args[1]);
303+
auto scriptPath = vm->asString(args[2]);
304+
305+
// Get or create the event scripts vector
306+
Value eventScriptsVec = self->getField("__eventDeferedScripts");
307+
ObjVector* eventScripts = vm->asVector(eventScriptsVec);
308+
309+
// Store as a pair: [eventName, scriptPath]
310+
Value pair = vm->createVector();
311+
ObjVector* pairVec = vm->asVector(pair);
312+
pairVec->fields.push_back(vm->createString(eventName));
313+
pairVec->fields.push_back(vm->createString(scriptPath));
314+
315+
eventScripts->fields.push_back(pair);
316+
317+
LOG_MILE("StandardSysClass", "Set event script for '" << eventName << "': " << scriptPath);
318+
319+
// Return self for chaining
320+
return vm->retainValue(args[0]);
321+
});
322+
283323
// build() - finalizes and registers the system with the ECS
284324
vm->addNativeMethod(klass, "build", [ecsRefCopy](VM* vm, int argCount, Value* args) -> Value {
285325
if (argCount < 1)
@@ -320,6 +360,19 @@ namespace pg
320360
eventScriptMap[eventName] = scriptPath;
321361
}
322362

363+
// Build event script map
364+
_S_EventScriptMap eventDeferedScriptMap;
365+
ObjVector* eventDeferedScripts = vm->asVector(self->getField("__eventDeferedScripts"));
366+
367+
for (Value pairVal : eventDeferedScripts->fields)
368+
{
369+
ObjVector* pair = vm->asVector(pairVal);
370+
std::string eventName = vm->asString(pair->fields[0]);
371+
std::string scriptPath = vm->asString(pair->fields[1]);
372+
373+
eventDeferedScriptMap[eventName] = scriptPath;
374+
}
375+
323376
// Create the StandardSystemImpl
324377
auto* systemImpl = new StandardSystemImpl(
325378
systemName,
@@ -330,6 +383,7 @@ namespace pg
330383
initScript, // initScriptPath
331384
{}, // eventCallbackMap - empty, using scripts instead
332385
eventScriptMap, // eventScriptMap
386+
eventDeferedScriptMap, // deferredEventScriptMap
333387
nullptr, // executeCallback
334388
executeScript, // executeScriptPath
335389
nullptr, // saveCallback
@@ -682,6 +736,7 @@ namespace pg
682736
systemInstance->setField("__executeScript", vm->createString(""));
683737
systemInstance->setField("__deltaScript", vm->createString(""));
684738
systemInstance->setField("__eventScripts", vm->createVector()); // Vector of [eventName, scriptPath] pairs
739+
systemInstance->setField("__eventDeferedScripts", vm->createVector()); // Vector of [eventName, scriptPath] pairs
685740

686741
LOG_MILE("Ecs Compiled Module", "Created system builder for '" << systemName << "'");
687742

src/Engine/ECS/entitysystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ namespace pg
354354
LOG_THIS_MEMBER("ECS");
355355

356356
_unique_id sys1Id = registry.getTypeId(sysAfter);
357-
_unique_id sys2Id = registry.getTypeId(sysBefore));
357+
_unique_id sys2Id = registry.getTypeId(sysBefore);
358358

359359
_succeed(sys1Id, sys2Id);
360360
}

src/Engine/ECS/standardsystem.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ namespace pg
254254
return *this;
255255
}
256256

257+
StandardSystemBuilder& StandardSystemBuilder::onProcessEvent(const std::string& eventName, const std::string& scriptName)
258+
{
259+
data.deferredScriptEventCallbackList[eventName] = scriptName;
260+
261+
return *this;
262+
}
263+
257264
StandardSystemBuilder& StandardSystemBuilder::onExecute(const std::string& scriptName)
258265
{
259266
data.executeScript = scriptName;
@@ -280,6 +287,7 @@ namespace pg
280287
data.initScript,
281288
data.eventCallbackList,
282289
data.scriptEventCallbackList,
290+
data.deferredScriptEventCallbackList,
283291
data.executeCallback,
284292
data.executeScript,
285293
data.saveCallback,

src/Engine/ECS/standardsystem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ namespace pg
115115
// Scripts overload
116116
StandardSystemBuilder& onInit(const std::string& scriptName);
117117
StandardSystemBuilder& onEvent(const std::string& eventName, const std::string& scriptName);
118+
StandardSystemBuilder& onProcessEvent(const std::string& eventName, const std::string& scriptName);
118119
StandardSystemBuilder& onExecute(const std::string& scriptName);
119120
StandardSystemBuilder& onDelta(const std::string& scriptName);
120121

@@ -135,6 +136,7 @@ namespace pg
135136

136137
_S_EventMap eventCallbackList;
137138
_S_EventScriptMap scriptEventCallbackList;
139+
_S_EventScriptMap deferredScriptEventCallbackList;
138140

139141
_S_ExecuteCallback executeCallback;
140142
std::string executeScript;

src/Engine/ECS/system.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,12 +320,64 @@ namespace pg
320320
registry->addEventListener<TickEvent>(this);
321321
}
322322

323-
// Register event listeners
323+
for (auto [eventName, scriptName] : deferredEventScriptCallbackList)
324+
{
325+
auto cachedBytecode = getCachedScript(ecsRef, scriptName, this);
326+
327+
if (cachedBytecode.empty())
328+
continue;
329+
330+
std::string capturedScriptName = scriptName;
331+
332+
deferredEventCompiledScriptCallbackList.emplace(eventName, [this, cachedBytecode, capturedScriptName](StandardSystemHandle* sys, const StandardEvent& event) {
333+
auto ecsRef = sys->getWorld();
334+
335+
VM vm;
336+
ecsRef->setupVm(vm);
337+
338+
vm.addNativeModule("sys", SystemModule{this});
339+
340+
auto value = serializeToTable(&vm, event);
341+
vm.globals["event"] = value;
342+
343+
auto result = interpretWithSysData(sys, vm, cachedBytecode);
344+
345+
if (result != InterpretResult::OK)
346+
{
347+
LOG_ERROR("StandardSystemImpl", "Deferred event script handler error for: " << capturedScriptName);
348+
LOG_ERROR("StandardSystemImpl", "Interpret result: " << (result == InterpretResult::COMPILE_ERROR ? "COMPILE_ERROR" : "RUNTIME_ERROR"));
349+
LOG_ERROR("StandardSystemImpl", "Check VM error messages above for details");
350+
}
351+
});
352+
}
353+
354+
// Register immediate event listeners
324355
for (const auto& eventName : listenedEvents)
325356
{
326357
registry->addStandardEventListener(eventName, this);
327358
}
328359

360+
// Register deferred event listeners via the same standard path.
361+
// onEvent() will push them onto _deferredEventQueue instead of processing immediately.
362+
for (const auto& eventName : listenedDeferredEvents)
363+
{
364+
registry->addStandardEventListener(eventName, this);
365+
}
366+
367+
// Drain the deferred queue during _execute(), after cmdDispatcher has committed entity changes.
368+
if (not listenedDeferredEvents.empty())
369+
{
370+
_executionQueue.emplace_back([this]()
371+
{
372+
while (not _deferredEventQueue.empty())
373+
{
374+
auto event = _deferredEventQueue.front();
375+
_deferredEventQueue.pop();
376+
onProcessEvent(event);
377+
}
378+
});
379+
}
380+
329381
LOG_INFO("StandardSystemImpl", "System fully registered with " << componentOwners.size() << " components and " << listenedEvents.size() << " events");
330382

331383
// Call onRegisterFinished to trigger init callbacks and scripts

src/Engine/ECS/system.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ namespace pg
176176
const std::string& initScriptPath,
177177
_S_EventMap eventMap,
178178
_S_EventScriptMap eventScriptMap,
179+
_S_EventScriptMap deferredEventScriptMap,
179180
_S_ExecuteCallback executeCb,
180181
const std::string& executeScriptPath,
181182
_S_SaveCallback saveCb,
@@ -186,6 +187,7 @@ namespace pg
186187
systemName(name), ownedComponents(componentNames), defaultComponentValues(defaultComponentValues),
187188
initCallback(initCb), initScript(initScriptPath),
188189
eventCallbackList(eventMap), eventScriptCallbackList(eventScriptMap),
190+
deferredEventScriptCallbackList(deferredEventScriptMap),
189191
executeCallback(executeCb), executeScript(executeScriptPath),
190192
saveCallback(saveCb), loadCallback(loadCb), firstLoadCallback(firstLoadCb),
191193
deltaCallback(deltaCb), deltaScript(deltaScriptPath)
@@ -200,6 +202,11 @@ namespace pg
200202
listenedEvents.insert(key);
201203
}
202204

205+
for (auto [key, _] : deferredEventScriptMap)
206+
{
207+
listenedDeferredEvents.insert(key);
208+
}
209+
203210
handle._internalSystemPtr = this;
204211
if (saveLoadEnabled)
205212
{
@@ -225,6 +232,13 @@ namespace pg
225232
{
226233
LOG_THIS_MEMBER("StandardSystemImpl");
227234

235+
// Deferred events are queued and processed later during _execute()
236+
if (listenedDeferredEvents.count(event.name))
237+
{
238+
_deferredEventQueue.push(event);
239+
return;
240+
}
241+
228242
// Call user event callback
229243
auto it = eventCallbackList.find(event.name);
230244

@@ -241,6 +255,18 @@ namespace pg
241255
}
242256
}
243257

258+
void onProcessEvent(const StandardEvent& event)
259+
{
260+
LOG_THIS_MEMBER("StandardSystemImpl");
261+
262+
auto it = deferredEventCompiledScriptCallbackList.find(event.name);
263+
264+
if (it != deferredEventCompiledScriptCallbackList.end())
265+
{
266+
it->second(&handle, event);
267+
}
268+
}
269+
244270
void onEvent(const TickEvent& event);
245271

246272
virtual void onRegisterFinished() override
@@ -375,6 +401,7 @@ namespace pg
375401
private:
376402
std::string systemName;
377403
std::set<std::string> listenedEvents;
404+
std::set<std::string> listenedDeferredEvents;
378405
std::vector<std::string> ownedComponents;
379406
std::unordered_map<std::string, ElementMap> defaultComponentValues;
380407
std::unordered_map<std::string, Own<StandardComponent>*> componentOwners;
@@ -391,6 +418,10 @@ namespace pg
391418
_S_EventScriptMap eventScriptCallbackList;
392419
_S_EventMap eventCompiledScriptCallbackList;
393420

421+
_S_EventScriptMap deferredEventScriptCallbackList;
422+
_S_EventMap deferredEventCompiledScriptCallbackList;
423+
std::queue<StandardEvent> _deferredEventQueue;
424+
394425
_S_ExecuteCallback executeCallback;
395426
std::string executeScript;
396427
_S_ExecuteCallback compiledExecuteScriptCallback;

0 commit comments

Comments
 (0)