Added ordering for handlers - by int value returned by virtual function GetOrder(); Also, some handlers (WorldUnloaded and WorldThingDestroyed) are now executed in reverse order.

This commit is contained in:
ZZYZX 2017-02-02 19:57:00 +02:00
parent 765bc2db39
commit bc1194d03b
3 changed files with 86 additions and 8 deletions

View file

@ -7,6 +7,7 @@
#include "actor.h" #include "actor.h"
DStaticEventHandler* E_FirstEventHandler = nullptr; DStaticEventHandler* E_FirstEventHandler = nullptr;
DStaticEventHandler* E_LastEventHandler = nullptr;
bool E_RegisterHandler(DStaticEventHandler* handler) bool E_RegisterHandler(DStaticEventHandler* handler)
{ {
@ -14,17 +15,53 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
return false; return false;
if (E_CheckHandler(handler)) if (E_CheckHandler(handler))
return false; return false;
// link into normal list // link into normal list
handler->prev = nullptr; // update: link at specific position based on order.
handler->next = E_FirstEventHandler; DStaticEventHandler* before = nullptr;
if (handler->next) for (DStaticEventHandler* existinghandler = E_FirstEventHandler; existinghandler; existinghandler = existinghandler->next)
handler->next->prev = handler; {
if (existinghandler->GetOrder() > handler->GetOrder())
{
before = existinghandler;
break;
}
}
// 1. MyHandler2->1:
// E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler2
// 2. MyHandler3->2:
// E_FirstEventHandler = MyHandler2, E_LastEventHandler = MyHandler3
if (before != nullptr)
{
// if before is not null, link it before the existing handler.
// note that before can be first handler, check for this.
handler->next = before;
handler->prev = before->prev;
before->prev = handler;
if (before == E_FirstEventHandler)
E_FirstEventHandler = handler; E_FirstEventHandler = handler;
}
else
{
// so if before is null, it means add last.
// it can also mean that we have no handlers at all yet.
handler->prev = E_LastEventHandler;
handler->next = nullptr;
if (E_FirstEventHandler == nullptr)
E_FirstEventHandler = handler;
E_LastEventHandler = handler;
if (handler->prev != nullptr)
handler->prev->next = handler;
}
if (handler->IsStatic()) if (handler->IsStatic())
{ {
handler->ObjectFlags |= OF_Fixed; handler->ObjectFlags |= OF_Fixed;
handler->ObjectFlags |= OF_Transient; handler->ObjectFlags |= OF_Transient;
} }
return true; return true;
} }
@ -41,6 +78,8 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
handler->next->prev = handler->prev; handler->next->prev = handler->prev;
if (handler == E_FirstEventHandler) if (handler == E_FirstEventHandler)
E_FirstEventHandler = handler->next; E_FirstEventHandler = handler->next;
if (handler == E_LastEventHandler)
E_LastEventHandler = handler->prev;
if (handler->IsStatic()) if (handler->IsStatic())
{ {
handler->ObjectFlags &= ~(OF_Fixed|OF_Transient); handler->ObjectFlags &= ~(OF_Fixed|OF_Transient);
@ -224,7 +263,7 @@ void E_WorldLoaded()
void E_WorldUnloaded() void E_WorldUnloaded()
{ {
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
{ {
if (handler->IsStatic()) continue; if (handler->IsStatic()) continue;
handler->WorldUnloaded(); handler->WorldUnloaded();
@ -242,7 +281,7 @@ void E_WorldLoadedUnsafe()
void E_WorldUnloadedUnsafe() void E_WorldUnloadedUnsafe()
{ {
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
{ {
if (!handler->IsStatic()) continue; if (!handler->IsStatic()) continue;
handler->WorldUnloaded(); handler->WorldUnloaded();
@ -294,7 +333,7 @@ void E_WorldThingDestroyed(AActor* actor)
// this is because Destroyed should be reverse of Spawned. we don't want to catch random inventory give failures. // this is because Destroyed should be reverse of Spawned. we don't want to catch random inventory give failures.
if (!(actor->ObjectFlags & OF_Spawned)) if (!(actor->ObjectFlags & OF_Spawned))
return; return;
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
handler->WorldThingDestroyed(actor); handler->WorldThingDestroyed(actor);
} }
@ -449,6 +488,12 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame)
DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder)
{
PARAM_SELF_PROLOGUE(DStaticEventHandler);
ACTION_RETURN_INT(0);
}
// =========================================== // ===========================================
// //
// Event handlers // Event handlers
@ -630,3 +675,22 @@ void DStaticEventHandler::OnDestroy()
E_UnregisterHandler(this); E_UnregisterHandler(this);
Super::OnDestroy(); Super::OnDestroy();
} }
//
int DStaticEventHandler::GetOrder()
{
// if we have cached order, return it.
// otherwise call VM.
if (haveorder)
return order;
IFVIRTUAL(DStaticEventHandler, GetOrder)
{
VMReturn results[1] = { &order };
VMValue params[1] = { (DStaticEventHandler*)this };
GlobalVMStack.Call(func, params, 1, results, 1, nullptr);
haveorder = true;
}
return order;
}

View file

@ -59,12 +59,18 @@ public:
{ {
prev = 0; prev = 0;
next = 0; next = 0;
order = 0;
haveorder = false;
} }
DStaticEventHandler* prev; DStaticEventHandler* prev;
DStaticEventHandler* next; DStaticEventHandler* next;
virtual bool IsStatic() { return true; } virtual bool IsStatic() { return true; }
// order is cached to avoid calling the VM for sorting too much
int order;
bool haveorder;
// serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields
void Serialize(FSerializer& arc) override void Serialize(FSerializer& arc) override
{ {
@ -93,6 +99,9 @@ public:
virtual void WorldLightning(); virtual void WorldLightning();
virtual void WorldTick(); virtual void WorldTick();
virtual void RenderFrame(); virtual void RenderFrame();
// gets the order of this item.
int GetOrder();
}; };
class DEventHandler : public DStaticEventHandler class DEventHandler : public DStaticEventHandler
{ {

View file

@ -49,6 +49,11 @@ class StaticEventHandler : Object native
virtual native void WorldTick(WorldEvent e); virtual native void WorldTick(WorldEvent e);
virtual native void RenderFrame(RenderEvent e); virtual native void RenderFrame(RenderEvent e);
// this function should return a value that will be queried on Register() to decide the relative order of this handler to every other.
// this is most useful in UI systems.
// default is 0.
virtual native int GetOrder();
} }
class EventHandler : StaticEventHandler native class EventHandler : StaticEventHandler native