From e18b17217fbcb35e9670b3fae2f39bfcb0715ecf Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Wed, 15 Aug 2018 17:46:03 +0200 Subject: [PATCH] Added CheckReplacement to event handlers, a function inspired by its namesake in Unreal's Mutator class. Performs runtime replacement of actor classes. Takes priority over the "replaces" keyword in both DECORATE and ZScript. --- src/events.cpp | 27 +++++++++++++++++++++++++++ src/events.h | 12 ++++++++++++ src/info.cpp | 4 +++- wadsrc/static/zscript/events.txt | 9 +++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index eabf1b9313..11766f6c90 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -38,6 +38,7 @@ #include "actor.h" #include "c_dispatch.h" #include "d_net.h" +#include "info.h" DStaticEventHandler* E_FirstEventHandler = nullptr; DStaticEventHandler* E_LastEventHandler = nullptr; @@ -506,6 +507,12 @@ bool E_CheckRequireMouse() return false; } +void E_CheckReplacement( PClassActor *replacee, PClassActor **replacement ) +{ + for (DStaticEventHandler *handler = E_FirstEventHandler; handler; handler = handler->next) + handler->CheckReplacement(replacee,replacement); +} + // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) DEFINE_EVENT_LOOPER(WorldLightning) @@ -571,6 +578,9 @@ DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Name) DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, Args) DEFINE_FIELD_X(ConsoleEvent, FConsoleEvent, IsManual) +DEFINE_FIELD_X(ReplaceEvent, FReplaceEvent, Replacee) +DEFINE_FIELD_X(ReplaceEvent, FReplaceEvent, Replacement) + DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -653,6 +663,8 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, PostUiTick); DEFINE_EMPTY_HANDLER(DStaticEventHandler, ConsoleProcess); DEFINE_EMPTY_HANDLER(DStaticEventHandler, NetworkProcess); +DEFINE_EMPTY_HANDLER(DStaticEventHandler, CheckReplacement); + // =========================================== // // Event handlers @@ -1123,6 +1135,21 @@ void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int } } +void DStaticEventHandler::CheckReplacement( PClassActor *replacee, PClassActor **replacement ) +{ + IFVIRTUAL(DStaticEventHandler, CheckReplacement) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_CheckReplacement_VMPtr) + return; + FReplaceEvent e = { replacee, *replacement }; + VMValue params[2] = { (DStaticEventHandler*)this, &e }; + VMCall(func, params, 2, nullptr, 0); + if ( e.Replacement != replacee ) // prevent infinite recursion + *replacement = e.Replacement; + } +} + // void DStaticEventHandler::OnDestroy() { diff --git a/src/events.h b/src/events.h index 072502501b..4359178ceb 100755 --- a/src/events.h +++ b/src/events.h @@ -69,6 +69,9 @@ bool E_Responder(const event_t* ev); // splits events into InputProcess and UiPr // this executes on console/net events. void E_Console(int player, FString name, int arg1, int arg2, int arg3, bool manual); +// called when looking up the replacement for an actor class +void E_CheckReplacement(PClassActor* replacee, PClassActor** replacement); + // send networked event. unified function. bool E_SendNetworkEvent(FString name, int arg1, int arg2, int arg3, bool manual); @@ -166,6 +169,9 @@ public: // void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual); + + // + void CheckReplacement(PClassActor* replacee, PClassActor** replacement); }; class DEventHandler : public DStaticEventHandler { @@ -262,4 +268,10 @@ struct FConsoleEvent bool IsManual; }; +struct FReplaceEvent +{ + PClassActor* Replacee; + PClassActor* Replacement; +}; + #endif diff --git a/src/info.cpp b/src/info.cpp index 4022e8b2ab..480c358145 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -425,7 +425,9 @@ PClassActor *PClassActor::GetReplacement(bool lookskill) lookskill = false; skillrepname = NAME_None; } } - auto Replacement = ActorInfo()->Replacement; + // [MK] ZScript replacement through Event Handlers, has priority over others + PClassActor *Replacement = ActorInfo()->Replacement; + E_CheckReplacement(this,&Replacement); if (Replacement == nullptr && (!lookskill || skillrepname == NAME_None)) { return this; diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index fc8b82721a..038e84515c 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -285,6 +285,12 @@ struct ConsoleEvent native version("2.4") native readonly bool IsManual; } +struct ReplaceEvent native version("2.4") +{ + native readonly Class Replacee; + native Class Replacement; +} + class StaticEventHandler : Object native play version("2.4") { // static event handlers CAN register other static event handlers. @@ -329,6 +335,9 @@ class StaticEventHandler : Object native play version("2.4") virtual native ui void ConsoleProcess(ConsoleEvent e); virtual native void NetworkProcess(ConsoleEvent e); + // + virtual native void CheckReplacement(ReplaceEvent e); + // this value 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.