From 60406a3cb621c079b45cd64668fd5091b5c18d63 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 02:33:53 +0200 Subject: [PATCH 01/69] Added: prototype event system --- src/CMakeLists.txt | 1 + src/d_main.cpp | 4 + src/events.cpp | 184 ++++++++++++++++++++++++++++++++++++++ src/events.h | 60 +++++++++++++ src/gl/scene/gl_scene.cpp | 4 + src/r_main.cpp | 4 + wadsrc/static/zscript.txt | 1 + 7 files changed, 258 insertions(+) create mode 100755 src/events.cpp create mode 100755 src/events.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 870275324..50d873ffd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1214,6 +1214,7 @@ set (PCH_SOURCES scripting/zscript/zcc_expr.cpp scripting/zscript/zcc_parser.cpp sfmt/SFMT.cpp + events.cpp ) enable_precompiled_headers( g_pch.h PCH_SOURCES ) diff --git a/src/d_main.cpp b/src/d_main.cpp index 971e0ece0..6760195db 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -110,6 +110,7 @@ #include "autosegs.h" #include "fragglescript/t_fs.h" #include "g_levellocals.h" +#include "events.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -775,6 +776,9 @@ void D_Display () screen->SetBlendingRect(viewwindowx, viewwindowy, viewwindowx + viewwidth, viewwindowy + viewheight); + // [ZZ] execute event hook that we just started the frame + E_RenderFrame(); + // Renderer->RenderView(&players[consoleplayer]); if ((hw2d = screen->Begin2D(viewactive))) diff --git a/src/events.cpp b/src/events.cpp new file mode 100755 index 000000000..9de70eb03 --- /dev/null +++ b/src/events.cpp @@ -0,0 +1,184 @@ +#include "events.h" +#include "virtual.h" +#include "r_utility.h" + +DEventHandler* E_FirstDEventHandler = nullptr; + +void E_RegisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link into normal list + handler->prev = nullptr; + handler->next = E_FirstDEventHandler; + if (handler->next) + handler->next->prev = handler; + E_FirstDEventHandler = handler; +} + +void E_UnregisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link out of normal list + if (handler->prev) + handler->prev->next = handler->next; + if (handler->next) + handler->next->prev = handler->prev; + if (handler == E_FirstDEventHandler) + E_FirstDEventHandler = handler->next; +} + +void E_MapLoaded() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapLoaded(); +} + +void E_MapUnloading() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapUnloading(); +} + +void E_RenderFrame() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderFrame(); +} + +void E_RenderCamera() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderCamera(); +} + +// declarations +IMPLEMENT_CLASS(DEventHandler, false, false); +IMPLEMENT_CLASS(DRenderEventHandler, false, false); + +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPos); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); + +DEFINE_ACTION_FUNCTION(DEventHandler, Create) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Register) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_RegisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_UnregisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapLoaded) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapUnloading) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderFrame) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderCamera) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +// +void DEventHandler::OnDestroy() +{ + E_UnregisterHandler(this); + DObject::OnDestroy(); +} + +void DEventHandler::MapLoaded() +{ + IFVIRTUAL(DEventHandler, MapLoaded) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::MapUnloading() +{ + IFVIRTUAL(DEventHandler, MapUnloading) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderFrame() +{ + IFVIRTUAL(DEventHandler, RenderFrame) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderCamera() +{ + IFVIRTUAL(DEventHandler, RenderCamera) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DRenderEventHandler::Setup() +{ + ViewPos = ::ViewPos; + ViewAngle = ::ViewAngle; + ViewPitch = ::ViewPitch; + ViewRoll = ::ViewRoll; + FracTic = ::r_TicFracF; +} + +void DRenderEventHandler::RenderFrame() +{ + Setup(); + DEventHandler::RenderFrame(); +} + +void DRenderEventHandler::RenderCamera() +{ + Setup(); + DEventHandler::RenderCamera(); +} diff --git a/src/events.h b/src/events.h new file mode 100755 index 000000000..b254ddfaf --- /dev/null +++ b/src/events.h @@ -0,0 +1,60 @@ +#ifndef EVENTS_H +#define EVENTS_H + +#include "dobject.h" + +class DEventHandler : public DObject // make it a part of normal GC process +{ + DECLARE_CLASS(DEventHandler, DObject) +public: + DEventHandler* prev; + DEventHandler* next; + DEventHandler* unregPrev; + DEventHandler* unregNext; + + // destroy handler. this unlinks EventHandler from the list automatically. + void OnDestroy() override; + + // called right after the map has loaded (approximately same time as OPEN ACS scripts) + virtual void MapLoaded(); + // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) + virtual void MapUnloading(); + // called on each render frame once. + virtual void RenderFrame(); + // called before entering each actor's view (including RenderFrame) + virtual void RenderCamera(); +}; +extern DEventHandler* E_FirstEventHandler; + +class DRenderEventHandler : public DEventHandler +{ + DECLARE_CLASS(DRenderEventHandler, DEventHandler) +public: + DVector3 ViewPos; + DAngle ViewAngle; + DAngle ViewPitch; + DAngle ViewRoll; + double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. + + void RenderFrame() override; + void RenderCamera() override; + +private: + void Setup(); +}; + +// register +void E_RegisterHandler(DEventHandler* handler); +// unregister +void E_UnregisterHandler(DEventHandler* handler); + +// called right after the map has loaded (approximately same time as OPEN ACS scripts) +void E_MapLoaded(); +// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) +void E_MapUnloading(); +// called on each render frame once. +void E_RenderFrame(); +// called before entering each actor's view (including RenderFrame) +void E_RenderCamera(); + +#endif \ No newline at end of file diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b67cf810e..f3b37ffb5 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -44,6 +44,7 @@ #include "gl/gl_functions.h" #include "serializer.h" #include "g_levellocals.h" +#include "events.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/system/gl_interface.h" @@ -477,6 +478,9 @@ void FGLRenderer::RenderTranslucent() void FGLRenderer::DrawScene(int drawmode) { + // [ZZ] call event hook + E_RenderCamera(); + static int recursion=0; static int ssao_portals_available = 0; diff --git a/src/r_main.cpp b/src/r_main.cpp index 7030339c7..11e7cfc09 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -59,6 +59,7 @@ #include "r_data/colormaps.h" #include "p_maputl.h" #include "r_thread.h" +#include "events.h" CVAR (String, r_viewsize, "", CVAR_NOSET) CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) @@ -840,6 +841,9 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) R_SetupBuffer (); R_SetupFrame (actor); + // [ZZ] call event hook + E_RenderCamera(); + // Clear buffers. R_ClearClipSegs (0, viewwidth); R_ClearDrawSegs (); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 7cd9722bc..9f1033b17 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -5,6 +5,7 @@ #include "zscript/constants.txt" #include "zscript/actor.txt" #include "zscript/actor_checks.txt" +#include "zscript/events.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" From 4c082d968edea3375dcd2c057148d49072394ccb Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 02:56:15 +0200 Subject: [PATCH 02/69] Added EventHandler.CreateOnce and EventHandler.Find to refer to handlers after they are created --- src/events.cpp | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 9de70eb03..93973bd6f 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,7 +2,7 @@ #include "virtual.h" #include "r_utility.h" -DEventHandler* E_FirstDEventHandler = nullptr; +DEventHandler* E_FirstEventHandler = nullptr; void E_RegisterHandler(DEventHandler* handler) { @@ -10,10 +10,10 @@ void E_RegisterHandler(DEventHandler* handler) return; // link into normal list handler->prev = nullptr; - handler->next = E_FirstDEventHandler; + handler->next = E_FirstEventHandler; if (handler->next) handler->next->prev = handler; - E_FirstDEventHandler = handler; + E_FirstEventHandler = handler; } void E_UnregisterHandler(DEventHandler* handler) @@ -25,31 +25,31 @@ void E_UnregisterHandler(DEventHandler* handler) handler->prev->next = handler->next; if (handler->next) handler->next->prev = handler->prev; - if (handler == E_FirstDEventHandler) - E_FirstDEventHandler = handler->next; + if (handler == E_FirstEventHandler) + E_FirstEventHandler = handler->next; } void E_MapLoaded() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapLoaded(); } void E_MapUnloading() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapUnloading(); } void E_RenderFrame() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderFrame(); } void E_RenderCamera() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderCamera(); } @@ -71,6 +71,28 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) ACTION_RETURN_OBJECT(t->CreateNew()); } +DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + // check if there are already registered handlers of this type. + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(nullptr); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Find) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(handler); + ACTION_RETURN_OBJECT(nullptr); +} + DEFINE_ACTION_FUNCTION(DEventHandler, Register) { PARAM_PROLOGUE; From f5c29ec3e2bb37410747f9b5022ff449eca65be0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 04:15:30 +0200 Subject: [PATCH 03/69] Forgot to add events.txt --- wadsrc/static/zscript/events.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 wadsrc/static/zscript/events.txt diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt new file mode 100755 index 000000000..080dfe3cf --- /dev/null +++ b/wadsrc/static/zscript/events.txt @@ -0,0 +1,24 @@ +class EventHandler : Object native +{ + static native EventHandler Create(class type); + static native EventHandler CreateOnce(class type); + static native EventHandler Find(class type); + + static native bool Register(EventHandler handler); + static native bool Unregister(EventHandler handler); + + virtual native void MapLoaded(); + virtual native void MapUnloading(); + + virtual native void RenderFrame(); + virtual native void RenderCamera(); +} + +class RenderEventHandler : EventHandler native +{ + native readonly Vector3 ViewPos; + native readonly double ViewAngle; + native readonly double ViewPitch; + native readonly double ViewRoll; + native readonly double FracTic; +} \ No newline at end of file From 841c7c9712243efd7516a5ae88f28686f6aafe5b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 06:23:44 +0200 Subject: [PATCH 04/69] Generalized event handler definition; removed excessive VM calls when we don't have override defined. --- src/events.cpp | 83 +++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 65 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 93973bd6f..1767ac333 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -109,33 +109,26 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) return 0; } -DEFINE_ACTION_FUNCTION(DEventHandler, MapLoaded) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; +#define DEFINE_EVENT_HANDLER(cls, funcname) DEFINE_ACTION_FUNCTION(cls, funcname) \ +{ \ + PARAM_SELF_PROLOGUE(cls); \ + return 0; \ +} \ +void cls::funcname() \ +{ \ + IFVIRTUAL(cls, funcname) \ + { \ + if (func == cls##_##funcname##_VMPtr) \ + return; \ + VMValue params[1] = { (cls*)this }; \ + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); \ + } \ } -DEFINE_ACTION_FUNCTION(DEventHandler, MapUnloading) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} - -DEFINE_ACTION_FUNCTION(DEventHandler, RenderFrame) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} - -DEFINE_ACTION_FUNCTION(DEventHandler, RenderCamera) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} +DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded) +DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading) +DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame) +DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera) // void DEventHandler::OnDestroy() @@ -144,46 +137,6 @@ void DEventHandler::OnDestroy() DObject::OnDestroy(); } -void DEventHandler::MapLoaded() -{ - IFVIRTUAL(DEventHandler, MapLoaded) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::MapUnloading() -{ - IFVIRTUAL(DEventHandler, MapUnloading) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::RenderFrame() -{ - IFVIRTUAL(DEventHandler, RenderFrame) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::RenderCamera() -{ - IFVIRTUAL(DEventHandler, RenderCamera) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - void DRenderEventHandler::Setup() { ViewPos = ::ViewPos; From 9c1c7129c18d671b487f358933e2482990599537 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:04:35 +0200 Subject: [PATCH 05/69] Added per-thing render hooks --- src/events.cpp | 41 ++++++++++++++++++--- src/events.h | 63 +++++++++++++++++++++++++------- src/gl/scene/gl_sprite.cpp | 3 ++ src/r_things.cpp | 3 ++ wadsrc/static/zscript/events.txt | 7 ++++ 5 files changed, 97 insertions(+), 20 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 1767ac333..4516f32c9 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -53,6 +53,18 @@ void E_RenderCamera() handler->RenderCamera(); } +void E_RenderBeforeThing(AActor* thing) +{ + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->RenderBeforeThing(thing); +} + +void E_RenderAfterThing(AActor* thing) +{ + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->RenderAfterThing(thing); +} + // declarations IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DRenderEventHandler, false, false); @@ -62,6 +74,8 @@ DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, Camera); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, CurrentThing); DEFINE_ACTION_FUNCTION(DEventHandler, Create) { @@ -109,12 +123,12 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) return 0; } -#define DEFINE_EVENT_HANDLER(cls, funcname) DEFINE_ACTION_FUNCTION(cls, funcname) \ +#define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ { \ PARAM_SELF_PROLOGUE(cls); \ return 0; \ } \ -void cls::funcname() \ +void cls::funcname(args) \ { \ IFVIRTUAL(cls, funcname) \ { \ @@ -125,10 +139,12 @@ void cls::funcname() \ } \ } -DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded) -DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading) -DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame) -DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera) +DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded,) +DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderBeforeThing, AActor*) +DEFINE_EVENT_HANDLER(DEventHandler, RenderAfterThing, AActor*) // void DEventHandler::OnDestroy() @@ -144,6 +160,7 @@ void DRenderEventHandler::Setup() ViewPitch = ::ViewPitch; ViewRoll = ::ViewRoll; FracTic = ::r_TicFracF; + Camera = ::camera; } void DRenderEventHandler::RenderFrame() @@ -157,3 +174,15 @@ void DRenderEventHandler::RenderCamera() Setup(); DEventHandler::RenderCamera(); } + +void DRenderEventHandler::RenderBeforeThing(AActor* thing) +{ + CurrentThing = thing; + DEventHandler::RenderBeforeThing(thing); +} + +void DRenderEventHandler::RenderAfterThing(AActor* thing) +{ + CurrentThing = thing; + DEventHandler::RenderAfterThing(thing); +} \ No newline at end of file diff --git a/src/events.h b/src/events.h index b254ddfaf..d8e647432 100755 --- a/src/events.h +++ b/src/events.h @@ -3,6 +3,26 @@ #include "dobject.h" +class DEventHandler; + +// register +void E_RegisterHandler(DEventHandler* handler); +// unregister +void E_UnregisterHandler(DEventHandler* handler); + +// called right after the map has loaded (approximately same time as OPEN ACS scripts) +void E_MapLoaded(); +// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) +void E_MapUnloading(); +// called on each render frame once. +void E_RenderFrame(); +// called before entering each actor's view (including RenderFrame) +void E_RenderCamera(); +// called before adding each actor to the render list +void E_RenderBeforeThing(AActor* thing); +// called after adding each actor to the render list +void E_RenderAfterThing(AActor* thing); + class DEventHandler : public DObject // make it a part of normal GC process { DECLARE_CLASS(DEventHandler, DObject) @@ -23,6 +43,10 @@ public: virtual void RenderFrame(); // called before entering each actor's view (including RenderFrame) virtual void RenderCamera(); + // called before adding each actor to the render list + virtual void RenderBeforeThing(AActor* thing); + // called after adding each actor to the render list + virtual void RenderAfterThing(AActor* thing); }; extern DEventHandler* E_FirstEventHandler; @@ -30,31 +54,42 @@ class DRenderEventHandler : public DEventHandler { DECLARE_CLASS(DRenderEventHandler, DEventHandler) public: + // these are for all render events DVector3 ViewPos; DAngle ViewAngle; DAngle ViewPitch; DAngle ViewRoll; double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. + // this makes sense in RenderCamera + AActor* Camera; + // this is for RenderBeforeThing and RenderAfterThing + AActor* CurrentThing; void RenderFrame() override; void RenderCamera() override; + void RenderBeforeThing(AActor* thing) override; + void RenderAfterThing(AActor* thing) override; + + // this is a class that I use to automatically call RenderAfterThing. + // C++ is really horrible for not providing try-finally statement. + struct AutoThing + { + AActor* thing; + + AutoThing(AActor* thing) + { + this->thing = thing; + E_RenderBeforeThing(this->thing); + } + + ~AutoThing() + { + E_RenderAfterThing(this->thing); + } + }; private: void Setup(); }; -// register -void E_RegisterHandler(DEventHandler* handler); -// unregister -void E_UnregisterHandler(DEventHandler* handler); - -// called right after the map has loaded (approximately same time as OPEN ACS scripts) -void E_MapLoaded(); -// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) -void E_MapUnloading(); -// called on each render frame once. -void E_RenderFrame(); -// called before entering each actor's view (including RenderFrame) -void E_RenderCamera(); - #endif \ No newline at end of file diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index adbc626ed..fcf56fa7d 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -37,6 +37,7 @@ #include "a_pickups.h" #include "d_player.h" #include "g_levellocals.h" +#include "events.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" @@ -649,6 +650,8 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing == nullptr) return; + DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); diff --git a/src/r_things.cpp b/src/r_things.cpp index b6b4a472a..6a4bf0d1a 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -66,6 +66,7 @@ #include "p_maputl.h" #include "g_levellocals.h" #include "r_thread.h" +#include "events.h" EXTERN_CVAR(Bool, st_scale) EXTERN_CVAR(Bool, r_shadercolormaps) @@ -1244,6 +1245,8 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) if (thing->validcount == validcount) continue; thing->validcount = validcount; + DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + FIntCVar *cvar = thing->GetClass()->distancecheck; if (cvar != NULL && *cvar >= 0) { diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 080dfe3cf..8f091e4f5 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -12,13 +12,20 @@ class EventHandler : Object native virtual native void RenderFrame(); virtual native void RenderCamera(); + virtual native void RenderBeforeThing(); + virtual native void RenderAfterThing(); } class RenderEventHandler : EventHandler native { + // for frame and camera native readonly Vector3 ViewPos; native readonly double ViewAngle; native readonly double ViewPitch; native readonly double ViewRoll; native readonly double FracTic; + // for camera + native readonly Actor Camera; + // for thing + native readonly Actor CurrentThing; } \ No newline at end of file From 578ae9b62ae0a2a3b2dcff7f051f115990c7a0fc Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:29:18 +0200 Subject: [PATCH 06/69] Fixed RenderCamera event in software renderer --- src/r_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/r_main.cpp b/src/r_main.cpp index 11e7cfc09..25e3021f0 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -618,6 +618,9 @@ void R_HighlightPortal (PortalDrawseg* pds) void R_EnterPortal (PortalDrawseg* pds, int depth) { + // [ZZ] portal hook + E_RenderCamera(); + // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { From 5e53b73d604cbddaaa210936120770489524a3e2 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:50:18 +0200 Subject: [PATCH 07/69] More portal fixing in software renderer --- src/r_main.cpp | 6 +++--- src/r_plane.cpp | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index 25e3021f0..1ae22ba3f 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -618,9 +618,6 @@ void R_HighlightPortal (PortalDrawseg* pds) void R_EnterPortal (PortalDrawseg* pds, int depth) { - // [ZZ] portal hook - E_RenderCamera(); - // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { @@ -723,6 +720,9 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) R_CopyStackedViewParameters(); + // [ZZ] portal hook + E_RenderCamera(); + validcount++; PortalDrawseg* prevpds = CurrentPortal; CurrentPortal = pds; diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 29f852ece..b452d97a0 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -59,6 +59,7 @@ #include "v_palette.h" #include "r_data/colormaps.h" #include "g_levellocals.h" +#include "events.h" #ifdef _MSC_VER #pragma warning(disable:4244) @@ -1178,6 +1179,8 @@ void R_DrawPortals () R_SetViewAngle (); validcount++; // Make sure we see all sprites + E_RenderCamera(); + R_ClearPlanes (false); R_ClearClipSegs (pl->left, pl->right); WindowLeft = pl->left; From fb1d55101e3f00e15f05c4683c58b70bfc48569c Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 08:56:57 +0200 Subject: [PATCH 08/69] Made the EventHandler class tree a bit more branchy. Now disallowing creation of Static* via EventHandler.Create. --- src/events.cpp | 120 +++++++++++++++++++------------ src/events.h | 44 ++++++++---- src/g_level.cpp | 2 + src/gl/scene/gl_sprite.cpp | 2 +- src/p_spec.cpp | 3 + src/r_things.cpp | 2 +- wadsrc/static/zscript/events.txt | 25 ++++--- 7 files changed, 128 insertions(+), 70 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 4516f32c9..dc563692a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,24 +2,29 @@ #include "virtual.h" #include "r_utility.h" -DEventHandler* E_FirstEventHandler = nullptr; +DStaticEventHandler* E_FirstEventHandler = nullptr; -void E_RegisterHandler(DEventHandler* handler) +bool E_RegisterHandler(DStaticEventHandler* handler) { if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) - return; + return false; + if (E_CheckHandler(handler)) + return false; // link into normal list handler->prev = nullptr; handler->next = E_FirstEventHandler; if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; + return true; } -void E_UnregisterHandler(DEventHandler* handler) +bool E_UnregisterHandler(DStaticEventHandler* handler) { if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) - return; + return false; + if (!E_CheckHandler(handler)) + return false; // link out of normal list if (handler->prev) handler->prev->next = handler->next; @@ -27,60 +32,78 @@ void E_UnregisterHandler(DEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; + return true; +} + +bool E_CheckHandler(DStaticEventHandler* handler) +{ + for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next) + if (handler == lhandler) return true; + return false; } void E_MapLoaded() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapLoaded(); } void E_MapUnloading() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapUnloading(); } void E_RenderFrame() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderFrame(); } void E_RenderCamera() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderCamera(); } void E_RenderBeforeThing(AActor* thing) { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderBeforeThing(thing); } void E_RenderAfterThing(AActor* thing) { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderAfterThing(thing); } // declarations +IMPLEMENT_CLASS(DStaticEventHandler, false, false); +IMPLEMENT_CLASS(DStaticRenderEventHandler, false, false); IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DRenderEventHandler, false, false); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPos); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, Camera); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, CurrentThing); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPos); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewAngle); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPitch); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewRoll); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, FracTic); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, Camera); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, CurrentThing); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); + PARAM_CLASS(t, DStaticEventHandler); + // check if type inherits dynamic handlers + if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + { + // disallow static types creation with Create() + ACTION_RETURN_OBJECT(nullptr); + } // generate a new object of this type. ACTION_RETURN_OBJECT(t->CreateNew()); } @@ -88,9 +111,16 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); + PARAM_CLASS(t, DStaticEventHandler); + // check if type inherits dynamic handlers + if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + { + // disallow static types creation with Create() + ACTION_RETURN_OBJECT(nullptr); + } // check if there are already registered handlers of this type. - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) if (handler->GetClass() == t) // check precise class ACTION_RETURN_OBJECT(nullptr); // generate a new object of this type. @@ -100,8 +130,8 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) DEFINE_ACTION_FUNCTION(DEventHandler, Find) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + PARAM_CLASS(t, DStaticEventHandler); + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) if (handler->GetClass() == t) // check precise class ACTION_RETURN_OBJECT(handler); ACTION_RETURN_OBJECT(nullptr); @@ -110,17 +140,17 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Find) DEFINE_ACTION_FUNCTION(DEventHandler, Register) { PARAM_PROLOGUE; - PARAM_OBJECT(handler, DEventHandler); - E_RegisterHandler(handler); - return 0; + PARAM_OBJECT(handler, DStaticEventHandler); + if (handler->IsStatic()) ACTION_RETURN_BOOL(false); + ACTION_RETURN_BOOL(E_RegisterHandler(handler)); } DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) { PARAM_PROLOGUE; - PARAM_OBJECT(handler, DEventHandler); - E_UnregisterHandler(handler); - return 0; + PARAM_OBJECT(handler, DStaticEventHandler); + if (handler->IsStatic()) ACTION_RETURN_BOOL(false); + ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } #define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ @@ -139,21 +169,21 @@ void cls::funcname(args) \ } \ } -DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded,) -DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderBeforeThing, AActor*) -DEFINE_EVENT_HANDLER(DEventHandler, RenderAfterThing, AActor*) +DEFINE_EVENT_HANDLER(DStaticEventHandler, MapLoaded,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, MapUnloading,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderCamera,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderBeforeThing, AActor*) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderAfterThing, AActor*) // -void DEventHandler::OnDestroy() +void DStaticEventHandler::OnDestroy() { E_UnregisterHandler(this); DObject::OnDestroy(); } -void DRenderEventHandler::Setup() +void DStaticRenderEventHandler::Setup() { ViewPos = ::ViewPos; ViewAngle = ::ViewAngle; @@ -163,26 +193,26 @@ void DRenderEventHandler::Setup() Camera = ::camera; } -void DRenderEventHandler::RenderFrame() +void DStaticRenderEventHandler::RenderFrame() { Setup(); - DEventHandler::RenderFrame(); + DStaticEventHandler::RenderFrame(); } -void DRenderEventHandler::RenderCamera() +void DStaticRenderEventHandler::RenderCamera() { Setup(); - DEventHandler::RenderCamera(); + DStaticEventHandler::RenderCamera(); } -void DRenderEventHandler::RenderBeforeThing(AActor* thing) +void DStaticRenderEventHandler::RenderBeforeThing(AActor* thing) { CurrentThing = thing; - DEventHandler::RenderBeforeThing(thing); + DStaticEventHandler::RenderBeforeThing(thing); } -void DRenderEventHandler::RenderAfterThing(AActor* thing) +void DStaticRenderEventHandler::RenderAfterThing(AActor* thing) { CurrentThing = thing; - DEventHandler::RenderAfterThing(thing); + DStaticEventHandler::RenderAfterThing(thing); } \ No newline at end of file diff --git a/src/events.h b/src/events.h index d8e647432..b6a858834 100755 --- a/src/events.h +++ b/src/events.h @@ -3,12 +3,14 @@ #include "dobject.h" -class DEventHandler; +class DStaticEventHandler; // register -void E_RegisterHandler(DEventHandler* handler); +bool E_RegisterHandler(DStaticEventHandler* handler); // unregister -void E_UnregisterHandler(DEventHandler* handler); +bool E_UnregisterHandler(DStaticEventHandler* handler); +// find +bool E_CheckHandler(DStaticEventHandler* handler); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_MapLoaded(); @@ -23,18 +25,22 @@ void E_RenderBeforeThing(AActor* thing); // called after adding each actor to the render list void E_RenderAfterThing(AActor* thing); -class DEventHandler : public DObject // make it a part of normal GC process +class DStaticEventHandler : public DObject // make it a part of normal GC process { - DECLARE_CLASS(DEventHandler, DObject) + DECLARE_CLASS(DStaticEventHandler, DObject) public: - DEventHandler* prev; - DEventHandler* next; - DEventHandler* unregPrev; - DEventHandler* unregNext; + DStaticEventHandler* prev; + DStaticEventHandler* next; + DStaticEventHandler* unregPrev; + DStaticEventHandler* unregNext; + virtual bool IsStatic() { return true; } // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; + // this checks if we are /actually/ static, using DObject dynamic typing system. + static bool IsActuallyStatic(PClass* type); + // called right after the map has loaded (approximately same time as OPEN ACS scripts) virtual void MapLoaded(); // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) @@ -48,11 +54,17 @@ public: // called after adding each actor to the render list virtual void RenderAfterThing(AActor* thing); }; -extern DEventHandler* E_FirstEventHandler; - -class DRenderEventHandler : public DEventHandler +class DEventHandler : public DStaticEventHandler { - DECLARE_CLASS(DRenderEventHandler, DEventHandler) + DECLARE_CLASS(DEventHandler, DStaticEventHandler) // TODO: make sure this does not horribly break anything +public: + bool IsStatic() override { return false; } +}; +extern DStaticEventHandler* E_FirstEventHandler; + +class DStaticRenderEventHandler : public DStaticEventHandler +{ + DECLARE_CLASS(DStaticRenderEventHandler, DStaticEventHandler) public: // these are for all render events DVector3 ViewPos; @@ -91,5 +103,11 @@ public: private: void Setup(); }; +class DRenderEventHandler : public DStaticRenderEventHandler +{ + DECLARE_CLASS(DRenderEventHandler, DStaticRenderEventHandler) // TODO: make sure this does not horribly break anythings +public: + bool IsStatic() override { return false; } +}; #endif \ No newline at end of file diff --git a/src/g_level.cpp b/src/g_level.cpp index a71b481c9..e92642d00 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -85,6 +85,7 @@ #include "p_spec.h" #include "serializer.h" #include "virtual.h" +#include "events.h" #include "gi.h" @@ -655,6 +656,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill // [RH] Give scripts a chance to do something unloading = true; FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true); + E_MapUnloading(); unloading = false; STAT_ChangeLevel(nextlevel); diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index fcf56fa7d..e2dc6feff 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -650,7 +650,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing == nullptr) return; - DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e5a1178d8..89f920b2f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -39,6 +39,7 @@ #include "d_event.h" #include "g_level.h" #include "gstrings.h" +#include "events.h" #include "i_system.h" #include "m_argv.h" @@ -1442,6 +1443,8 @@ void P_SpawnSpecials (void) break; } } + // [ZZ] Loading event hook + E_MapLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } diff --git a/src/r_things.cpp b/src/r_things.cpp index 6a4bf0d1a..65e33c5b1 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1245,7 +1245,7 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) if (thing->validcount == validcount) continue; thing->validcount = validcount; - DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); FIntCVar *cvar = thing->GetClass()->distancecheck; if (cvar != NULL && *cvar >= 0) diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 8f091e4f5..6d0be8cf5 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,12 +1,5 @@ -class EventHandler : Object native +class StaticEventHandler : Object native { - static native EventHandler Create(class type); - static native EventHandler CreateOnce(class type); - static native EventHandler Find(class type); - - static native bool Register(EventHandler handler); - static native bool Unregister(EventHandler handler); - virtual native void MapLoaded(); virtual native void MapUnloading(); @@ -16,7 +9,7 @@ class EventHandler : Object native virtual native void RenderAfterThing(); } -class RenderEventHandler : EventHandler native +class StaticRenderEventHandler : StaticEventHandler native { // for frame and camera native readonly Vector3 ViewPos; @@ -28,4 +21,16 @@ class RenderEventHandler : EventHandler native native readonly Actor Camera; // for thing native readonly Actor CurrentThing; -} \ No newline at end of file +} + +class EventHandler : StaticEventHandler native +{ + static native StaticEventHandler Create(class type); + static native StaticEventHandler CreateOnce(class type); + static native StaticEventHandler Find(class type); + + static native bool Register(StaticEventHandler handler); + static native bool Unregister(StaticEventHandler handler); +} + +class RenderEventHandler : StaticRenderEventHandler native { } From 2de98c2dd3a04bf4527e87f57fad84d1abdb95db Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 08:58:59 +0200 Subject: [PATCH 09/69] Hopefully I'm using OF_Fixed correctly --- src/events.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index dc563692a..29647fa6a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -16,6 +16,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; + if (handler->IsStatic()) handler->ObjectFlags |= OF_Fixed; return true; } @@ -32,6 +33,11 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; + if (handler->IsStatic()) + { + handler->ObjectFlags |= OF_YesReallyDelete; + delete handler; + } return true; } From 9b3b21c7352589d3ea4d82ff54f09bb4ac59b14b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:36:39 +0200 Subject: [PATCH 10/69] Added EventHandlers in Map section of MAPINFO --- src/events.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++---- src/events.h | 5 ++++ src/g_level.cpp | 2 ++ src/g_level.h | 2 ++ src/g_mapinfo.cpp | 12 ++++++++ 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 29647fa6a..97b32df41 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -1,6 +1,8 @@ #include "events.h" #include "virtual.h" #include "r_utility.h" +#include "g_levellocals.h" +#include "v_text.h" DStaticEventHandler* E_FirstEventHandler = nullptr; @@ -16,7 +18,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; - if (handler->IsStatic()) handler->ObjectFlags |= OF_Fixed; + if (handler->IsStatic() && handler->isMapScope) handler->ObjectFlags |= OF_Fixed; return true; } @@ -33,7 +35,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; - if (handler->IsStatic()) + if (handler->IsStatic() && handler->isMapScope) { handler->ObjectFlags |= OF_YesReallyDelete; delete handler; @@ -48,6 +50,64 @@ bool E_CheckHandler(DStaticEventHandler* handler) return false; } +bool E_IsStaticType(PClass* type) +{ + return (!type->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); +} + +void E_InitStaticHandlers(bool map) +{ + // remove existing + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic() && handler->isMapScope == map) + handler->Destroy(); + } + + // add new + if (map) + { + for (unsigned int i = 0; i < level.info->EventHandlers.Size(); i++) + { + FString typestring = level.info->EventHandlers[i]; + PClass* type = PClass::FindClass(typestring); + + if (type == nullptr) + { + Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + continue; + } + + if (!E_IsStaticType(type)) + { + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + continue; + } + + // check if type already exists, don't add twice. + bool typeExists = false; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsA(type)) + { + typeExists = true; + break; + } + } + + if (typeExists) continue; + DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); + handler->isMapScope = true; + E_RegisterHandler(handler); + } + } + else + { + + } +} + void E_MapLoaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) @@ -104,8 +164,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) PARAM_PROLOGUE; PARAM_CLASS(t, DStaticEventHandler); // check if type inherits dynamic handlers - if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && - !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + if (E_IsStaticType(t)) { // disallow static types creation with Create() ACTION_RETURN_OBJECT(nullptr); @@ -119,8 +178,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) PARAM_PROLOGUE; PARAM_CLASS(t, DStaticEventHandler); // check if type inherits dynamic handlers - if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && - !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + if (E_IsStaticType(t)) { // disallow static types creation with Create() ACTION_RETURN_OBJECT(nullptr); diff --git a/src/events.h b/src/events.h index b6a858834..8be072735 100755 --- a/src/events.h +++ b/src/events.h @@ -11,6 +11,10 @@ bool E_RegisterHandler(DStaticEventHandler* handler); bool E_UnregisterHandler(DStaticEventHandler* handler); // find bool E_CheckHandler(DStaticEventHandler* handler); +// check type +bool E_IsStaticType(PClass* type); +// init static handlers +void E_InitStaticHandlers(bool map); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_MapLoaded(); @@ -33,6 +37,7 @@ public: DStaticEventHandler* next; DStaticEventHandler* unregPrev; DStaticEventHandler* unregNext; + bool isMapScope; // this is only used with IsStatic=true virtual bool IsStatic() { return true; } // destroy handler. this unlinks EventHandler from the list automatically. diff --git a/src/g_level.cpp b/src/g_level.cpp index e92642d00..8ab1f2d48 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1066,6 +1066,8 @@ void G_DoLoadLevel (int position, bool autosave) } } StatusBar->AttachToPlayer (&players[consoleplayer]); + // [ZZ] init per-map static handlers + E_InitStaticHandlers(true); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/g_level.h b/src/g_level.h index 1fadcee3a..d59a4fc09 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -338,6 +338,8 @@ struct level_info_t TArray PrecacheSounds; TArray PrecacheTextures; TArray PrecacheClasses; + + TArray EventHandlers; level_info_t() { diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index bb641b23b..a33872ff4 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -52,6 +52,7 @@ #include "version.h" #include "v_text.h" #include "g_levellocals.h" +#include "events.h" TArray wadclusterinfos; TArray wadlevelinfos; @@ -1046,6 +1047,17 @@ DEFINE_MAP_OPTION(PrecacheSounds, true) } while (parse.sc.CheckString(",")); } +DEFINE_MAP_OPTION(EventHandlers, true) +{ + parse.ParseAssign(); + + do + { + parse.sc.MustGetString(); + info->EventHandlers.Push(parse.sc.String); + } while (parse.sc.CheckString(",")); +} + DEFINE_MAP_OPTION(PrecacheTextures, true) { parse.ParseAssign(); From e33a320544e6d51eae769ac2a941bb97c63caee7 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:39:33 +0200 Subject: [PATCH 11/69] Fixed static handlers being OF_Fixed: only global (non-map) static handlers should be fixed. --- src/events.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 97b32df41..8927649f4 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -18,7 +18,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; - if (handler->IsStatic() && handler->isMapScope) handler->ObjectFlags |= OF_Fixed; + if (handler->IsStatic() && !handler->isMapScope) handler->ObjectFlags |= OF_Fixed; return true; } @@ -35,7 +35,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; - if (handler->IsStatic() && handler->isMapScope) + if (handler->IsStatic() && !handler->isMapScope) { handler->ObjectFlags |= OF_YesReallyDelete; delete handler; From d5a0c29a6813df1f5cfd79c2f3e54cb2057d13bd Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:58:48 +0200 Subject: [PATCH 12/69] Implemented global EventHandlers in MAPINFO --- src/events.cpp | 68 ++++++++++++++++++++++++++++--------------------- src/g_level.cpp | 2 ++ src/gi.cpp | 1 + src/gi.h | 1 + src/info.cpp | 4 +++ src/p_spec.cpp | 2 -- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 8927649f4..504b2667f 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,6 +2,7 @@ #include "virtual.h" #include "r_utility.h" #include "g_levellocals.h" +#include "gi.h" #include "v_text.h" DStaticEventHandler* E_FirstEventHandler = nullptr; @@ -56,6 +57,37 @@ bool E_IsStaticType(PClass* type) !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); } +static void E_InitStaticHandler(PClass* type, FString typestring, bool map) +{ + if (type == nullptr) + { + Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + return; + } + + if (!E_IsStaticType(type)) + { + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + return; + } + + // check if type already exists, don't add twice. + bool typeExists = false; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsA(type)) + { + typeExists = true; + break; + } + } + + if (typeExists) return; + DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); + handler->isMapScope = map; + E_RegisterHandler(handler); +} + void E_InitStaticHandlers(bool map) { // remove existing @@ -72,39 +104,17 @@ void E_InitStaticHandlers(bool map) { FString typestring = level.info->EventHandlers[i]; PClass* type = PClass::FindClass(typestring); - - if (type == nullptr) - { - Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); - continue; - } - - if (!E_IsStaticType(type)) - { - Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); - continue; - } - - // check if type already exists, don't add twice. - bool typeExists = false; - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { - if (handler->IsA(type)) - { - typeExists = true; - break; - } - } - - if (typeExists) continue; - DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); - handler->isMapScope = true; - E_RegisterHandler(handler); + E_InitStaticHandler(type, typestring, true); } } else { - + for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) + { + FString typestring = gameinfo.EventHandlers[i]; + PClass* type = PClass::FindClass(typestring); + E_InitStaticHandler(type, typestring, false); + } } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 8ab1f2d48..ec4e3049e 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1068,6 +1068,8 @@ void G_DoLoadLevel (int position, bool autosave) StatusBar->AttachToPlayer (&players[consoleplayer]); // [ZZ] init per-map static handlers E_InitStaticHandlers(true); + // call map load hook + E_MapLoaded(); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/gi.cpp b/src/gi.cpp index 8d8ff9da7..b1e0b1cf2 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -317,6 +317,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRINGARRAY(PrecachedClasses, "precacheclasses", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedTextures, "precachetextures", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedSounds, "precachesounds", 0, false) + GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, false) GAMEINFOKEY_STRING(PauseSign, "pausesign") GAMEINFOKEY_STRING(quitSound, "quitSound") GAMEINFOKEY_STRING(BorderFlat, "borderFlat") diff --git a/src/gi.h b/src/gi.h index bd5e84363..1bab4e9a7 100644 --- a/src/gi.h +++ b/src/gi.h @@ -124,6 +124,7 @@ struct gameinfo_t TArray PrecachedClasses; TArray PrecachedTextures; TArray PrecachedSounds; + TArray EventHandlers; FString titleMusic; int titleOrder; diff --git a/src/info.cpp b/src/info.cpp index a424c890f..4167eea04 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -54,6 +54,7 @@ #include "thingdef.h" #include "d_player.h" #include "doomerrors.h" +#include "events.h" extern void LoadActors (); extern void InitBotStuff(); @@ -214,6 +215,9 @@ void PClassActor::StaticInit() ClearStrifeTypes(); LoadActors (); InitBotStuff(); + + // reinit GLOBAL static stuff from gameinfo, once classes are loaded. + E_InitStaticHandlers(false); } //========================================================================== diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 89f920b2f..0eb619723 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1443,8 +1443,6 @@ void P_SpawnSpecials (void) break; } } - // [ZZ] Loading event hook - E_MapLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } From ce616f9c06672ab84825fa79b46faf3fbf2d2dbf Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 02:33:53 +0200 Subject: [PATCH 13/69] Added: prototype event system --- src/CMakeLists.txt | 1 + src/d_main.cpp | 4 + src/events.cpp | 184 ++++++++++++++++++++++++++++++++++++++ src/events.h | 60 +++++++++++++ src/gl/scene/gl_scene.cpp | 4 + src/r_main.cpp | 4 + wadsrc/static/zscript.txt | 1 + 7 files changed, 258 insertions(+) create mode 100755 src/events.cpp create mode 100755 src/events.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55d728097..808462fd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1213,6 +1213,7 @@ set (PCH_SOURCES scripting/zscript/zcc_compile.cpp scripting/zscript/zcc_parser.cpp sfmt/SFMT.cpp + events.cpp ) enable_precompiled_headers( g_pch.h PCH_SOURCES ) diff --git a/src/d_main.cpp b/src/d_main.cpp index 971e0ece0..6760195db 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -110,6 +110,7 @@ #include "autosegs.h" #include "fragglescript/t_fs.h" #include "g_levellocals.h" +#include "events.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -775,6 +776,9 @@ void D_Display () screen->SetBlendingRect(viewwindowx, viewwindowy, viewwindowx + viewwidth, viewwindowy + viewheight); + // [ZZ] execute event hook that we just started the frame + E_RenderFrame(); + // Renderer->RenderView(&players[consoleplayer]); if ((hw2d = screen->Begin2D(viewactive))) diff --git a/src/events.cpp b/src/events.cpp new file mode 100755 index 000000000..9de70eb03 --- /dev/null +++ b/src/events.cpp @@ -0,0 +1,184 @@ +#include "events.h" +#include "virtual.h" +#include "r_utility.h" + +DEventHandler* E_FirstDEventHandler = nullptr; + +void E_RegisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link into normal list + handler->prev = nullptr; + handler->next = E_FirstDEventHandler; + if (handler->next) + handler->next->prev = handler; + E_FirstDEventHandler = handler; +} + +void E_UnregisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link out of normal list + if (handler->prev) + handler->prev->next = handler->next; + if (handler->next) + handler->next->prev = handler->prev; + if (handler == E_FirstDEventHandler) + E_FirstDEventHandler = handler->next; +} + +void E_MapLoaded() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapLoaded(); +} + +void E_MapUnloading() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapUnloading(); +} + +void E_RenderFrame() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderFrame(); +} + +void E_RenderCamera() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderCamera(); +} + +// declarations +IMPLEMENT_CLASS(DEventHandler, false, false); +IMPLEMENT_CLASS(DRenderEventHandler, false, false); + +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPos); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); + +DEFINE_ACTION_FUNCTION(DEventHandler, Create) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Register) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_RegisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_UnregisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapLoaded) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapUnloading) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderFrame) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderCamera) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +// +void DEventHandler::OnDestroy() +{ + E_UnregisterHandler(this); + DObject::OnDestroy(); +} + +void DEventHandler::MapLoaded() +{ + IFVIRTUAL(DEventHandler, MapLoaded) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::MapUnloading() +{ + IFVIRTUAL(DEventHandler, MapUnloading) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderFrame() +{ + IFVIRTUAL(DEventHandler, RenderFrame) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderCamera() +{ + IFVIRTUAL(DEventHandler, RenderCamera) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DRenderEventHandler::Setup() +{ + ViewPos = ::ViewPos; + ViewAngle = ::ViewAngle; + ViewPitch = ::ViewPitch; + ViewRoll = ::ViewRoll; + FracTic = ::r_TicFracF; +} + +void DRenderEventHandler::RenderFrame() +{ + Setup(); + DEventHandler::RenderFrame(); +} + +void DRenderEventHandler::RenderCamera() +{ + Setup(); + DEventHandler::RenderCamera(); +} diff --git a/src/events.h b/src/events.h new file mode 100755 index 000000000..b254ddfaf --- /dev/null +++ b/src/events.h @@ -0,0 +1,60 @@ +#ifndef EVENTS_H +#define EVENTS_H + +#include "dobject.h" + +class DEventHandler : public DObject // make it a part of normal GC process +{ + DECLARE_CLASS(DEventHandler, DObject) +public: + DEventHandler* prev; + DEventHandler* next; + DEventHandler* unregPrev; + DEventHandler* unregNext; + + // destroy handler. this unlinks EventHandler from the list automatically. + void OnDestroy() override; + + // called right after the map has loaded (approximately same time as OPEN ACS scripts) + virtual void MapLoaded(); + // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) + virtual void MapUnloading(); + // called on each render frame once. + virtual void RenderFrame(); + // called before entering each actor's view (including RenderFrame) + virtual void RenderCamera(); +}; +extern DEventHandler* E_FirstEventHandler; + +class DRenderEventHandler : public DEventHandler +{ + DECLARE_CLASS(DRenderEventHandler, DEventHandler) +public: + DVector3 ViewPos; + DAngle ViewAngle; + DAngle ViewPitch; + DAngle ViewRoll; + double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. + + void RenderFrame() override; + void RenderCamera() override; + +private: + void Setup(); +}; + +// register +void E_RegisterHandler(DEventHandler* handler); +// unregister +void E_UnregisterHandler(DEventHandler* handler); + +// called right after the map has loaded (approximately same time as OPEN ACS scripts) +void E_MapLoaded(); +// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) +void E_MapUnloading(); +// called on each render frame once. +void E_RenderFrame(); +// called before entering each actor's view (including RenderFrame) +void E_RenderCamera(); + +#endif \ No newline at end of file diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b67cf810e..f3b37ffb5 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -44,6 +44,7 @@ #include "gl/gl_functions.h" #include "serializer.h" #include "g_levellocals.h" +#include "events.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/system/gl_interface.h" @@ -477,6 +478,9 @@ void FGLRenderer::RenderTranslucent() void FGLRenderer::DrawScene(int drawmode) { + // [ZZ] call event hook + E_RenderCamera(); + static int recursion=0; static int ssao_portals_available = 0; diff --git a/src/r_main.cpp b/src/r_main.cpp index 7030339c7..11e7cfc09 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -59,6 +59,7 @@ #include "r_data/colormaps.h" #include "p_maputl.h" #include "r_thread.h" +#include "events.h" CVAR (String, r_viewsize, "", CVAR_NOSET) CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) @@ -840,6 +841,9 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) R_SetupBuffer (); R_SetupFrame (actor); + // [ZZ] call event hook + E_RenderCamera(); + // Clear buffers. R_ClearClipSegs (0, viewwidth); R_ClearDrawSegs (); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 7cd9722bc..9f1033b17 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -5,6 +5,7 @@ #include "zscript/constants.txt" #include "zscript/actor.txt" #include "zscript/actor_checks.txt" +#include "zscript/events.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt" From ca0d92a4548fdd1bd900bdf98e7fefebdaf80698 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 02:56:15 +0200 Subject: [PATCH 14/69] Added EventHandler.CreateOnce and EventHandler.Find to refer to handlers after they are created --- src/events.cpp | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 9de70eb03..93973bd6f 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,7 +2,7 @@ #include "virtual.h" #include "r_utility.h" -DEventHandler* E_FirstDEventHandler = nullptr; +DEventHandler* E_FirstEventHandler = nullptr; void E_RegisterHandler(DEventHandler* handler) { @@ -10,10 +10,10 @@ void E_RegisterHandler(DEventHandler* handler) return; // link into normal list handler->prev = nullptr; - handler->next = E_FirstDEventHandler; + handler->next = E_FirstEventHandler; if (handler->next) handler->next->prev = handler; - E_FirstDEventHandler = handler; + E_FirstEventHandler = handler; } void E_UnregisterHandler(DEventHandler* handler) @@ -25,31 +25,31 @@ void E_UnregisterHandler(DEventHandler* handler) handler->prev->next = handler->next; if (handler->next) handler->next->prev = handler->prev; - if (handler == E_FirstDEventHandler) - E_FirstDEventHandler = handler->next; + if (handler == E_FirstEventHandler) + E_FirstEventHandler = handler->next; } void E_MapLoaded() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapLoaded(); } void E_MapUnloading() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapUnloading(); } void E_RenderFrame() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderFrame(); } void E_RenderCamera() { - for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderCamera(); } @@ -71,6 +71,28 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) ACTION_RETURN_OBJECT(t->CreateNew()); } +DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + // check if there are already registered handlers of this type. + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(nullptr); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Find) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(handler); + ACTION_RETURN_OBJECT(nullptr); +} + DEFINE_ACTION_FUNCTION(DEventHandler, Register) { PARAM_PROLOGUE; From 2aadd1e13c0e469c553fe42431b9fcee4aa27299 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 04:15:30 +0200 Subject: [PATCH 15/69] Forgot to add events.txt --- wadsrc/static/zscript/events.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 wadsrc/static/zscript/events.txt diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt new file mode 100755 index 000000000..080dfe3cf --- /dev/null +++ b/wadsrc/static/zscript/events.txt @@ -0,0 +1,24 @@ +class EventHandler : Object native +{ + static native EventHandler Create(class type); + static native EventHandler CreateOnce(class type); + static native EventHandler Find(class type); + + static native bool Register(EventHandler handler); + static native bool Unregister(EventHandler handler); + + virtual native void MapLoaded(); + virtual native void MapUnloading(); + + virtual native void RenderFrame(); + virtual native void RenderCamera(); +} + +class RenderEventHandler : EventHandler native +{ + native readonly Vector3 ViewPos; + native readonly double ViewAngle; + native readonly double ViewPitch; + native readonly double ViewRoll; + native readonly double FracTic; +} \ No newline at end of file From 5bfd484ae2b9e1ec5c57419a71aa55ffebab4176 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 06:23:44 +0200 Subject: [PATCH 16/69] Generalized event handler definition; removed excessive VM calls when we don't have override defined. --- src/events.cpp | 83 +++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 65 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 93973bd6f..1767ac333 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -109,33 +109,26 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) return 0; } -DEFINE_ACTION_FUNCTION(DEventHandler, MapLoaded) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; +#define DEFINE_EVENT_HANDLER(cls, funcname) DEFINE_ACTION_FUNCTION(cls, funcname) \ +{ \ + PARAM_SELF_PROLOGUE(cls); \ + return 0; \ +} \ +void cls::funcname() \ +{ \ + IFVIRTUAL(cls, funcname) \ + { \ + if (func == cls##_##funcname##_VMPtr) \ + return; \ + VMValue params[1] = { (cls*)this }; \ + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); \ + } \ } -DEFINE_ACTION_FUNCTION(DEventHandler, MapUnloading) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} - -DEFINE_ACTION_FUNCTION(DEventHandler, RenderFrame) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} - -DEFINE_ACTION_FUNCTION(DEventHandler, RenderCamera) -{ - PARAM_SELF_PROLOGUE(DEventHandler); - // do nothing - return 0; -} +DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded) +DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading) +DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame) +DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera) // void DEventHandler::OnDestroy() @@ -144,46 +137,6 @@ void DEventHandler::OnDestroy() DObject::OnDestroy(); } -void DEventHandler::MapLoaded() -{ - IFVIRTUAL(DEventHandler, MapLoaded) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::MapUnloading() -{ - IFVIRTUAL(DEventHandler, MapUnloading) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::RenderFrame() -{ - IFVIRTUAL(DEventHandler, RenderFrame) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - -void DEventHandler::RenderCamera() -{ - IFVIRTUAL(DEventHandler, RenderCamera) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DEventHandler*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } -} - void DRenderEventHandler::Setup() { ViewPos = ::ViewPos; From 302af61686c0ae5900a0ba06d87e353c88d06aec Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:04:35 +0200 Subject: [PATCH 17/69] Added per-thing render hooks --- src/events.cpp | 41 ++++++++++++++++++--- src/events.h | 63 +++++++++++++++++++++++++------- src/gl/scene/gl_sprite.cpp | 3 ++ src/r_things.cpp | 3 ++ wadsrc/static/zscript/events.txt | 7 ++++ 5 files changed, 97 insertions(+), 20 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 1767ac333..4516f32c9 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -53,6 +53,18 @@ void E_RenderCamera() handler->RenderCamera(); } +void E_RenderBeforeThing(AActor* thing) +{ + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->RenderBeforeThing(thing); +} + +void E_RenderAfterThing(AActor* thing) +{ + for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->RenderAfterThing(thing); +} + // declarations IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DRenderEventHandler, false, false); @@ -62,6 +74,8 @@ DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, Camera); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, CurrentThing); DEFINE_ACTION_FUNCTION(DEventHandler, Create) { @@ -109,12 +123,12 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) return 0; } -#define DEFINE_EVENT_HANDLER(cls, funcname) DEFINE_ACTION_FUNCTION(cls, funcname) \ +#define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ { \ PARAM_SELF_PROLOGUE(cls); \ return 0; \ } \ -void cls::funcname() \ +void cls::funcname(args) \ { \ IFVIRTUAL(cls, funcname) \ { \ @@ -125,10 +139,12 @@ void cls::funcname() \ } \ } -DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded) -DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading) -DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame) -DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera) +DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded,) +DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera,) +DEFINE_EVENT_HANDLER(DEventHandler, RenderBeforeThing, AActor*) +DEFINE_EVENT_HANDLER(DEventHandler, RenderAfterThing, AActor*) // void DEventHandler::OnDestroy() @@ -144,6 +160,7 @@ void DRenderEventHandler::Setup() ViewPitch = ::ViewPitch; ViewRoll = ::ViewRoll; FracTic = ::r_TicFracF; + Camera = ::camera; } void DRenderEventHandler::RenderFrame() @@ -157,3 +174,15 @@ void DRenderEventHandler::RenderCamera() Setup(); DEventHandler::RenderCamera(); } + +void DRenderEventHandler::RenderBeforeThing(AActor* thing) +{ + CurrentThing = thing; + DEventHandler::RenderBeforeThing(thing); +} + +void DRenderEventHandler::RenderAfterThing(AActor* thing) +{ + CurrentThing = thing; + DEventHandler::RenderAfterThing(thing); +} \ No newline at end of file diff --git a/src/events.h b/src/events.h index b254ddfaf..d8e647432 100755 --- a/src/events.h +++ b/src/events.h @@ -3,6 +3,26 @@ #include "dobject.h" +class DEventHandler; + +// register +void E_RegisterHandler(DEventHandler* handler); +// unregister +void E_UnregisterHandler(DEventHandler* handler); + +// called right after the map has loaded (approximately same time as OPEN ACS scripts) +void E_MapLoaded(); +// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) +void E_MapUnloading(); +// called on each render frame once. +void E_RenderFrame(); +// called before entering each actor's view (including RenderFrame) +void E_RenderCamera(); +// called before adding each actor to the render list +void E_RenderBeforeThing(AActor* thing); +// called after adding each actor to the render list +void E_RenderAfterThing(AActor* thing); + class DEventHandler : public DObject // make it a part of normal GC process { DECLARE_CLASS(DEventHandler, DObject) @@ -23,6 +43,10 @@ public: virtual void RenderFrame(); // called before entering each actor's view (including RenderFrame) virtual void RenderCamera(); + // called before adding each actor to the render list + virtual void RenderBeforeThing(AActor* thing); + // called after adding each actor to the render list + virtual void RenderAfterThing(AActor* thing); }; extern DEventHandler* E_FirstEventHandler; @@ -30,31 +54,42 @@ class DRenderEventHandler : public DEventHandler { DECLARE_CLASS(DRenderEventHandler, DEventHandler) public: + // these are for all render events DVector3 ViewPos; DAngle ViewAngle; DAngle ViewPitch; DAngle ViewRoll; double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. + // this makes sense in RenderCamera + AActor* Camera; + // this is for RenderBeforeThing and RenderAfterThing + AActor* CurrentThing; void RenderFrame() override; void RenderCamera() override; + void RenderBeforeThing(AActor* thing) override; + void RenderAfterThing(AActor* thing) override; + + // this is a class that I use to automatically call RenderAfterThing. + // C++ is really horrible for not providing try-finally statement. + struct AutoThing + { + AActor* thing; + + AutoThing(AActor* thing) + { + this->thing = thing; + E_RenderBeforeThing(this->thing); + } + + ~AutoThing() + { + E_RenderAfterThing(this->thing); + } + }; private: void Setup(); }; -// register -void E_RegisterHandler(DEventHandler* handler); -// unregister -void E_UnregisterHandler(DEventHandler* handler); - -// called right after the map has loaded (approximately same time as OPEN ACS scripts) -void E_MapLoaded(); -// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) -void E_MapUnloading(); -// called on each render frame once. -void E_RenderFrame(); -// called before entering each actor's view (including RenderFrame) -void E_RenderCamera(); - #endif \ No newline at end of file diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index adbc626ed..fcf56fa7d 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -37,6 +37,7 @@ #include "a_pickups.h" #include "d_player.h" #include "g_levellocals.h" +#include "events.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_framebuffer.h" @@ -649,6 +650,8 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing == nullptr) return; + DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); diff --git a/src/r_things.cpp b/src/r_things.cpp index 730448706..498208de3 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -66,6 +66,7 @@ #include "p_maputl.h" #include "g_levellocals.h" #include "r_thread.h" +#include "events.h" EXTERN_CVAR(Bool, st_scale) EXTERN_CVAR(Bool, r_shadercolormaps) @@ -1244,6 +1245,8 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) if (thing->validcount == validcount) continue; thing->validcount = validcount; + DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + FIntCVar *cvar = thing->GetClass()->distancecheck; if (cvar != NULL && *cvar >= 0) { diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 080dfe3cf..8f091e4f5 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -12,13 +12,20 @@ class EventHandler : Object native virtual native void RenderFrame(); virtual native void RenderCamera(); + virtual native void RenderBeforeThing(); + virtual native void RenderAfterThing(); } class RenderEventHandler : EventHandler native { + // for frame and camera native readonly Vector3 ViewPos; native readonly double ViewAngle; native readonly double ViewPitch; native readonly double ViewRoll; native readonly double FracTic; + // for camera + native readonly Actor Camera; + // for thing + native readonly Actor CurrentThing; } \ No newline at end of file From ac19af7514ca453f6e5d034d4c69152dbb9f776d Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:29:18 +0200 Subject: [PATCH 18/69] Fixed RenderCamera event in software renderer --- src/r_main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/r_main.cpp b/src/r_main.cpp index 11e7cfc09..25e3021f0 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -618,6 +618,9 @@ void R_HighlightPortal (PortalDrawseg* pds) void R_EnterPortal (PortalDrawseg* pds, int depth) { + // [ZZ] portal hook + E_RenderCamera(); + // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { From a226337185b67f18d3e1b1a95b492f8ab92d7467 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 07:50:18 +0200 Subject: [PATCH 19/69] More portal fixing in software renderer --- src/r_main.cpp | 6 +++--- src/r_plane.cpp | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/r_main.cpp b/src/r_main.cpp index 25e3021f0..1ae22ba3f 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -618,9 +618,6 @@ void R_HighlightPortal (PortalDrawseg* pds) void R_EnterPortal (PortalDrawseg* pds, int depth) { - // [ZZ] portal hook - E_RenderCamera(); - // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { @@ -723,6 +720,9 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) R_CopyStackedViewParameters(); + // [ZZ] portal hook + E_RenderCamera(); + validcount++; PortalDrawseg* prevpds = CurrentPortal; CurrentPortal = pds; diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 29f852ece..b452d97a0 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -59,6 +59,7 @@ #include "v_palette.h" #include "r_data/colormaps.h" #include "g_levellocals.h" +#include "events.h" #ifdef _MSC_VER #pragma warning(disable:4244) @@ -1178,6 +1179,8 @@ void R_DrawPortals () R_SetViewAngle (); validcount++; // Make sure we see all sprites + E_RenderCamera(); + R_ClearPlanes (false); R_ClearClipSegs (pl->left, pl->right); WindowLeft = pl->left; From 35ec14f465f57b3a4f6d04ad9fdc7469337d2fc6 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 08:56:57 +0200 Subject: [PATCH 20/69] Made the EventHandler class tree a bit more branchy. Now disallowing creation of Static* via EventHandler.Create. --- src/events.cpp | 120 +++++++++++++++++++------------ src/events.h | 44 ++++++++---- src/g_level.cpp | 2 + src/gl/scene/gl_sprite.cpp | 2 +- src/p_spec.cpp | 3 + src/r_things.cpp | 2 +- wadsrc/static/zscript/events.txt | 25 ++++--- 7 files changed, 128 insertions(+), 70 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 4516f32c9..dc563692a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,24 +2,29 @@ #include "virtual.h" #include "r_utility.h" -DEventHandler* E_FirstEventHandler = nullptr; +DStaticEventHandler* E_FirstEventHandler = nullptr; -void E_RegisterHandler(DEventHandler* handler) +bool E_RegisterHandler(DStaticEventHandler* handler) { if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) - return; + return false; + if (E_CheckHandler(handler)) + return false; // link into normal list handler->prev = nullptr; handler->next = E_FirstEventHandler; if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; + return true; } -void E_UnregisterHandler(DEventHandler* handler) +bool E_UnregisterHandler(DStaticEventHandler* handler) { if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) - return; + return false; + if (!E_CheckHandler(handler)) + return false; // link out of normal list if (handler->prev) handler->prev->next = handler->next; @@ -27,60 +32,78 @@ void E_UnregisterHandler(DEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; + return true; +} + +bool E_CheckHandler(DStaticEventHandler* handler) +{ + for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next) + if (handler == lhandler) return true; + return false; } void E_MapLoaded() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapLoaded(); } void E_MapUnloading() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->MapUnloading(); } void E_RenderFrame() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderFrame(); } void E_RenderCamera() { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderCamera(); } void E_RenderBeforeThing(AActor* thing) { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderBeforeThing(thing); } void E_RenderAfterThing(AActor* thing) { - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->RenderAfterThing(thing); } // declarations +IMPLEMENT_CLASS(DStaticEventHandler, false, false); +IMPLEMENT_CLASS(DStaticRenderEventHandler, false, false); IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DRenderEventHandler, false, false); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPos); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, Camera); -DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, CurrentThing); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPos); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewAngle); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPitch); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewRoll); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, FracTic); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, Camera); +DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, CurrentThing); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); + PARAM_CLASS(t, DStaticEventHandler); + // check if type inherits dynamic handlers + if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + { + // disallow static types creation with Create() + ACTION_RETURN_OBJECT(nullptr); + } // generate a new object of this type. ACTION_RETURN_OBJECT(t->CreateNew()); } @@ -88,9 +111,16 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); + PARAM_CLASS(t, DStaticEventHandler); + // check if type inherits dynamic handlers + if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + { + // disallow static types creation with Create() + ACTION_RETURN_OBJECT(nullptr); + } // check if there are already registered handlers of this type. - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) if (handler->GetClass() == t) // check precise class ACTION_RETURN_OBJECT(nullptr); // generate a new object of this type. @@ -100,8 +130,8 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) DEFINE_ACTION_FUNCTION(DEventHandler, Find) { PARAM_PROLOGUE; - PARAM_CLASS(t, DEventHandler); - for (DEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + PARAM_CLASS(t, DStaticEventHandler); + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) if (handler->GetClass() == t) // check precise class ACTION_RETURN_OBJECT(handler); ACTION_RETURN_OBJECT(nullptr); @@ -110,17 +140,17 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Find) DEFINE_ACTION_FUNCTION(DEventHandler, Register) { PARAM_PROLOGUE; - PARAM_OBJECT(handler, DEventHandler); - E_RegisterHandler(handler); - return 0; + PARAM_OBJECT(handler, DStaticEventHandler); + if (handler->IsStatic()) ACTION_RETURN_BOOL(false); + ACTION_RETURN_BOOL(E_RegisterHandler(handler)); } DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) { PARAM_PROLOGUE; - PARAM_OBJECT(handler, DEventHandler); - E_UnregisterHandler(handler); - return 0; + PARAM_OBJECT(handler, DStaticEventHandler); + if (handler->IsStatic()) ACTION_RETURN_BOOL(false); + ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } #define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ @@ -139,21 +169,21 @@ void cls::funcname(args) \ } \ } -DEFINE_EVENT_HANDLER(DEventHandler, MapLoaded,) -DEFINE_EVENT_HANDLER(DEventHandler, MapUnloading,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderFrame,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderCamera,) -DEFINE_EVENT_HANDLER(DEventHandler, RenderBeforeThing, AActor*) -DEFINE_EVENT_HANDLER(DEventHandler, RenderAfterThing, AActor*) +DEFINE_EVENT_HANDLER(DStaticEventHandler, MapLoaded,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, MapUnloading,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderCamera,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderBeforeThing, AActor*) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderAfterThing, AActor*) // -void DEventHandler::OnDestroy() +void DStaticEventHandler::OnDestroy() { E_UnregisterHandler(this); DObject::OnDestroy(); } -void DRenderEventHandler::Setup() +void DStaticRenderEventHandler::Setup() { ViewPos = ::ViewPos; ViewAngle = ::ViewAngle; @@ -163,26 +193,26 @@ void DRenderEventHandler::Setup() Camera = ::camera; } -void DRenderEventHandler::RenderFrame() +void DStaticRenderEventHandler::RenderFrame() { Setup(); - DEventHandler::RenderFrame(); + DStaticEventHandler::RenderFrame(); } -void DRenderEventHandler::RenderCamera() +void DStaticRenderEventHandler::RenderCamera() { Setup(); - DEventHandler::RenderCamera(); + DStaticEventHandler::RenderCamera(); } -void DRenderEventHandler::RenderBeforeThing(AActor* thing) +void DStaticRenderEventHandler::RenderBeforeThing(AActor* thing) { CurrentThing = thing; - DEventHandler::RenderBeforeThing(thing); + DStaticEventHandler::RenderBeforeThing(thing); } -void DRenderEventHandler::RenderAfterThing(AActor* thing) +void DStaticRenderEventHandler::RenderAfterThing(AActor* thing) { CurrentThing = thing; - DEventHandler::RenderAfterThing(thing); + DStaticEventHandler::RenderAfterThing(thing); } \ No newline at end of file diff --git a/src/events.h b/src/events.h index d8e647432..b6a858834 100755 --- a/src/events.h +++ b/src/events.h @@ -3,12 +3,14 @@ #include "dobject.h" -class DEventHandler; +class DStaticEventHandler; // register -void E_RegisterHandler(DEventHandler* handler); +bool E_RegisterHandler(DStaticEventHandler* handler); // unregister -void E_UnregisterHandler(DEventHandler* handler); +bool E_UnregisterHandler(DStaticEventHandler* handler); +// find +bool E_CheckHandler(DStaticEventHandler* handler); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_MapLoaded(); @@ -23,18 +25,22 @@ void E_RenderBeforeThing(AActor* thing); // called after adding each actor to the render list void E_RenderAfterThing(AActor* thing); -class DEventHandler : public DObject // make it a part of normal GC process +class DStaticEventHandler : public DObject // make it a part of normal GC process { - DECLARE_CLASS(DEventHandler, DObject) + DECLARE_CLASS(DStaticEventHandler, DObject) public: - DEventHandler* prev; - DEventHandler* next; - DEventHandler* unregPrev; - DEventHandler* unregNext; + DStaticEventHandler* prev; + DStaticEventHandler* next; + DStaticEventHandler* unregPrev; + DStaticEventHandler* unregNext; + virtual bool IsStatic() { return true; } // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; + // this checks if we are /actually/ static, using DObject dynamic typing system. + static bool IsActuallyStatic(PClass* type); + // called right after the map has loaded (approximately same time as OPEN ACS scripts) virtual void MapLoaded(); // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) @@ -48,11 +54,17 @@ public: // called after adding each actor to the render list virtual void RenderAfterThing(AActor* thing); }; -extern DEventHandler* E_FirstEventHandler; - -class DRenderEventHandler : public DEventHandler +class DEventHandler : public DStaticEventHandler { - DECLARE_CLASS(DRenderEventHandler, DEventHandler) + DECLARE_CLASS(DEventHandler, DStaticEventHandler) // TODO: make sure this does not horribly break anything +public: + bool IsStatic() override { return false; } +}; +extern DStaticEventHandler* E_FirstEventHandler; + +class DStaticRenderEventHandler : public DStaticEventHandler +{ + DECLARE_CLASS(DStaticRenderEventHandler, DStaticEventHandler) public: // these are for all render events DVector3 ViewPos; @@ -91,5 +103,11 @@ public: private: void Setup(); }; +class DRenderEventHandler : public DStaticRenderEventHandler +{ + DECLARE_CLASS(DRenderEventHandler, DStaticRenderEventHandler) // TODO: make sure this does not horribly break anythings +public: + bool IsStatic() override { return false; } +}; #endif \ No newline at end of file diff --git a/src/g_level.cpp b/src/g_level.cpp index a71b481c9..e92642d00 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -85,6 +85,7 @@ #include "p_spec.h" #include "serializer.h" #include "virtual.h" +#include "events.h" #include "gi.h" @@ -655,6 +656,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill // [RH] Give scripts a chance to do something unloading = true; FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true); + E_MapUnloading(); unloading = false; STAT_ChangeLevel(nextlevel); diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index fcf56fa7d..e2dc6feff 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -650,7 +650,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing == nullptr) return; - DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index e5a1178d8..89f920b2f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -39,6 +39,7 @@ #include "d_event.h" #include "g_level.h" #include "gstrings.h" +#include "events.h" #include "i_system.h" #include "m_argv.h" @@ -1442,6 +1443,8 @@ void P_SpawnSpecials (void) break; } } + // [ZZ] Loading event hook + E_MapLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } diff --git a/src/r_things.cpp b/src/r_things.cpp index 498208de3..a4709b483 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1245,7 +1245,7 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) if (thing->validcount == validcount) continue; thing->validcount = validcount; - DRenderEventHandler::AutoThing autoRenderThingEvent(thing); + DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); FIntCVar *cvar = thing->GetClass()->distancecheck; if (cvar != NULL && *cvar >= 0) diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 8f091e4f5..6d0be8cf5 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,12 +1,5 @@ -class EventHandler : Object native +class StaticEventHandler : Object native { - static native EventHandler Create(class type); - static native EventHandler CreateOnce(class type); - static native EventHandler Find(class type); - - static native bool Register(EventHandler handler); - static native bool Unregister(EventHandler handler); - virtual native void MapLoaded(); virtual native void MapUnloading(); @@ -16,7 +9,7 @@ class EventHandler : Object native virtual native void RenderAfterThing(); } -class RenderEventHandler : EventHandler native +class StaticRenderEventHandler : StaticEventHandler native { // for frame and camera native readonly Vector3 ViewPos; @@ -28,4 +21,16 @@ class RenderEventHandler : EventHandler native native readonly Actor Camera; // for thing native readonly Actor CurrentThing; -} \ No newline at end of file +} + +class EventHandler : StaticEventHandler native +{ + static native StaticEventHandler Create(class type); + static native StaticEventHandler CreateOnce(class type); + static native StaticEventHandler Find(class type); + + static native bool Register(StaticEventHandler handler); + static native bool Unregister(StaticEventHandler handler); +} + +class RenderEventHandler : StaticRenderEventHandler native { } From 890166a732978a5f6b3461c213a65fe9d457a96a Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 08:58:59 +0200 Subject: [PATCH 21/69] Hopefully I'm using OF_Fixed correctly --- src/events.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index dc563692a..29647fa6a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -16,6 +16,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; + if (handler->IsStatic()) handler->ObjectFlags |= OF_Fixed; return true; } @@ -32,6 +33,11 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; + if (handler->IsStatic()) + { + handler->ObjectFlags |= OF_YesReallyDelete; + delete handler; + } return true; } From 76b99da4b34dcc58e2f8ca8c2021979b2feacc42 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:36:39 +0200 Subject: [PATCH 22/69] Added EventHandlers in Map section of MAPINFO --- src/events.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++---- src/events.h | 5 ++++ src/g_level.cpp | 2 ++ src/g_level.h | 2 ++ src/g_mapinfo.cpp | 12 ++++++++ 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 29647fa6a..97b32df41 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -1,6 +1,8 @@ #include "events.h" #include "virtual.h" #include "r_utility.h" +#include "g_levellocals.h" +#include "v_text.h" DStaticEventHandler* E_FirstEventHandler = nullptr; @@ -16,7 +18,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; - if (handler->IsStatic()) handler->ObjectFlags |= OF_Fixed; + if (handler->IsStatic() && handler->isMapScope) handler->ObjectFlags |= OF_Fixed; return true; } @@ -33,7 +35,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; - if (handler->IsStatic()) + if (handler->IsStatic() && handler->isMapScope) { handler->ObjectFlags |= OF_YesReallyDelete; delete handler; @@ -48,6 +50,64 @@ bool E_CheckHandler(DStaticEventHandler* handler) return false; } +bool E_IsStaticType(PClass* type) +{ + return (!type->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); +} + +void E_InitStaticHandlers(bool map) +{ + // remove existing + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic() && handler->isMapScope == map) + handler->Destroy(); + } + + // add new + if (map) + { + for (unsigned int i = 0; i < level.info->EventHandlers.Size(); i++) + { + FString typestring = level.info->EventHandlers[i]; + PClass* type = PClass::FindClass(typestring); + + if (type == nullptr) + { + Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + continue; + } + + if (!E_IsStaticType(type)) + { + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + continue; + } + + // check if type already exists, don't add twice. + bool typeExists = false; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsA(type)) + { + typeExists = true; + break; + } + } + + if (typeExists) continue; + DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); + handler->isMapScope = true; + E_RegisterHandler(handler); + } + } + else + { + + } +} + void E_MapLoaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) @@ -104,8 +164,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Create) PARAM_PROLOGUE; PARAM_CLASS(t, DStaticEventHandler); // check if type inherits dynamic handlers - if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && - !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + if (E_IsStaticType(t)) { // disallow static types creation with Create() ACTION_RETURN_OBJECT(nullptr); @@ -119,8 +178,7 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) PARAM_PROLOGUE; PARAM_CLASS(t, DStaticEventHandler); // check if type inherits dynamic handlers - if (!t->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && - !t->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))) + if (E_IsStaticType(t)) { // disallow static types creation with Create() ACTION_RETURN_OBJECT(nullptr); diff --git a/src/events.h b/src/events.h index b6a858834..8be072735 100755 --- a/src/events.h +++ b/src/events.h @@ -11,6 +11,10 @@ bool E_RegisterHandler(DStaticEventHandler* handler); bool E_UnregisterHandler(DStaticEventHandler* handler); // find bool E_CheckHandler(DStaticEventHandler* handler); +// check type +bool E_IsStaticType(PClass* type); +// init static handlers +void E_InitStaticHandlers(bool map); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_MapLoaded(); @@ -33,6 +37,7 @@ public: DStaticEventHandler* next; DStaticEventHandler* unregPrev; DStaticEventHandler* unregNext; + bool isMapScope; // this is only used with IsStatic=true virtual bool IsStatic() { return true; } // destroy handler. this unlinks EventHandler from the list automatically. diff --git a/src/g_level.cpp b/src/g_level.cpp index e92642d00..8ab1f2d48 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1066,6 +1066,8 @@ void G_DoLoadLevel (int position, bool autosave) } } StatusBar->AttachToPlayer (&players[consoleplayer]); + // [ZZ] init per-map static handlers + E_InitStaticHandlers(true); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/g_level.h b/src/g_level.h index 1fadcee3a..d59a4fc09 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -338,6 +338,8 @@ struct level_info_t TArray PrecacheSounds; TArray PrecacheTextures; TArray PrecacheClasses; + + TArray EventHandlers; level_info_t() { diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index bb641b23b..a33872ff4 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -52,6 +52,7 @@ #include "version.h" #include "v_text.h" #include "g_levellocals.h" +#include "events.h" TArray wadclusterinfos; TArray wadlevelinfos; @@ -1046,6 +1047,17 @@ DEFINE_MAP_OPTION(PrecacheSounds, true) } while (parse.sc.CheckString(",")); } +DEFINE_MAP_OPTION(EventHandlers, true) +{ + parse.ParseAssign(); + + do + { + parse.sc.MustGetString(); + info->EventHandlers.Push(parse.sc.String); + } while (parse.sc.CheckString(",")); +} + DEFINE_MAP_OPTION(PrecacheTextures, true) { parse.ParseAssign(); From ba4a74265ca331708cde67018b6fc9533ddd0639 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:39:33 +0200 Subject: [PATCH 23/69] Fixed static handlers being OF_Fixed: only global (non-map) static handlers should be fixed. --- src/events.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 97b32df41..8927649f4 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -18,7 +18,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; - if (handler->IsStatic() && handler->isMapScope) handler->ObjectFlags |= OF_Fixed; + if (handler->IsStatic() && !handler->isMapScope) handler->ObjectFlags |= OF_Fixed; return true; } @@ -35,7 +35,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; - if (handler->IsStatic() && handler->isMapScope) + if (handler->IsStatic() && !handler->isMapScope) { handler->ObjectFlags |= OF_YesReallyDelete; delete handler; From efb1e5d33abb340e19ec4ca4271636ace38d0215 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Sun, 22 Jan 2017 09:58:48 +0200 Subject: [PATCH 24/69] Implemented global EventHandlers in MAPINFO --- src/events.cpp | 68 ++++++++++++++++++++++++++++--------------------- src/g_level.cpp | 2 ++ src/gi.cpp | 1 + src/gi.h | 1 + src/info.cpp | 4 +++ src/p_spec.cpp | 2 -- 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 8927649f4..504b2667f 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -2,6 +2,7 @@ #include "virtual.h" #include "r_utility.h" #include "g_levellocals.h" +#include "gi.h" #include "v_text.h" DStaticEventHandler* E_FirstEventHandler = nullptr; @@ -56,6 +57,37 @@ bool E_IsStaticType(PClass* type) !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); } +static void E_InitStaticHandler(PClass* type, FString typestring, bool map) +{ + if (type == nullptr) + { + Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + return; + } + + if (!E_IsStaticType(type)) + { + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + return; + } + + // check if type already exists, don't add twice. + bool typeExists = false; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsA(type)) + { + typeExists = true; + break; + } + } + + if (typeExists) return; + DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); + handler->isMapScope = map; + E_RegisterHandler(handler); +} + void E_InitStaticHandlers(bool map) { // remove existing @@ -72,39 +104,17 @@ void E_InitStaticHandlers(bool map) { FString typestring = level.info->EventHandlers[i]; PClass* type = PClass::FindClass(typestring); - - if (type == nullptr) - { - Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); - continue; - } - - if (!E_IsStaticType(type)) - { - Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); - continue; - } - - // check if type already exists, don't add twice. - bool typeExists = false; - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { - if (handler->IsA(type)) - { - typeExists = true; - break; - } - } - - if (typeExists) continue; - DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); - handler->isMapScope = true; - E_RegisterHandler(handler); + E_InitStaticHandler(type, typestring, true); } } else { - + for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) + { + FString typestring = gameinfo.EventHandlers[i]; + PClass* type = PClass::FindClass(typestring); + E_InitStaticHandler(type, typestring, false); + } } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 8ab1f2d48..ec4e3049e 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1068,6 +1068,8 @@ void G_DoLoadLevel (int position, bool autosave) StatusBar->AttachToPlayer (&players[consoleplayer]); // [ZZ] init per-map static handlers E_InitStaticHandlers(true); + // call map load hook + E_MapLoaded(); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/gi.cpp b/src/gi.cpp index 8d8ff9da7..b1e0b1cf2 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -317,6 +317,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRINGARRAY(PrecachedClasses, "precacheclasses", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedTextures, "precachetextures", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedSounds, "precachesounds", 0, false) + GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, false) GAMEINFOKEY_STRING(PauseSign, "pausesign") GAMEINFOKEY_STRING(quitSound, "quitSound") GAMEINFOKEY_STRING(BorderFlat, "borderFlat") diff --git a/src/gi.h b/src/gi.h index bd5e84363..1bab4e9a7 100644 --- a/src/gi.h +++ b/src/gi.h @@ -124,6 +124,7 @@ struct gameinfo_t TArray PrecachedClasses; TArray PrecachedTextures; TArray PrecachedSounds; + TArray EventHandlers; FString titleMusic; int titleOrder; diff --git a/src/info.cpp b/src/info.cpp index a424c890f..4167eea04 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -54,6 +54,7 @@ #include "thingdef.h" #include "d_player.h" #include "doomerrors.h" +#include "events.h" extern void LoadActors (); extern void InitBotStuff(); @@ -214,6 +215,9 @@ void PClassActor::StaticInit() ClearStrifeTypes(); LoadActors (); InitBotStuff(); + + // reinit GLOBAL static stuff from gameinfo, once classes are loaded. + E_InitStaticHandlers(false); } //========================================================================== diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 89f920b2f..0eb619723 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1443,8 +1443,6 @@ void P_SpawnSpecials (void) break; } } - // [ZZ] Loading event hook - E_MapLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } From 23c9386addf5cb6088df8fdd2e670cdf2548248c Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 23 Jan 2017 23:05:51 +0200 Subject: [PATCH 25/69] Removed RenderCamera, RenderBeforeThing, RenderAfterThing. Serialization preparations. --- src/events.cpp | 47 ++++++-------------------------------- src/events.h | 40 ++++---------------------------- src/gl/scene/gl_scene.cpp | 3 --- src/gl/scene/gl_sprite.cpp | 2 -- src/p_saveg.cpp | 3 +++ src/r_main.cpp | 6 ----- src/r_plane.cpp | 2 -- src/r_things.cpp | 2 -- 8 files changed, 14 insertions(+), 91 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 504b2667f..60e2e3a49 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -53,10 +53,16 @@ bool E_CheckHandler(DStaticEventHandler* handler) bool E_IsStaticType(PClass* type) { - return (!type->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && + return (type->IsDescendantOf(RUNTIME_CLASS(DStaticEventHandler)) && // make sure it's from our hierarchy at all. + !type->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); } +void E_SerializeEvents(FSerializer& arc) +{ + // todo : stuff +} + static void E_InitStaticHandler(PClass* type, FString typestring, bool map) { if (type == nullptr) @@ -136,24 +142,6 @@ void E_RenderFrame() handler->RenderFrame(); } -void E_RenderCamera() -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->RenderCamera(); -} - -void E_RenderBeforeThing(AActor* thing) -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->RenderBeforeThing(thing); -} - -void E_RenderAfterThing(AActor* thing) -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->RenderAfterThing(thing); -} - // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); IMPLEMENT_CLASS(DStaticRenderEventHandler, false, false); @@ -166,7 +154,6 @@ DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPitch); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewRoll); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, FracTic); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, Camera); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, CurrentThing); DEFINE_ACTION_FUNCTION(DEventHandler, Create) @@ -246,9 +233,6 @@ void cls::funcname(args) \ DEFINE_EVENT_HANDLER(DStaticEventHandler, MapLoaded,) DEFINE_EVENT_HANDLER(DStaticEventHandler, MapUnloading,) DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderCamera,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderBeforeThing, AActor*) -DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderAfterThing, AActor*) // void DStaticEventHandler::OnDestroy() @@ -273,20 +257,3 @@ void DStaticRenderEventHandler::RenderFrame() DStaticEventHandler::RenderFrame(); } -void DStaticRenderEventHandler::RenderCamera() -{ - Setup(); - DStaticEventHandler::RenderCamera(); -} - -void DStaticRenderEventHandler::RenderBeforeThing(AActor* thing) -{ - CurrentThing = thing; - DStaticEventHandler::RenderBeforeThing(thing); -} - -void DStaticRenderEventHandler::RenderAfterThing(AActor* thing) -{ - CurrentThing = thing; - DStaticEventHandler::RenderAfterThing(thing); -} \ No newline at end of file diff --git a/src/events.h b/src/events.h index 8be072735..4ea37c513 100755 --- a/src/events.h +++ b/src/events.h @@ -2,6 +2,7 @@ #define EVENTS_H #include "dobject.h" +#include "serializer.h" class DStaticEventHandler; @@ -22,12 +23,9 @@ void E_MapLoaded(); void E_MapUnloading(); // called on each render frame once. void E_RenderFrame(); -// called before entering each actor's view (including RenderFrame) -void E_RenderCamera(); -// called before adding each actor to the render list -void E_RenderBeforeThing(AActor* thing); -// called after adding each actor to the render list -void E_RenderAfterThing(AActor* thing); + +// serialization stuff +void E_SerializeEvents(FSerializer& arc); class DStaticEventHandler : public DObject // make it a part of normal GC process { @@ -52,12 +50,6 @@ public: virtual void MapUnloading(); // called on each render frame once. virtual void RenderFrame(); - // called before entering each actor's view (including RenderFrame) - virtual void RenderCamera(); - // called before adding each actor to the render list - virtual void RenderBeforeThing(AActor* thing); - // called after adding each actor to the render list - virtual void RenderAfterThing(AActor* thing); }; class DEventHandler : public DStaticEventHandler { @@ -77,33 +69,9 @@ public: DAngle ViewPitch; DAngle ViewRoll; double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. - // this makes sense in RenderCamera AActor* Camera; - // this is for RenderBeforeThing and RenderAfterThing - AActor* CurrentThing; void RenderFrame() override; - void RenderCamera() override; - void RenderBeforeThing(AActor* thing) override; - void RenderAfterThing(AActor* thing) override; - - // this is a class that I use to automatically call RenderAfterThing. - // C++ is really horrible for not providing try-finally statement. - struct AutoThing - { - AActor* thing; - - AutoThing(AActor* thing) - { - this->thing = thing; - E_RenderBeforeThing(this->thing); - } - - ~AutoThing() - { - E_RenderAfterThing(this->thing); - } - }; private: void Setup(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index f3b37ffb5..870af02dd 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -478,9 +478,6 @@ void FGLRenderer::RenderTranslucent() void FGLRenderer::DrawScene(int drawmode) { - // [ZZ] call event hook - E_RenderCamera(); - static int recursion=0; static int ssao_portals_available = 0; diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index e2dc6feff..9ca52e18f 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -650,8 +650,6 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal) if (thing == nullptr) return; - DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); - // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 04c35d157..7a660129b 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -63,6 +63,7 @@ #include "r_renderer.h" #include "serializer.h" #include "g_levellocals.h" +#include "events.h" static TStaticArray loadsectors; static TStaticArray loadlines; @@ -967,6 +968,8 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) arc("sectorportals", level.sectorPortals); if (arc.isReading()) P_CollectLinkedPortals(); + // [ZZ] serialize events + E_SerializeEvents(arc); DThinker::SerializeThinkers(arc, !hubload); arc.Array("polyobjs", polyobjs, po_NumPolyobjs); arc("subsectors", subsectors); diff --git a/src/r_main.cpp b/src/r_main.cpp index 1ae22ba3f..4a8e796ad 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -720,9 +720,6 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) R_CopyStackedViewParameters(); - // [ZZ] portal hook - E_RenderCamera(); - validcount++; PortalDrawseg* prevpds = CurrentPortal; CurrentPortal = pds; @@ -844,9 +841,6 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) R_SetupBuffer (); R_SetupFrame (actor); - // [ZZ] call event hook - E_RenderCamera(); - // Clear buffers. R_ClearClipSegs (0, viewwidth); R_ClearDrawSegs (); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index b452d97a0..62730e731 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1179,8 +1179,6 @@ void R_DrawPortals () R_SetViewAngle (); validcount++; // Make sure we see all sprites - E_RenderCamera(); - R_ClearPlanes (false); R_ClearClipSegs (pl->left, pl->right); WindowLeft = pl->left; diff --git a/src/r_things.cpp b/src/r_things.cpp index a4709b483..a468e4c58 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -1245,8 +1245,6 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) if (thing->validcount == validcount) continue; thing->validcount = validcount; - DStaticRenderEventHandler::AutoThing autoRenderThingEvent(thing); - FIntCVar *cvar = thing->GetClass()->distancecheck; if (cvar != NULL && *cvar >= 0) { From 3e093a20ff698a3ab3cab3627b2b74fd9cfe8d61 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 24 Jan 2017 00:17:12 +0200 Subject: [PATCH 26/69] First take at serialization --- src/c_console.cpp | 10 ++++ src/events.cpp | 84 ++++++++++++++++++++++++-------- src/events.h | 47 ++++++++++++++---- src/g_level.cpp | 13 +++-- src/p_spec.cpp | 2 + src/scripting/thingdef_data.cpp | 2 +- wadsrc/static/zscript/base.txt | 1 + wadsrc/static/zscript/events.txt | 12 ++--- 8 files changed, 128 insertions(+), 43 deletions(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index a9cd97557..649559966 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -69,6 +69,8 @@ #include "c_consolebuffer.h" #include "g_levellocals.h" +FString FStringFormat(VM_ARGS); // extern from thingdef_data.cpp + #include "gi.h" #define LEFTMARGIN 8 @@ -1332,6 +1334,14 @@ DEFINE_ACTION_FUNCTION(_Console, HideConsole) return 0; } +DEFINE_ACTION_FUNCTION(_Console, Printf) +{ + PARAM_PROLOGUE; + FString s = FStringFormat(param, defaultparam, numparam, ret, numret); + Printf("%s", s); + return 0; +} + static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer) { int data1 = ev->data1; diff --git a/src/events.cpp b/src/events.cpp index 60e2e3a49..b80aac2ef 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -61,6 +61,53 @@ bool E_IsStaticType(PClass* type) void E_SerializeEvents(FSerializer& arc) { // todo : stuff + if (arc.BeginArray("eventhandlers")) + { + int numlocalhandlers = 0; + TArray handlers; + if (arc.isReading()) + { + numlocalhandlers = arc.ArraySize(); + // delete all current local handlers, if any + for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next) + if (!lhandler->IsStatic()) lhandler->Destroy(); + } + else + { + for (DStaticEventHandler* lhandler = E_FirstEventHandler; lhandler; lhandler = lhandler->next) + { + if (lhandler->IsStatic()) continue; + numlocalhandlers++; + handlers.Push(lhandler); + } + } + + for (int i = 0; i < numlocalhandlers; i++) + { + // serialize the object properly. + if (arc.isReading()) + { + // get object and put it into the array + DStaticEventHandler* lhandler; + arc(nullptr, lhandler); + if (lhandler != nullptr) + handlers.Push(lhandler); + } + else + { + ::Serialize(arc, nullptr, handlers[i], nullptr); + } + } + + if (arc.isReading()) + { + // add all newly deserialized handlers into the list + for (int i = 0; i < numlocalhandlers; i++) + E_RegisterHandler(handlers[i]); + } + + arc.EndArray(); + } } static void E_InitStaticHandler(PClass* type, FString typestring, bool map) @@ -124,23 +171,17 @@ void E_InitStaticHandlers(bool map) } } -void E_MapLoaded() -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->MapLoaded(); +#define DEFINE_EVENT_LOOPER(name) void E_##name() \ +{ \ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) \ + handler->name(); \ } -void E_MapUnloading() -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->MapUnloading(); -} - -void E_RenderFrame() -{ - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->RenderFrame(); -} +DEFINE_EVENT_LOOPER(WorldLoaded) +DEFINE_EVENT_LOOPER(WorldUnloading) +DEFINE_EVENT_LOOPER(WorldLoadedUnsafe) +DEFINE_EVENT_LOOPER(WorldUnloadingUnsafe) +DEFINE_EVENT_LOOPER(RenderFrame) // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); @@ -230,15 +271,17 @@ void cls::funcname(args) \ } \ } -DEFINE_EVENT_HANDLER(DStaticEventHandler, MapLoaded,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, MapUnloading,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoaded,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloading,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoadedUnsafe, ) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloadingUnsafe, ) +DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame, ) // void DStaticEventHandler::OnDestroy() { E_UnregisterHandler(this); - DObject::OnDestroy(); + Super::OnDestroy(); } void DStaticRenderEventHandler::Setup() @@ -254,6 +297,5 @@ void DStaticRenderEventHandler::Setup() void DStaticRenderEventHandler::RenderFrame() { Setup(); - DStaticEventHandler::RenderFrame(); + Super::RenderFrame(); } - diff --git a/src/events.h b/src/events.h index 4ea37c513..d7ceb4056 100755 --- a/src/events.h +++ b/src/events.h @@ -18,9 +18,13 @@ bool E_IsStaticType(PClass* type); void E_InitStaticHandlers(bool map); // called right after the map has loaded (approximately same time as OPEN ACS scripts) -void E_MapLoaded(); +void E_WorldLoaded(); // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) -void E_MapUnloading(); +void E_WorldUnloading(); +// called right after the map has loaded (every time, UNSAFE VERSION) +void E_WorldLoadedUnsafe(); +// called right before the map is unloaded (every time, UNSAFE VERSION) +void E_WorldUnloadingUnsafe(); // called on each render frame once. void E_RenderFrame(); @@ -38,17 +42,28 @@ public: bool isMapScope; // this is only used with IsStatic=true virtual bool IsStatic() { return true; } + // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields + void Serialize(FSerializer& arc) override + { + Super::Serialize(arc); + if (arc.isReading()) + { + Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); + } + else + { + Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars()); + } + /* do nothing */ + } + // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; - // this checks if we are /actually/ static, using DObject dynamic typing system. - static bool IsActuallyStatic(PClass* type); - - // called right after the map has loaded (approximately same time as OPEN ACS scripts) - virtual void MapLoaded(); - // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) - virtual void MapUnloading(); - // called on each render frame once. + virtual void WorldLoaded(); + virtual void WorldUnloading(); + virtual void WorldLoadedUnsafe(); + virtual void WorldUnloadingUnsafe(); virtual void RenderFrame(); }; class DEventHandler : public DStaticEventHandler @@ -71,6 +86,18 @@ public: double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. AActor* Camera; + // serialization handler for our local stuff + void Serialize(FSerializer& arc) override + { + Super::Serialize(arc); + arc("ViewPos", ViewPos); + arc("ViewAngle", ViewAngle); + arc("ViewPitch", ViewPitch); + arc("ViewRoll", ViewRoll); + arc("FracTic", FracTic); + arc("Camera", Camera); + } + void RenderFrame() override; private: diff --git a/src/g_level.cpp b/src/g_level.cpp index ec4e3049e..06fc40ff9 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -407,6 +407,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel) bool wantFast; int i; + // did we have any level before? + if (level.info != nullptr) + E_WorldUnloadingUnsafe(); + if (!savegamerestore) { G_ClearHubInfo(); @@ -656,7 +660,10 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill // [RH] Give scripts a chance to do something unloading = true; FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true); - E_MapUnloading(); + // [ZZ] safe world unload + E_WorldUnloading(); + // [ZZ] unsafe world unload (changemap != map) + E_WorldUnloadingUnsafe(); unloading = false; STAT_ChangeLevel(nextlevel); @@ -1068,8 +1075,8 @@ void G_DoLoadLevel (int position, bool autosave) StatusBar->AttachToPlayer (&players[consoleplayer]); // [ZZ] init per-map static handlers E_InitStaticHandlers(true); - // call map load hook - E_MapLoaded(); + // unsafe world load + E_WorldLoadedUnsafe(); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 0eb619723..b52166347 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1443,6 +1443,8 @@ void P_SpawnSpecials (void) break; } } + // [ZZ] safe world load + E_WorldLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9fa33314e..d349691c6 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -945,7 +945,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Replace) return 0; } -static FString FStringFormat(VM_ARGS) +FString FStringFormat(VM_ARGS) { assert(param[0].Type == REGT_STRING); FString fmtstring = param[0].s().GetChars(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index a1177289e..55da329c9 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -41,6 +41,7 @@ struct Console native { native static void HideConsole(); native static void MidPrint(string fontname, string textlabel, bool bold = false); // always uses the stringtable. + native static vararg void Printf(string fmt, ...); } struct DamageTypeDefinition native diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 6d0be8cf5..80c022efb 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,12 +1,11 @@ class StaticEventHandler : Object native { - virtual native void MapLoaded(); - virtual native void MapUnloading(); + virtual native void WorldLoaded(); + virtual native void WorldLoadedUnsafe(); + virtual native void WorldUnloading(); + virtual native void WorldUnloadingUnsafe(); virtual native void RenderFrame(); - virtual native void RenderCamera(); - virtual native void RenderBeforeThing(); - virtual native void RenderAfterThing(); } class StaticRenderEventHandler : StaticEventHandler native @@ -17,10 +16,7 @@ class StaticRenderEventHandler : StaticEventHandler native native readonly double ViewPitch; native readonly double ViewRoll; native readonly double FracTic; - // for camera native readonly Actor Camera; - // for thing - native readonly Actor CurrentThing; } class EventHandler : StaticEventHandler native From 09ca1f610dc7d6c32c6633bc3626fbe2f127555b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 07:50:09 +0200 Subject: [PATCH 27/69] Removed World*Unsafe handlers (merged with WorldLoaded/WorldUnloading); Removed the concept of 'map-local static' handlers, static handlers are now only those that run globally. --- src/events.cpp | 83 +++++++++++++++++++++++--------- src/events.h | 14 ++++-- src/g_level.cpp | 2 + src/p_spec.cpp | 2 - wadsrc/static/zscript/events.txt | 2 - 5 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index b80aac2ef..81461f73a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -19,7 +19,10 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->next) handler->next->prev = handler; E_FirstEventHandler = handler; - if (handler->IsStatic() && !handler->isMapScope) handler->ObjectFlags |= OF_Fixed; + if (handler->IsStatic()) + { + handler->ObjectFlags |= OF_Fixed; + } return true; } @@ -36,10 +39,10 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; - if (handler->IsStatic() && !handler->isMapScope) + if (handler->IsStatic()) { - handler->ObjectFlags |= OF_YesReallyDelete; - delete handler; + handler->ObjectFlags &= ~OF_Fixed; + handler->Destroy(); } return true; } @@ -114,13 +117,13 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) { if (type == nullptr) { - Printf("%cGWarning: unknown event handler class %s in MAPINFO!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + Printf("%cGWarning: unknown event handler class %s in MAPINFO!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); return; } - if (!E_IsStaticType(type)) + if (!E_IsStaticType(type) && !map) { - Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!", TEXTCOLOR_ESCAPE, typestring.GetChars()); + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nGameInfo event handlers should inherit Static* directly!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); return; } @@ -137,21 +140,15 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) if (typeExists) return; DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); - handler->isMapScope = map; E_RegisterHandler(handler); } void E_InitStaticHandlers(bool map) { - // remove existing - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { - if (handler->IsStatic() && handler->isMapScope == map) - handler->Destroy(); - } + if (savegamerestore) + return; - // add new - if (map) + if (map) // don't initialize map handlers if restoring from savegame. { for (unsigned int i = 0; i < level.info->EventHandlers.Size(); i++) { @@ -162,6 +159,13 @@ void E_InitStaticHandlers(bool map) } else { + // delete old static handlers if any. + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic()) + handler->Destroy(); + } + for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) { FString typestring = gameinfo.EventHandlers[i]; @@ -177,10 +181,47 @@ void E_InitStaticHandlers(bool map) handler->name(); \ } -DEFINE_EVENT_LOOPER(WorldLoaded) -DEFINE_EVENT_LOOPER(WorldUnloading) -DEFINE_EVENT_LOOPER(WorldLoadedUnsafe) -DEFINE_EVENT_LOOPER(WorldUnloadingUnsafe) +// note for the functions below. +// *Unsafe is executed on EVERY map load/close, including savegame loading, etc. +// There is no point in allowing non-static handlers to receive unsafe event separately, as there is no point in having static handlers receive safe event. +// Because the main point of safe WorldLoaded/Unloading is that it will be preserved in savegames. +void E_WorldLoaded() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic()) continue; + if (handler->isFromSaveGame) continue; // don't execute WorldLoaded for handlers loaded from the savegame. + handler->WorldLoaded(); + } +} + +void E_WorldUnloading() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic()) continue; + handler->WorldUnloading(); + } +} + +void E_WorldLoadedUnsafe() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (!handler->IsStatic()) continue; + handler->WorldLoaded(); + } +} + +void E_WorldUnloadingUnsafe() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (!handler->IsStatic()) continue; + handler->WorldUnloading(); + } +} + DEFINE_EVENT_LOOPER(RenderFrame) // declarations @@ -273,8 +314,6 @@ void cls::funcname(args) \ DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoaded,) DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloading,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoadedUnsafe, ) -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloadingUnsafe, ) DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame, ) // diff --git a/src/events.h b/src/events.h index d7ceb4056..b8adffd48 100755 --- a/src/events.h +++ b/src/events.h @@ -35,11 +35,16 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces { DECLARE_CLASS(DStaticEventHandler, DObject) public: + DStaticEventHandler() + { + prev = 0; + next = 0; + isFromSaveGame = false; + } + DStaticEventHandler* prev; DStaticEventHandler* next; - DStaticEventHandler* unregPrev; - DStaticEventHandler* unregNext; - bool isMapScope; // this is only used with IsStatic=true + bool isFromSaveGame; // this gets set to true if this object was received using serializator virtual bool IsStatic() { return true; } // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields @@ -49,6 +54,7 @@ public: if (arc.isReading()) { Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); + isFromSaveGame = true; } else { @@ -62,8 +68,6 @@ public: virtual void WorldLoaded(); virtual void WorldUnloading(); - virtual void WorldLoadedUnsafe(); - virtual void WorldUnloadingUnsafe(); virtual void RenderFrame(); }; class DEventHandler : public DStaticEventHandler diff --git a/src/g_level.cpp b/src/g_level.cpp index 06fc40ff9..0310b3846 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1077,6 +1077,8 @@ void G_DoLoadLevel (int position, bool autosave) E_InitStaticHandlers(true); // unsafe world load E_WorldLoadedUnsafe(); + // regular world load (savegames are handled internally) + E_WorldLoaded(); P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map. if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index b52166347..0eb619723 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1443,8 +1443,6 @@ void P_SpawnSpecials (void) break; } } - // [ZZ] safe world load - E_WorldLoaded(); // [RH] Start running any open scripts on this map FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false); } diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 80c022efb..c604101ce 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,9 +1,7 @@ class StaticEventHandler : Object native { virtual native void WorldLoaded(); - virtual native void WorldLoadedUnsafe(); virtual native void WorldUnloading(); - virtual native void WorldUnloadingUnsafe(); virtual native void RenderFrame(); } From fd282d3001a6efd2fecbde17cf29ff34344ead8a Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 08:19:38 +0200 Subject: [PATCH 28/69] Fixed map/global static handlers; map handlers should not receive WorldLoaded/WorldUnloaded on load/save anymore. --- src/events.cpp | 24 ++++++++++++++++-------- src/events.h | 6 +++--- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 81461f73a..a4ff68836 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -121,9 +121,9 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) return; } - if (!E_IsStaticType(type) && !map) + if (!E_IsStaticType(type)) { - Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nGameInfo event handlers should inherit Static* directly!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); + Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); return; } @@ -140,6 +140,7 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) if (typeExists) return; DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); + handler->isMapScope = map; E_RegisterHandler(handler); } @@ -150,6 +151,13 @@ void E_InitStaticHandlers(bool map) if (map) // don't initialize map handlers if restoring from savegame. { + // delete old map static handlers if any. + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic() && handler->isMapScope) + handler->Destroy(); + } + for (unsigned int i = 0; i < level.info->EventHandlers.Size(); i++) { FString typestring = level.info->EventHandlers[i]; @@ -162,7 +170,7 @@ void E_InitStaticHandlers(bool map) // delete old static handlers if any. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic()) + if (handler->IsStatic() && !handler->isMapScope) handler->Destroy(); } @@ -189,8 +197,8 @@ void E_WorldLoaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic()) continue; - if (handler->isFromSaveGame) continue; // don't execute WorldLoaded for handlers loaded from the savegame. + if (handler->IsStatic() && !handler->isMapScope) continue; + if (handler->isMapScope && savegamerestore) continue; // don't execute WorldLoaded for handlers loaded from the savegame. handler->WorldLoaded(); } } @@ -199,7 +207,7 @@ void E_WorldUnloading() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic()) continue; + if (handler->IsStatic() && !handler->isMapScope) continue; handler->WorldUnloading(); } } @@ -208,7 +216,7 @@ void E_WorldLoadedUnsafe() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (!handler->IsStatic()) continue; + if (!handler->IsStatic() || handler->isMapScope) continue; handler->WorldLoaded(); } } @@ -217,7 +225,7 @@ void E_WorldUnloadingUnsafe() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (!handler->IsStatic()) continue; + if (!handler->IsStatic() || handler->isMapScope) continue; handler->WorldUnloading(); } } diff --git a/src/events.h b/src/events.h index b8adffd48..172d14485 100755 --- a/src/events.h +++ b/src/events.h @@ -39,12 +39,12 @@ public: { prev = 0; next = 0; - isFromSaveGame = false; + isMapScope = false; } DStaticEventHandler* prev; DStaticEventHandler* next; - bool isFromSaveGame; // this gets set to true if this object was received using serializator + bool isMapScope; virtual bool IsStatic() { return true; } // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields @@ -54,7 +54,7 @@ public: if (arc.isReading()) { Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); - isFromSaveGame = true; + isMapScope = true; // unserialized static handler means map scope anyway. other handlers don't get serialized. } else { From 0598c18ad8cc5a90bf08e1626331fc230b2fb288 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 08:47:15 +0200 Subject: [PATCH 29/69] Added WorldEventHandler with WorldThingSpawned. WorldThingDestroyed is not implemented because you already can attach an object that would check master's state. --- src/events.cpp | 48 +++++++++++++++++++--- src/events.h | 70 ++++++++++++++++++++++++++++++-- src/g_level.cpp | 6 +-- wadsrc/static/zscript/events.txt | 10 ++++- 4 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index a4ff68836..f1601911e 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -203,12 +203,12 @@ void E_WorldLoaded() } } -void E_WorldUnloading() +void E_WorldUnloaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { if (handler->IsStatic() && !handler->isMapScope) continue; - handler->WorldUnloading(); + handler->WorldUnloaded(); } } @@ -221,22 +221,31 @@ void E_WorldLoadedUnsafe() } } -void E_WorldUnloadingUnsafe() +void E_WorldUnloadedUnsafe() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { if (!handler->IsStatic() || handler->isMapScope) continue; - handler->WorldUnloading(); + handler->WorldUnloaded(); } } +void E_WorldThingSpawned(AActor* actor) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingSpawned(actor); +} + +// normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); IMPLEMENT_CLASS(DStaticRenderEventHandler, false, false); +IMPLEMENT_CLASS(DStaticWorldEventHandler, false, false); IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DRenderEventHandler, false, false); +IMPLEMENT_CLASS(DWorldEventHandler, false, false); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPos); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewAngle); @@ -245,6 +254,9 @@ DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewRoll); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, FracTic); DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, Camera); +DEFINE_FIELD_X(StaticWorldEventHandler, DStaticWorldEventHandler, IsSaveGame); +DEFINE_FIELD_X(StaticWorldEventHandler, DStaticWorldEventHandler, Thing); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { @@ -321,7 +333,8 @@ void cls::funcname(args) \ } DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoaded,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloading,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloaded,) +DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldThingSpawned, AActor*) DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame, ) // @@ -346,3 +359,28 @@ void DStaticRenderEventHandler::RenderFrame() Setup(); Super::RenderFrame(); } + +void DStaticWorldEventHandler::Setup() +{ + IsSaveGame = savegamerestore; + Thing = nullptr; +} + +void DStaticWorldEventHandler::WorldLoaded() +{ + Setup(); + Super::WorldLoaded(); +} + +void DStaticWorldEventHandler::WorldUnloaded() +{ + Setup(); + Super::WorldUnloaded(); +} + +void DStaticWorldEventHandler::WorldThingSpawned(AActor* actor) +{ + Setup(); + Thing = actor; + Super::WorldThingSpawned(actor); +} \ No newline at end of file diff --git a/src/events.h b/src/events.h index 172d14485..fa9b16c32 100755 --- a/src/events.h +++ b/src/events.h @@ -20,17 +20,25 @@ void E_InitStaticHandlers(bool map); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_WorldLoaded(); // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) -void E_WorldUnloading(); +void E_WorldUnloaded(); // called right after the map has loaded (every time, UNSAFE VERSION) void E_WorldLoadedUnsafe(); // called right before the map is unloaded (every time, UNSAFE VERSION) -void E_WorldUnloadingUnsafe(); +void E_WorldUnloadedUnsafe(); +// called around PostBeginPlay of each actor. +void E_WorldThingSpawned(AActor* actor); // called on each render frame once. void E_RenderFrame(); // serialization stuff void E_SerializeEvents(FSerializer& arc); +// ============================================== +// +// EventHandler - base class +// +// ============================================== + class DStaticEventHandler : public DObject // make it a part of normal GC process { DECLARE_CLASS(DStaticEventHandler, DObject) @@ -67,7 +75,8 @@ public: void OnDestroy() override; virtual void WorldLoaded(); - virtual void WorldUnloading(); + virtual void WorldUnloaded(); + virtual void WorldThingSpawned(AActor*); virtual void RenderFrame(); }; class DEventHandler : public DStaticEventHandler @@ -78,6 +87,13 @@ public: }; extern DStaticEventHandler* E_FirstEventHandler; + +// ============================================== +// +// RenderEventHandler - for renderer events +// +// ============================================== + class DStaticRenderEventHandler : public DStaticEventHandler { DECLARE_CLASS(DStaticRenderEventHandler, DStaticEventHandler) @@ -90,6 +106,12 @@ public: double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. AActor* Camera; + DStaticRenderEventHandler() + { + FracTic = 0; + Camera = nullptr; + } + // serialization handler for our local stuff void Serialize(FSerializer& arc) override { @@ -114,4 +136,46 @@ public: bool IsStatic() override { return false; } }; +// ============================================== +// +// WorldEventHandler - for world events +// +// ============================================== +class DStaticWorldEventHandler : public DStaticEventHandler +{ + DECLARE_CLASS(DStaticWorldEventHandler, DStaticEventHandler) +public: + // for WorldLoaded, WorldUnloaded. + bool IsSaveGame; // this will be true if world event was triggered during savegame loading. + // for WorldThingSpawned + AActor* Thing; + + DStaticWorldEventHandler() + { + IsSaveGame = false; + Thing = nullptr; + } + + void Serialize(FSerializer& arc) override + { + Super::Serialize(arc); + arc("IsSaveGame", IsSaveGame); + arc("Thing", Thing); + } + + void WorldLoaded() override; + void WorldUnloaded() override; + void WorldThingSpawned(AActor*) override; + +private: + void Setup(); +}; +// not sure if anyone wants non-static world handler, but here it is, just in case. +class DWorldEventHandler : public DStaticWorldEventHandler +{ + DECLARE_CLASS(DWorldEventHandler, DStaticWorldEventHandler) +public: + bool IsStatic() override { return false; } +}; + #endif \ No newline at end of file diff --git a/src/g_level.cpp b/src/g_level.cpp index 0310b3846..19c397437 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -409,7 +409,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) // did we have any level before? if (level.info != nullptr) - E_WorldUnloadingUnsafe(); + E_WorldUnloadedUnsafe(); if (!savegamerestore) { @@ -661,9 +661,9 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill unloading = true; FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true); // [ZZ] safe world unload - E_WorldUnloading(); + E_WorldUnloaded(); // [ZZ] unsafe world unload (changemap != map) - E_WorldUnloadingUnsafe(); + E_WorldUnloadedUnsafe(); unloading = false; STAT_ChangeLevel(nextlevel); diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index c604101ce..e3ee54025 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,7 +1,8 @@ class StaticEventHandler : Object native { virtual native void WorldLoaded(); - virtual native void WorldUnloading(); + virtual native void WorldUnloaded(); + virtual native void WorldThingSpawned(); virtual native void RenderFrame(); } @@ -17,6 +18,13 @@ class StaticRenderEventHandler : StaticEventHandler native native readonly Actor Camera; } +class StaticWorldEventHandler : StaticEventHandler native +{ + // for world + native readonly bool IsSaveGame; // this is set to true if static WorldLoaded was triggered during savegame loading. + native readonly Actor Thing; // this is for WorldThingSpawned +} + class EventHandler : StaticEventHandler native { static native StaticEventHandler Create(class type); From 83f868a04971cfe2e41074b25bb70a50dce0d283 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 09:10:33 +0200 Subject: [PATCH 30/69] Implemented WorldThingSpawned hook. Also changed Console.Printf to automatically add \n. Also fixed vararg calls with names. --- src/actor.h | 3 +++ src/c_console.cpp | 2 +- src/dthinker.h | 2 +- src/events.cpp | 4 ++++ src/p_mobj.cpp | 7 +++++++ src/scripting/codegeneration/codegen.cpp | 5 +++-- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/actor.h b/src/actor.h index d83446827..08684bde1 100644 --- a/src/actor.h +++ b/src/actor.h @@ -627,6 +627,9 @@ public: virtual void BeginPlay(); // Called immediately after the actor is created void CallBeginPlay(); + // [ZZ] custom postbeginplay (calls E_WorldThingSpawned) + void CallPostBeginPlay() override; + void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags. diff --git a/src/c_console.cpp b/src/c_console.cpp index 649559966..eb4c55d02 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1338,7 +1338,7 @@ DEFINE_ACTION_FUNCTION(_Console, Printf) { PARAM_PROLOGUE; FString s = FStringFormat(param, defaultparam, numparam, ret, numret); - Printf("%s", s); + Printf("%s\n", s); return 0; } diff --git a/src/dthinker.h b/src/dthinker.h index e0dcb607f..f86eff266 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -71,7 +71,7 @@ public: virtual void Tick (); void CallTick(); virtual void PostBeginPlay (); // Called just before the first tick - void CallPostBeginPlay(); + virtual void CallPostBeginPlay(); // different in actor. virtual void PostSerialize(); size_t PropagateMark(); diff --git a/src/events.cpp b/src/events.cpp index f1601911e..e61dd019a 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -4,6 +4,7 @@ #include "g_levellocals.h" #include "gi.h" #include "v_text.h" +#include "actor.h" DStaticEventHandler* E_FirstEventHandler = nullptr; @@ -232,6 +233,9 @@ void E_WorldUnloadedUnsafe() void E_WorldThingSpawned(AActor* actor) { + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->WorldThingSpawned(actor); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index df6223242..b94098607 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -71,6 +71,7 @@ #include "virtual.h" #include "g_levellocals.h" #include "a_morph.h" +#include "events.h" // MACROS ------------------------------------------------------------------ @@ -4970,6 +4971,12 @@ void AActor::PostBeginPlay () flags7 |= MF7_HANDLENODELAY; } +void AActor::CallPostBeginPlay() +{ + Super::CallPostBeginPlay(); + E_WorldThingSpawned(this); +} + void AActor::MarkPrecacheSounds() const { SeeSound.MarkUsed(); diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8fd95c411..73a9ba1da 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8206,9 +8206,10 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (x) { if (x->ValueType == TypeName || - x->ValueType == TypeSound) + x->ValueType == TypeSound || + x->ValueType == TypeSpriteID) // spriteID can be a string too. { - x = new FxStringCast(ArgList[i]); + x = new FxStringCast(x); x = x->Resolve(ctx); } } From 414d16a0f7cbe366ea0666af8fcf329078253589 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 09:11:10 +0200 Subject: [PATCH 31/69] Reverted spriteID part - can't be a string --- src/scripting/codegeneration/codegen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 73a9ba1da..c05065802 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -8206,8 +8206,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if (x) { if (x->ValueType == TypeName || - x->ValueType == TypeSound || - x->ValueType == TypeSpriteID) // spriteID can be a string too. + x->ValueType == TypeSound) // spriteID can be a string too. { x = new FxStringCast(x); x = x->Resolve(ctx); From e8a0eda47643d94137ae595e980df9b0adbbd8d3 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 09:19:42 +0200 Subject: [PATCH 32/69] AddEventHandlers in GameInfo --- src/gi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gi.cpp b/src/gi.cpp index b1e0b1cf2..9f6827ab4 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -317,6 +317,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRINGARRAY(PrecachedClasses, "precacheclasses", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedTextures, "precachetextures", 0, false) GAMEINFOKEY_STRINGARRAY(PrecachedSounds, "precachesounds", 0, false) + GAMEINFOKEY_STRINGARRAY(EventHandlers, "addeventhandlers", 0, true) GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, false) GAMEINFOKEY_STRING(PauseSign, "pausesign") GAMEINFOKEY_STRING(quitSound, "quitSound") From c7e3ff235681419f7bd72cb9e0f17fdfcf5d1fbd Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 09:28:27 +0200 Subject: [PATCH 33/69] Static event handlers can create/register/unregister other static event handlers. --- src/events.cpp | 39 +++++++++++++++++++++++++++++++- wadsrc/static/zscript/events.txt | 8 +++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index e61dd019a..f296144d9 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -289,7 +289,30 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) // check if there are already registered handlers of this type. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) if (handler->GetClass() == t) // check precise class - ACTION_RETURN_OBJECT(nullptr); + ACTION_RETURN_OBJECT(handler); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +// for static +DEFINE_ACTION_FUNCTION(DStaticEventHandler, Create) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DStaticEventHandler); + // static handlers can create any type of object. + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DStaticEventHandler, CreateOnce) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DStaticEventHandler); + // static handlers can create any type of object. + // check if there are already registered handlers of this type. + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(handler); // generate a new object of this type. ACTION_RETURN_OBJECT(t->CreateNew()); } @@ -320,6 +343,20 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } +DEFINE_ACTION_FUNCTION(DStaticEventHandler, Register) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DStaticEventHandler); + ACTION_RETURN_BOOL(E_RegisterHandler(handler)); +} + +DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DStaticEventHandler); + ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); +} + #define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ { \ PARAM_SELF_PROLOGUE(cls); \ diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index e3ee54025..85a662e3a 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,5 +1,13 @@ class StaticEventHandler : Object native { + // static event handlers CAN register other static event handlers. + // unlike EventHandler.Create that will not create them. + protected static native StaticEventHandler Create(class type); + protected static native StaticEventHandler CreateOnce(class type); + + protected static native bool Register(StaticEventHandler handler); + protected static native bool Unregister(StaticEventHandler handler); + virtual native void WorldLoaded(); virtual native void WorldUnloaded(); virtual native void WorldThingSpawned(); From 2382a76be5efa0f06e65cc97d7e61a0a72d3be71 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 09:33:06 +0200 Subject: [PATCH 34/69] Made separate .Find in Static handlers for convenience. --- src/events.cpp | 57 +++++++++++++++++++------------- wadsrc/static/zscript/events.txt | 1 + 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index f296144d9..30a699ee2 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -294,29 +294,6 @@ DEFINE_ACTION_FUNCTION(DEventHandler, CreateOnce) ACTION_RETURN_OBJECT(t->CreateNew()); } -// for static -DEFINE_ACTION_FUNCTION(DStaticEventHandler, Create) -{ - PARAM_PROLOGUE; - PARAM_CLASS(t, DStaticEventHandler); - // static handlers can create any type of object. - // generate a new object of this type. - ACTION_RETURN_OBJECT(t->CreateNew()); -} - -DEFINE_ACTION_FUNCTION(DStaticEventHandler, CreateOnce) -{ - PARAM_PROLOGUE; - PARAM_CLASS(t, DStaticEventHandler); - // static handlers can create any type of object. - // check if there are already registered handlers of this type. - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - if (handler->GetClass() == t) // check precise class - ACTION_RETURN_OBJECT(handler); - // generate a new object of this type. - ACTION_RETURN_OBJECT(t->CreateNew()); -} - DEFINE_ACTION_FUNCTION(DEventHandler, Find) { PARAM_PROLOGUE; @@ -343,6 +320,40 @@ DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } +// for static +DEFINE_ACTION_FUNCTION(DStaticEventHandler, Create) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DStaticEventHandler); + // static handlers can create any type of object. + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DStaticEventHandler, CreateOnce) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DStaticEventHandler); + // static handlers can create any type of object. + // check if there are already registered handlers of this type. + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(handler); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +// we might later want to change this +DEFINE_ACTION_FUNCTION(DStaticEventHandler, Find) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DStaticEventHandler); + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->GetClass() == t) // check precise class + ACTION_RETURN_OBJECT(handler); + ACTION_RETURN_OBJECT(nullptr); +} + DEFINE_ACTION_FUNCTION(DStaticEventHandler, Register) { PARAM_PROLOGUE; diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 85a662e3a..e5b878603 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -4,6 +4,7 @@ class StaticEventHandler : Object native // unlike EventHandler.Create that will not create them. protected static native StaticEventHandler Create(class type); protected static native StaticEventHandler CreateOnce(class type); + protected static native StaticEventHandler Find(Class type); // just for convenience. who knows. protected static native bool Register(StaticEventHandler handler); protected static native bool Unregister(StaticEventHandler handler); From 5751f843509d59cb4e933baa1a93974bdb68c8c0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 30 Jan 2017 11:56:03 +0200 Subject: [PATCH 35/69] Moved empty virtual methods to script side --- src/events.cpp | 9 +------- wadsrc/static/zscript/events.txt | 35 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 30a699ee2..c75abdf87 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -368,17 +368,10 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister) ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } -#define DEFINE_EVENT_HANDLER(cls, funcname, args) DEFINE_ACTION_FUNCTION(cls, funcname) \ -{ \ - PARAM_SELF_PROLOGUE(cls); \ - return 0; \ -} \ -void cls::funcname(args) \ +#define DEFINE_EVENT_HANDLER(cls, funcname, args) void cls::funcname(args) \ { \ IFVIRTUAL(cls, funcname) \ { \ - if (func == cls##_##funcname##_VMPtr) \ - return; \ VMValue params[1] = { (cls*)this }; \ GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); \ } \ diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index e5b878603..8e6b1f682 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -9,22 +9,23 @@ class StaticEventHandler : Object native protected static native bool Register(StaticEventHandler handler); protected static native bool Unregister(StaticEventHandler handler); - virtual native void WorldLoaded(); - virtual native void WorldUnloaded(); - virtual native void WorldThingSpawned(); - - virtual native void RenderFrame(); + // world stuff + virtual void WorldLoaded() {} + virtual void WorldUnloaded() {} + virtual void WorldThingSpawned() {} + // render stuff + virtual void RenderFrame() {} } class StaticRenderEventHandler : StaticEventHandler native { - // for frame and camera - native readonly Vector3 ViewPos; - native readonly double ViewAngle; - native readonly double ViewPitch; - native readonly double ViewRoll; - native readonly double FracTic; - native readonly Actor Camera; + // for frame and camera + native readonly Vector3 ViewPos; + native readonly double ViewAngle; + native readonly double ViewPitch; + native readonly double ViewRoll; + native readonly double FracTic; + native readonly Actor Camera; } class StaticWorldEventHandler : StaticEventHandler native @@ -36,12 +37,12 @@ class StaticWorldEventHandler : StaticEventHandler native class EventHandler : StaticEventHandler native { - static native StaticEventHandler Create(class type); - static native StaticEventHandler CreateOnce(class type); - static native StaticEventHandler Find(class type); + static native StaticEventHandler Create(class type); + static native StaticEventHandler CreateOnce(class type); + static native StaticEventHandler Find(class type); - static native bool Register(StaticEventHandler handler); - static native bool Unregister(StaticEventHandler handler); + static native bool Register(StaticEventHandler handler); + static native bool Unregister(StaticEventHandler handler); } class RenderEventHandler : StaticRenderEventHandler native { } From 27c8140c46a781d9ae88a41228a0e930f24ce2c9 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 01:28:47 +0200 Subject: [PATCH 36/69] Replaced specialized event handlers with Event structure passed to a method; returned the check for virtual implementation to make sure that we don't waste time initializing the event data. --- src/events.cpp | 122 ++++++++++++++++++++++++------- src/events.h | 70 ++++++------------ wadsrc/static/zscript/events.txt | 50 ++++++------- 3 files changed, 145 insertions(+), 97 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index c75abdf87..dc10827dd 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -58,8 +58,7 @@ bool E_CheckHandler(DStaticEventHandler* handler) bool E_IsStaticType(PClass* type) { return (type->IsDescendantOf(RUNTIME_CLASS(DStaticEventHandler)) && // make sure it's from our hierarchy at all. - !type->IsDescendantOf(RUNTIME_CLASS(DEventHandler)) && - !type->IsDescendantOf(RUNTIME_CLASS(DRenderEventHandler))); + !type->IsDescendantOf(RUNTIME_CLASS(DEventHandler))); } void E_SerializeEvents(FSerializer& arc) @@ -245,21 +244,20 @@ DEFINE_EVENT_LOOPER(RenderFrame) // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); -IMPLEMENT_CLASS(DStaticRenderEventHandler, false, false); -IMPLEMENT_CLASS(DStaticWorldEventHandler, false, false); IMPLEMENT_CLASS(DEventHandler, false, false); -IMPLEMENT_CLASS(DRenderEventHandler, false, false); -IMPLEMENT_CLASS(DWorldEventHandler, false, false); +IMPLEMENT_CLASS(DBaseEvent, false, false) +IMPLEMENT_CLASS(DRenderEvent, false, false) +IMPLEMENT_CLASS(DWorldEvent, false, false) -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPos); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewAngle); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewPitch); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, ViewRoll); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, FracTic); -DEFINE_FIELD_X(StaticRenderEventHandler, DStaticRenderEventHandler, Camera); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPitch); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewRoll); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, FracTic); +DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); -DEFINE_FIELD_X(StaticWorldEventHandler, DStaticWorldEventHandler, IsSaveGame); -DEFINE_FIELD_X(StaticWorldEventHandler, DStaticWorldEventHandler, Thing); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); DEFINE_ACTION_FUNCTION(DEventHandler, Create) @@ -368,19 +366,91 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister) ACTION_RETURN_BOOL(E_UnregisterHandler(handler)); } -#define DEFINE_EVENT_HANDLER(cls, funcname, args) void cls::funcname(args) \ +#define DEFINE_EMPTY_HANDLER(cls, funcname) DEFINE_ACTION_FUNCTION(cls, funcname) \ { \ - IFVIRTUAL(cls, funcname) \ - { \ - VMValue params[1] = { (cls*)this }; \ - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); \ - } \ + PARAM_SELF_PROLOGUE(cls); \ + return 0; \ } -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldLoaded,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldUnloaded,) -DEFINE_EVENT_HANDLER(DStaticEventHandler, WorldThingSpawned, AActor*) -DEFINE_EVENT_HANDLER(DStaticEventHandler, RenderFrame, ) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLoaded) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) + +static DWorldEvent* E_SetupWorldEvent() +{ + static DWorldEvent* e = nullptr; + if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew(); + e->IsSaveGame = savegamerestore; + e->Thing = nullptr; + return e; +} + +void DStaticEventHandler::WorldLoaded() +{ + IFVIRTUAL(DStaticEventHandler, WorldLoaded) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldLoaded_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::WorldUnloaded() +{ + IFVIRTUAL(DStaticEventHandler, WorldUnloaded) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldUnloaded_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::WorldThingSpawned(AActor* actor) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingSpawned) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingSpawned_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +static DRenderEvent* E_SetupRenderEvent() +{ + static DRenderEvent* e = nullptr; + if (!e) e = (DRenderEvent*)RUNTIME_CLASS(DRenderEvent)->CreateNew(); + e->ViewPos = ::ViewPos; + e->ViewAngle = ::ViewAngle; + e->ViewPitch = ::ViewPitch; + e->ViewRoll = ::ViewRoll; + e->FracTic = ::r_TicFracF; + e->Camera = ::camera; + return e; +} + +void DStaticEventHandler::RenderFrame() +{ + IFVIRTUAL(DStaticEventHandler, RenderFrame) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_RenderFrame_VMPtr) + return; + DRenderEvent* e = E_SetupRenderEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} // void DStaticEventHandler::OnDestroy() @@ -388,7 +458,7 @@ void DStaticEventHandler::OnDestroy() E_UnregisterHandler(this); Super::OnDestroy(); } - +/* void DStaticRenderEventHandler::Setup() { ViewPos = ::ViewPos; @@ -428,4 +498,4 @@ void DStaticWorldEventHandler::WorldThingSpawned(AActor* actor) Setup(); Thing = actor; Super::WorldThingSpawned(actor); -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/events.h b/src/events.h index fa9b16c32..a012730e6 100755 --- a/src/events.h +++ b/src/events.h @@ -87,16 +87,24 @@ public: }; extern DStaticEventHandler* E_FirstEventHandler; - -// ============================================== -// -// RenderEventHandler - for renderer events -// -// ============================================== - -class DStaticRenderEventHandler : public DStaticEventHandler +// we cannot call this DEvent because in ZScript, 'event' is a keyword +class DBaseEvent : public DObject { - DECLARE_CLASS(DStaticRenderEventHandler, DStaticEventHandler) + DECLARE_CLASS(DBaseEvent, DObject) +public: + + DBaseEvent() + { + // each type of event is created only once to avoid new/delete hell + // since from what I remember object creation and deletion results in a lot of GC processing + // (and we aren't supposed to pass event objects around anyway) + this->ObjectFlags |= OF_Fixed; + } +}; + +class DRenderEvent : public DBaseEvent +{ + DECLARE_CLASS(DRenderEvent, DBaseEvent) public: // these are for all render events DVector3 ViewPos; @@ -106,7 +114,7 @@ public: double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. AActor* Camera; - DStaticRenderEventHandler() + DRenderEvent() { FracTic = 0; Camera = nullptr; @@ -123,34 +131,18 @@ public: arc("FracTic", FracTic); arc("Camera", Camera); } - - void RenderFrame() override; - -private: - void Setup(); -}; -class DRenderEventHandler : public DStaticRenderEventHandler -{ - DECLARE_CLASS(DRenderEventHandler, DStaticRenderEventHandler) // TODO: make sure this does not horribly break anythings -public: - bool IsStatic() override { return false; } }; -// ============================================== -// -// WorldEventHandler - for world events -// -// ============================================== -class DStaticWorldEventHandler : public DStaticEventHandler +class DWorldEvent : public DBaseEvent { - DECLARE_CLASS(DStaticWorldEventHandler, DStaticEventHandler) + DECLARE_CLASS(DWorldEvent, DBaseEvent) public: - // for WorldLoaded, WorldUnloaded. - bool IsSaveGame; // this will be true if world event was triggered during savegame loading. - // for WorldThingSpawned + // for loaded/unloaded + bool IsSaveGame; + // for thingspawned, thingdied, thingdestroyed AActor* Thing; - DStaticWorldEventHandler() + DWorldEvent() { IsSaveGame = false; Thing = nullptr; @@ -162,20 +154,6 @@ public: arc("IsSaveGame", IsSaveGame); arc("Thing", Thing); } - - void WorldLoaded() override; - void WorldUnloaded() override; - void WorldThingSpawned(AActor*) override; - -private: - void Setup(); -}; -// not sure if anyone wants non-static world handler, but here it is, just in case. -class DWorldEventHandler : public DStaticWorldEventHandler -{ - DECLARE_CLASS(DWorldEventHandler, DStaticWorldEventHandler) -public: - bool IsStatic() override { return false; } }; #endif \ No newline at end of file diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 8e6b1f682..3a0e8d5eb 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -1,3 +1,23 @@ +class BaseEvent native { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything. + +class RenderEvent : BaseEvent native +{ + native readonly Vector3 ViewPos; + native readonly double ViewAngle; + native readonly double ViewPitch; + native readonly double ViewRoll; + native readonly double FracTic; + native readonly Actor Camera; +} + +class WorldEvent : BaseEvent native +{ + // for loaded/unloaded + native readonly bool IsSaveGame; + // for thingspawned/thingdied/thingdestroyed + native readonly Actor Thing; +} + class StaticEventHandler : Object native { // static event handlers CAN register other static event handlers. @@ -9,30 +29,12 @@ class StaticEventHandler : Object native protected static native bool Register(StaticEventHandler handler); protected static native bool Unregister(StaticEventHandler handler); - // world stuff - virtual void WorldLoaded() {} - virtual void WorldUnloaded() {} - virtual void WorldThingSpawned() {} - // render stuff - virtual void RenderFrame() {} -} + // actual handlers are here + virtual native void WorldLoaded(WorldEvent e); + virtual native void WorldUnloaded(WorldEvent e); + virtual native void WorldThingSpawned(WorldEvent e); -class StaticRenderEventHandler : StaticEventHandler native -{ - // for frame and camera - native readonly Vector3 ViewPos; - native readonly double ViewAngle; - native readonly double ViewPitch; - native readonly double ViewRoll; - native readonly double FracTic; - native readonly Actor Camera; -} - -class StaticWorldEventHandler : StaticEventHandler native -{ - // for world - native readonly bool IsSaveGame; // this is set to true if static WorldLoaded was triggered during savegame loading. - native readonly Actor Thing; // this is for WorldThingSpawned + virtual native void RenderFrame(RenderEvent e); } class EventHandler : StaticEventHandler native @@ -44,5 +46,3 @@ class EventHandler : StaticEventHandler native static native bool Register(StaticEventHandler handler); static native bool Unregister(StaticEventHandler handler); } - -class RenderEventHandler : StaticRenderEventHandler native { } From 71f62af6dbe1dfe48e98bcc9dd2c7f37369ad6be Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 02:07:00 +0200 Subject: [PATCH 37/69] Implemented WorldThingDied (calls at the same point as SCRIPT_Kill); Added Inflictor parameter for WorldThingDied. --- src/events.cpp | 72 ++++++++++++++++++++++++++++++++ src/events.h | 13 ++++++ src/p_interaction.cpp | 4 ++ wadsrc/static/zscript/events.txt | 5 +++ 4 files changed, 94 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index dc10827dd..80788f072 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -239,8 +239,27 @@ void E_WorldThingSpawned(AActor* actor) handler->WorldThingSpawned(actor); } +void E_WorldThingDied(AActor* actor, AActor* inflictor) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingDied(actor, inflictor); +} + +void E_WorldThingDestroyed(AActor* actor) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingDestroyed(actor); +} + // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) +DEFINE_EVENT_LOOPER(WorldLightning) // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); @@ -258,6 +277,7 @@ DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor); DEFINE_ACTION_FUNCTION(DEventHandler, Create) @@ -375,14 +395,24 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLoaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDied) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +// =========================================== +// +// Event handlers +// +// =========================================== + static DWorldEvent* E_SetupWorldEvent() { static DWorldEvent* e = nullptr; if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew(); e->IsSaveGame = savegamerestore; e->Thing = nullptr; + e->Inflictor = nullptr; return e; } @@ -426,6 +456,48 @@ void DStaticEventHandler::WorldThingSpawned(AActor* actor) } } +void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingDied) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingDied_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + e->Inflictor = inflictor; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::WorldThingDestroyed(AActor* actor) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingDestroyed) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingDestroyed_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::WorldLightning() +{ + IFVIRTUAL(DStaticEventHandler, WorldLightning) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldLightning_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + static DRenderEvent* E_SetupRenderEvent() { static DRenderEvent* e = nullptr; diff --git a/src/events.h b/src/events.h index a012730e6..5399443a7 100755 --- a/src/events.h +++ b/src/events.h @@ -27,6 +27,12 @@ void E_WorldLoadedUnsafe(); void E_WorldUnloadedUnsafe(); // called around PostBeginPlay of each actor. void E_WorldThingSpawned(AActor* actor); +// called after AActor::Die of each actor. +void E_WorldThingDied(AActor* actor, AActor* inflictor); +// called before AActor::Destroy of each actor. +void E_WorldThingDestroyed(AActor* actor); +// same as ACS SCRIPT_Lightning +void E_WorldLightning(); // called on each render frame once. void E_RenderFrame(); @@ -77,6 +83,9 @@ public: virtual void WorldLoaded(); virtual void WorldUnloaded(); virtual void WorldThingSpawned(AActor*); + virtual void WorldThingDied(AActor*, AActor*); + virtual void WorldThingDestroyed(AActor*); + virtual void WorldLightning(); virtual void RenderFrame(); }; class DEventHandler : public DStaticEventHandler @@ -141,11 +150,14 @@ public: bool IsSaveGame; // for thingspawned, thingdied, thingdestroyed AActor* Thing; + // for thingdied + AActor* Inflictor; // can be null DWorldEvent() { IsSaveGame = false; Thing = nullptr; + Inflictor = nullptr; } void Serialize(FSerializer& arc) override @@ -153,6 +165,7 @@ public: Super::Serialize(arc); arc("IsSaveGame", IsSaveGame); arc("Thing", Thing); + arc("Inflictor", Inflictor); } }; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c33cfb080..fbdac3f8f 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -60,6 +60,7 @@ #include "a_morph.h" #include "virtual.h" #include "g_levellocals.h" +#include "events.h" static FRandom pr_obituary ("Obituary"); static FRandom pr_botrespawn ("BotRespawn"); @@ -384,6 +385,9 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) target = source; } + // [ZZ] Fire WorldThingDied script hook. + E_WorldThingDied(this, inflictor); + // [JM] Fire KILL type scripts for actor. Not needed for players, since they have the "DEATH" script type. if (!player && !(flags7 & MF7_NOKILLSCRIPTS) && ((flags7 & MF7_USEKILLSCRIPTS) || gameinfo.forcekillscripts)) { diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 3a0e8d5eb..68f77ed9e 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -16,6 +16,8 @@ class WorldEvent : BaseEvent native native readonly bool IsSaveGame; // for thingspawned/thingdied/thingdestroyed native readonly Actor Thing; + // for thingdied. can be null + native readonly Actor Inflictor; } class StaticEventHandler : Object native @@ -33,6 +35,9 @@ class StaticEventHandler : Object native virtual native void WorldLoaded(WorldEvent e); virtual native void WorldUnloaded(WorldEvent e); virtual native void WorldThingSpawned(WorldEvent e); + virtual native void WorldThingDied(WorldEvent e); + virtual native void WorldThingDestroyed(WorldEvent e); + virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void RenderFrame(RenderEvent e); } From 3c1cecfa2bc3c2c077276bfeead0a89d1f73d9e9 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 02:15:57 +0200 Subject: [PATCH 38/69] Implemented WorldLightning and WorldThingDestroyed. --- src/g_shared/a_lightning.cpp | 4 ++++ src/p_mobj.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index deeb8405b..a5401f59a 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -11,6 +11,7 @@ #include "r_state.h" #include "serializer.h" #include "g_levellocals.h" +#include "events.h" static FRandom pr_lightning ("Lightning"); @@ -129,6 +130,9 @@ void DLightningThinker::LightningFlash () level.flags |= LEVEL_SWAPSKIES; // set alternate sky S_Sound (CHAN_AUTO, "world/thunder", 1.0, ATTN_NONE); + // [ZZ] just in case + E_WorldLightning(); + // start LIGHTNING scripts FBehavior::StaticStartTypedScripts (SCRIPT_Lightning, NULL, false); // [RH] Run lightning scripts // Calculate the next lighting flash diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b94098607..e45ca0b5f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5108,6 +5108,12 @@ void AActor::CallDeactivate(AActor *activator) void AActor::OnDestroy () { + // [ZZ] call destroy event hook. + // note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook. + // but you can't really do that without utterly breaking the game, so it's ok. + // note: if OnDestroy is ever made optional, E_WorldThingDestroyed should still be called for ANY thing. + E_WorldThingDestroyed(this); + ClearRenderSectorList(); ClearRenderLineList(); From 9a8a93fe516612b13ea7c3da43bf7f42a1cfa4b3 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 02:37:36 +0200 Subject: [PATCH 39/69] Made global handlers (from GameInfo) implicitly transient, because these never get serialized anyway. --- src/events.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index 80788f072..8eea680a7 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -23,6 +23,8 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->IsStatic()) { handler->ObjectFlags |= OF_Fixed; + if (!handler->isMapScope) // global (GameInfo) handlers are not serialized. + handler->ObjectFlags |= OF_Transient; } return true; } @@ -42,7 +44,7 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) E_FirstEventHandler = handler->next; if (handler->IsStatic()) { - handler->ObjectFlags &= ~OF_Fixed; + handler->ObjectFlags &= ~(OF_Fixed|OF_Transient); handler->Destroy(); } return true; From 066b22af0a9c3632f443ccc3f5d0aed84b0c7212 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 03:24:38 +0200 Subject: [PATCH 40/69] Almost forgot: WorldTick hook, since ZScript doesn't have delays --- src/events.cpp | 56 +++++++++----------------------- src/events.h | 3 ++ src/p_tick.cpp | 3 ++ wadsrc/static/zscript/events.txt | 1 + 4 files changed, 22 insertions(+), 41 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 8eea680a7..bba4d180d 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -262,6 +262,7 @@ void E_WorldThingDestroyed(AActor* actor) // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) DEFINE_EVENT_LOOPER(WorldLightning) +DEFINE_EVENT_LOOPER(WorldTick) // declarations IMPLEMENT_CLASS(DStaticEventHandler, false, false); @@ -400,6 +401,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDied) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) // =========================================== @@ -500,6 +502,19 @@ void DStaticEventHandler::WorldLightning() } } +void DStaticEventHandler::WorldTick() +{ + IFVIRTUAL(DStaticEventHandler, WorldTick) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldTick_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + static DRenderEvent* E_SetupRenderEvent() { static DRenderEvent* e = nullptr; @@ -532,44 +547,3 @@ void DStaticEventHandler::OnDestroy() E_UnregisterHandler(this); Super::OnDestroy(); } -/* -void DStaticRenderEventHandler::Setup() -{ - ViewPos = ::ViewPos; - ViewAngle = ::ViewAngle; - ViewPitch = ::ViewPitch; - ViewRoll = ::ViewRoll; - FracTic = ::r_TicFracF; - Camera = ::camera; -} - -void DStaticRenderEventHandler::RenderFrame() -{ - Setup(); - Super::RenderFrame(); -} - -void DStaticWorldEventHandler::Setup() -{ - IsSaveGame = savegamerestore; - Thing = nullptr; -} - -void DStaticWorldEventHandler::WorldLoaded() -{ - Setup(); - Super::WorldLoaded(); -} - -void DStaticWorldEventHandler::WorldUnloaded() -{ - Setup(); - Super::WorldUnloaded(); -} - -void DStaticWorldEventHandler::WorldThingSpawned(AActor* actor) -{ - Setup(); - Thing = actor; - Super::WorldThingSpawned(actor); -}*/ \ No newline at end of file diff --git a/src/events.h b/src/events.h index 5399443a7..fad159e76 100755 --- a/src/events.h +++ b/src/events.h @@ -33,6 +33,8 @@ void E_WorldThingDied(AActor* actor, AActor* inflictor); void E_WorldThingDestroyed(AActor* actor); // same as ACS SCRIPT_Lightning void E_WorldLightning(); +// this executes on every tick, before everything +void E_WorldTick(); // called on each render frame once. void E_RenderFrame(); @@ -86,6 +88,7 @@ public: virtual void WorldThingDied(AActor*, AActor*); virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); + virtual void WorldTick(); virtual void RenderFrame(); }; class DEventHandler : public DStaticEventHandler diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 2f8151425..990cdaf64 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -36,6 +36,7 @@ #include "r_utility.h" #include "p_spec.h" #include "g_levellocals.h" +#include "events.h" extern gamestate_t wipegamestate; @@ -125,6 +126,8 @@ void P_Ticker (void) /*Added by MC: Freeze mode.*/!(bglobal.freeze && players[i].Bot != NULL)) P_PlayerThink (&players[i]); + // [ZZ] call the WorldTick hook + E_WorldTick(); StatusBar->Tick (); // [RH] moved this here level.Tick (); // [RH] let the level tick DThinker::RunThinkers (); diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 68f77ed9e..179bf8ea6 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -38,6 +38,7 @@ class StaticEventHandler : Object native virtual native void WorldThingDied(WorldEvent e); virtual native void WorldThingDestroyed(WorldEvent e); virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. + virtual native void WorldTick(WorldEvent e); virtual native void RenderFrame(RenderEvent e); } From e74cd9883d44acc3230f2836c03939b96a74eb23 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 04:02:55 +0200 Subject: [PATCH 41/69] We don't want to store event objects in savegames. --- src/events.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/events.h b/src/events.h index fad159e76..b5bd76bff 100755 --- a/src/events.h +++ b/src/events.h @@ -111,6 +111,8 @@ public: // since from what I remember object creation and deletion results in a lot of GC processing // (and we aren't supposed to pass event objects around anyway) this->ObjectFlags |= OF_Fixed; + // we don't want to store events into the savegames because they are global. + this->ObjectFlags |= OF_Transient; } }; From 9942a598668556f4dfbff77fbcf9ca185bcad511 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 04:11:09 +0200 Subject: [PATCH 42/69] Almost forgot (x2): thing revived world event --- src/events.cpp | 24 ++++++++++++++++++++++++ src/events.h | 3 +++ src/p_mobj.cpp | 3 +++ wadsrc/static/zscript/events.txt | 1 + 4 files changed, 31 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index bba4d180d..68088a307 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -250,6 +250,15 @@ void E_WorldThingDied(AActor* actor, AActor* inflictor) handler->WorldThingDied(actor, inflictor); } +void E_WorldThingRevived(AActor* actor) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingRevived(actor); +} + void E_WorldThingDestroyed(AActor* actor) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -399,6 +408,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLoaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDied) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingRevived) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) @@ -475,6 +485,20 @@ void DStaticEventHandler::WorldThingDied(AActor* actor, AActor* inflictor) } } +void DStaticEventHandler::WorldThingRevived(AActor* actor) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingRevived) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingRevived_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + void DStaticEventHandler::WorldThingDestroyed(AActor* actor) { IFVIRTUAL(DStaticEventHandler, WorldThingDestroyed) diff --git a/src/events.h b/src/events.h index b5bd76bff..0bebcfc88 100755 --- a/src/events.h +++ b/src/events.h @@ -29,6 +29,8 @@ void E_WorldUnloadedUnsafe(); void E_WorldThingSpawned(AActor* actor); // called after AActor::Die of each actor. void E_WorldThingDied(AActor* actor, AActor* inflictor); +// called after AActor::Revive. +void E_WorldThingRevived(AActor* actor); // called before AActor::Destroy of each actor. void E_WorldThingDestroyed(AActor* actor); // same as ACS SCRIPT_Lightning @@ -86,6 +88,7 @@ public: virtual void WorldUnloaded(); virtual void WorldThingSpawned(AActor*); virtual void WorldThingDied(AActor*, AActor*); + virtual void WorldThingRevived(AActor*); virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); virtual void WorldTick(); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e45ca0b5f..f22f63937 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -7472,6 +7472,9 @@ void AActor::Revive() { level.total_monsters++; } + + // [ZZ] resurrect hook + E_WorldThingRevived(this); } int AActor::GetGibHealth() const diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 179bf8ea6..cedee667a 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -36,6 +36,7 @@ class StaticEventHandler : Object native virtual native void WorldUnloaded(WorldEvent e); virtual native void WorldThingSpawned(WorldEvent e); virtual native void WorldThingDied(WorldEvent e); + virtual native void WorldThingRevived(WorldEvent e); virtual native void WorldThingDestroyed(WorldEvent e); virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void WorldTick(WorldEvent e); From 89c475c2d1c7a145d34409203e2b5c7fdd406ae0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 04:35:44 +0200 Subject: [PATCH 43/69] Added WorldThingDamaged hook --- src/events.cpp | 40 +++++++++++++++++++++++++++++++- src/events.h | 32 ++++++++++--------------- src/p_interaction.cpp | 16 +++++++++++-- wadsrc/static/zscript/events.txt | 7 ++++++ 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 68088a307..3fb90dcbb 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -259,6 +259,15 @@ void E_WorldThingRevived(AActor* actor) handler->WorldThingRevived(actor); } +void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle) +{ + // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. + if (actor->ObjectFlags & OF_EuthanizeMe) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->WorldThingDamaged(actor, inflictor, source, damage, mod, flags, angle); +} + void E_WorldThingDestroyed(AActor* actor) { // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. @@ -290,7 +299,11 @@ DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor); - +DEFINE_FIELD_X(WorldEvent, DWorldEvent, Damage); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageSource); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageType); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageFlags); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle); DEFINE_ACTION_FUNCTION(DEventHandler, Create) { @@ -409,6 +422,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDied) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingRevived) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDamaged) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) @@ -427,6 +441,11 @@ static DWorldEvent* E_SetupWorldEvent() e->IsSaveGame = savegamerestore; e->Thing = nullptr; e->Inflictor = nullptr; + e->Damage = 0; + e->DamageAngle = 0.0; + e->DamageFlags = 0; + e->DamageSource = 0; + e->DamageType = NAME_None; return e; } @@ -499,6 +518,25 @@ void DStaticEventHandler::WorldThingRevived(AActor* actor) } } +void DStaticEventHandler::WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle) +{ + IFVIRTUAL(DStaticEventHandler, WorldThingDamaged) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_WorldThingDamaged_VMPtr) + return; + DWorldEvent* e = E_SetupWorldEvent(); + e->Thing = actor; + e->Damage = damage; + e->DamageSource = source; + e->DamageType = mod; + e->DamageFlags = flags; + e->DamageAngle = angle; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + void DStaticEventHandler::WorldThingDestroyed(AActor* actor) { IFVIRTUAL(DStaticEventHandler, WorldThingDestroyed) diff --git a/src/events.h b/src/events.h index 0bebcfc88..73fd5e401 100755 --- a/src/events.h +++ b/src/events.h @@ -31,6 +31,8 @@ void E_WorldThingSpawned(AActor* actor); void E_WorldThingDied(AActor* actor, AActor* inflictor); // called after AActor::Revive. void E_WorldThingRevived(AActor* actor); +// called before P_DamageMobj and before AActor::DamageMobj virtuals. +void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle); // called before AActor::Destroy of each actor. void E_WorldThingDestroyed(AActor* actor); // same as ACS SCRIPT_Lightning @@ -89,6 +91,7 @@ public: virtual void WorldThingSpawned(AActor*); virtual void WorldThingDied(AActor*, AActor*); virtual void WorldThingRevived(AActor*); + virtual void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle); virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); virtual void WorldTick(); @@ -136,18 +139,6 @@ public: FracTic = 0; Camera = nullptr; } - - // serialization handler for our local stuff - void Serialize(FSerializer& arc) override - { - Super::Serialize(arc); - arc("ViewPos", ViewPos); - arc("ViewAngle", ViewAngle); - arc("ViewPitch", ViewPitch); - arc("ViewRoll", ViewRoll); - arc("FracTic", FracTic); - arc("Camera", Camera); - } }; class DWorldEvent : public DBaseEvent @@ -160,20 +151,21 @@ public: AActor* Thing; // for thingdied AActor* Inflictor; // can be null + // for damagemobj + int Damage; + AActor* DamageSource; // can be null + FName DamageType; + int DamageFlags; + DAngle DamageAngle; DWorldEvent() { IsSaveGame = false; Thing = nullptr; Inflictor = nullptr; - } - - void Serialize(FSerializer& arc) override - { - Super::Serialize(arc); - arc("IsSaveGame", IsSaveGame); - arc("Thing", Thing); - arc("Inflictor", Inflictor); + Damage = 0; + DamageSource = nullptr; + DamageFlags = 0; } }; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index fbdac3f8f..b9c72e128 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1597,7 +1597,12 @@ DEFINE_ACTION_FUNCTION(AActor, DamageMobj) PARAM_NAME(mod); PARAM_INT_DEF(flags); PARAM_FLOAT_DEF(angle); - ACTION_RETURN_INT(DamageMobj(self, inflictor, source, damage, mod, flags, angle)); + + // [ZZ] event handlers need the result. + int realdamage = DamageMobj(self, inflictor, source, damage, mod, flags, angle); + if (!realdamage) ACTION_RETURN_INT(0); + E_WorldThingDamaged(self, inflictor, source, realdamage, mod, flags, angle); + ACTION_RETURN_INT(realdamage); } int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle) @@ -1611,7 +1616,14 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, GlobalVMStack.Call(func, params, 7, &ret, 1, nullptr); return retval; } - else return DamageMobj(target, inflictor, source, damage, mod, flags, angle); + else + { + int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle); + if (!realdamage) return 0; + // [ZZ] event handlers only need the resultant damage (they can't do anything about it anyway) + E_WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle); + return realdamage; + } } diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index cedee667a..a1029ff93 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -18,6 +18,12 @@ class WorldEvent : BaseEvent native native readonly Actor Thing; // for thingdied. can be null native readonly Actor Inflictor; + // for thingdamaged. + native readonly int Damage; + native readonly Actor DamageSource; + native readonly Name DamageType; + native readonly EDmgFlags DamageFlags; + native readonly double DamageAngle; } class StaticEventHandler : Object native @@ -37,6 +43,7 @@ class StaticEventHandler : Object native virtual native void WorldThingSpawned(WorldEvent e); virtual native void WorldThingDied(WorldEvent e); virtual native void WorldThingRevived(WorldEvent e); + virtual native void WorldThingDamaged(WorldEvent e); virtual native void WorldThingDestroyed(WorldEvent e); virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void WorldTick(WorldEvent e); From 26d38e65270ca57b3df1b8237cda8c502d098b99 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 04:53:18 +0200 Subject: [PATCH 44/69] Since WorldThingDestroyed is the reverse of WorldThingSpawned, it should ignore actors that didn't call PostBeginPlay. --- src/dobject.h | 1 + src/dthinker.cpp | 1 + src/events.cpp | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/dobject.h b/src/dobject.h index 6b9b87c75..dd03f669a 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -208,6 +208,7 @@ enum EObjectFlags OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) + OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning) }; template class TObjPtr; diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 7b63d2635..da68d8388 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -309,6 +309,7 @@ DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay) void DThinker::CallPostBeginPlay() { + ObjectFlags |= OF_Spawned; IFVIRTUAL(DThinker, PostBeginPlay) { // Without the type cast this picks the 'void *' assignment... diff --git a/src/events.cpp b/src/events.cpp index 3fb90dcbb..682b6da54 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -273,6 +273,10 @@ void E_WorldThingDestroyed(AActor* actor) // don't call anything if actor was destroyed on PostBeginPlay/BeginPlay/whatever. if (actor->ObjectFlags & OF_EuthanizeMe) return; + // don't call anything for non-spawned things (i.e. those that were created, but immediately destroyed) + // this is because Destroyed should be reverse of Spawned. we don't want to catch random inventory give failures. + if (!(actor->ObjectFlags & OF_Spawned)) + return; for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) handler->WorldThingDestroyed(actor); } From 6ada9c029101096fc58e7bb26199cd3bc8280fbf Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 06:22:01 +0200 Subject: [PATCH 45/69] Made map-section handlers in MAPINFO not static. Static now unambiguously means 'global from GameInfo'. --- src/events.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 682b6da54..d9c489f8d 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -119,15 +119,22 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) { if (type == nullptr) { - Printf("%cGWarning: unknown event handler class %s in MAPINFO!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); + I_Error("Fatal: unknown event handler class %s in MAPINFO!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); return; + } - if (!E_IsStaticType(type)) + if (E_IsStaticType(type) && map) + { + I_Error("Fatal: invalid event handler class %s in MAPINFO!\nMap-specific event handlers cannot be static.\n", typestring.GetChars()); + return; + } + /* + if (!E_IsStaticType(type) && !map) { Printf("%cGWarning: invalid event handler class %s in MAPINFO!\nMAPINFO event handlers should inherit Static* directly!\n", TEXTCOLOR_ESCAPE, typestring.GetChars()); return; - } + }*/ // check if type already exists, don't add twice. bool typeExists = false; @@ -153,13 +160,23 @@ void E_InitStaticHandlers(bool map) if (map) // don't initialize map handlers if restoring from savegame. { - // delete old map static handlers if any. + // delete old handlers if any. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic() && handler->isMapScope) + if (!handler->IsStatic()) handler->Destroy(); } + // load non-static handlers from gameinfo + for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) + { + FString typestring = gameinfo.EventHandlers[i]; + PClass* type = PClass::FindClass(typestring); + if (!type || E_IsStaticType(type)) // don't init the really global stuff here. + continue; + E_InitStaticHandler(type, typestring, false); + } + for (unsigned int i = 0; i < level.info->EventHandlers.Size(); i++) { FString typestring = level.info->EventHandlers[i]; @@ -180,6 +197,8 @@ void E_InitStaticHandlers(bool map) { FString typestring = gameinfo.EventHandlers[i]; PClass* type = PClass::FindClass(typestring); + if (!type || !E_IsStaticType(type)) // don't init map-local global stuff here. + continue; E_InitStaticHandler(type, typestring, false); } } From 765bc2db3980345ddf7ec7c8a753233e1ba98435 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Tue, 31 Jan 2017 06:24:39 +0200 Subject: [PATCH 46/69] Made map-section handlers in MAPINFO not static. Static now unambiguously means 'global from GameInfo'. --- src/events.cpp | 16 +++++++--------- src/events.h | 3 --- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index d9c489f8d..c9aba1660 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -23,8 +23,7 @@ bool E_RegisterHandler(DStaticEventHandler* handler) if (handler->IsStatic()) { handler->ObjectFlags |= OF_Fixed; - if (!handler->isMapScope) // global (GameInfo) handlers are not serialized. - handler->ObjectFlags |= OF_Transient; + handler->ObjectFlags |= OF_Transient; } return true; } @@ -149,7 +148,6 @@ static void E_InitStaticHandler(PClass* type, FString typestring, bool map) if (typeExists) return; DStaticEventHandler* handler = (DStaticEventHandler*)type->CreateNew(); - handler->isMapScope = map; E_RegisterHandler(handler); } @@ -189,7 +187,7 @@ void E_InitStaticHandlers(bool map) // delete old static handlers if any. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic() && !handler->isMapScope) + if (handler->IsStatic()) handler->Destroy(); } @@ -218,8 +216,8 @@ void E_WorldLoaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic() && !handler->isMapScope) continue; - if (handler->isMapScope && savegamerestore) continue; // don't execute WorldLoaded for handlers loaded from the savegame. + if (handler->IsStatic()) continue; + if (savegamerestore) continue; // don't execute WorldLoaded for handlers loaded from the savegame. handler->WorldLoaded(); } } @@ -228,7 +226,7 @@ void E_WorldUnloaded() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (handler->IsStatic() && !handler->isMapScope) continue; + if (handler->IsStatic()) continue; handler->WorldUnloaded(); } } @@ -237,7 +235,7 @@ void E_WorldLoadedUnsafe() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (!handler->IsStatic() || handler->isMapScope) continue; + if (!handler->IsStatic()) continue; handler->WorldLoaded(); } } @@ -246,7 +244,7 @@ void E_WorldUnloadedUnsafe() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { - if (!handler->IsStatic() || handler->isMapScope) continue; + if (!handler->IsStatic()) continue; handler->WorldUnloaded(); } } diff --git a/src/events.h b/src/events.h index 73fd5e401..4bbeb6174 100755 --- a/src/events.h +++ b/src/events.h @@ -59,12 +59,10 @@ public: { prev = 0; next = 0; - isMapScope = false; } DStaticEventHandler* prev; DStaticEventHandler* next; - bool isMapScope; virtual bool IsStatic() { return true; } // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields @@ -74,7 +72,6 @@ public: if (arc.isReading()) { Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars()); - isMapScope = true; // unserialized static handler means map scope anyway. other handlers don't get serialized. } else { From bc1194d03bc658f5fec4400ef272d60a95e7124b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 19:57:00 +0200 Subject: [PATCH 47/69] Added ordering for handlers - by int value returned by virtual function GetOrder(); Also, some handlers (WorldUnloaded and WorldThingDestroyed) are now executed in reverse order. --- src/events.cpp | 80 ++++++++++++++++++++++++++++---- src/events.h | 9 ++++ wadsrc/static/zscript/events.txt | 5 ++ 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index c9aba1660..23a8a8800 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -7,6 +7,7 @@ #include "actor.h" DStaticEventHandler* E_FirstEventHandler = nullptr; +DStaticEventHandler* E_LastEventHandler = nullptr; bool E_RegisterHandler(DStaticEventHandler* handler) { @@ -14,17 +15,53 @@ bool E_RegisterHandler(DStaticEventHandler* handler) return false; if (E_CheckHandler(handler)) return false; + // link into normal list - handler->prev = nullptr; - handler->next = E_FirstEventHandler; - if (handler->next) - handler->next->prev = handler; - E_FirstEventHandler = handler; + // update: link at specific position based on order. + DStaticEventHandler* before = nullptr; + for (DStaticEventHandler* existinghandler = E_FirstEventHandler; existinghandler; existinghandler = existinghandler->next) + { + 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; + } + 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()) { handler->ObjectFlags |= OF_Fixed; handler->ObjectFlags |= OF_Transient; } + return true; } @@ -41,6 +78,8 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) handler->next->prev = handler->prev; if (handler == E_FirstEventHandler) E_FirstEventHandler = handler->next; + if (handler == E_LastEventHandler) + E_LastEventHandler = handler->prev; if (handler->IsStatic()) { handler->ObjectFlags &= ~(OF_Fixed|OF_Transient); @@ -224,7 +263,7 @@ void E_WorldLoaded() 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; handler->WorldUnloaded(); @@ -242,7 +281,7 @@ void E_WorldLoadedUnsafe() 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; 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. if (!(actor->ObjectFlags & OF_Spawned)) return; - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) handler->WorldThingDestroyed(actor); } @@ -449,6 +488,12 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder) +{ + PARAM_SELF_PROLOGUE(DStaticEventHandler); + ACTION_RETURN_INT(0); +} + // =========================================== // // Event handlers @@ -630,3 +675,22 @@ void DStaticEventHandler::OnDestroy() E_UnregisterHandler(this); 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; +} \ No newline at end of file diff --git a/src/events.h b/src/events.h index 4bbeb6174..50a227c77 100755 --- a/src/events.h +++ b/src/events.h @@ -59,12 +59,18 @@ public: { prev = 0; next = 0; + order = 0; + haveorder = false; } DStaticEventHandler* prev; DStaticEventHandler* next; 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 void Serialize(FSerializer& arc) override { @@ -93,6 +99,9 @@ public: virtual void WorldLightning(); virtual void WorldTick(); virtual void RenderFrame(); + + // gets the order of this item. + int GetOrder(); }; class DEventHandler : public DStaticEventHandler { diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index a1029ff93..3f155c145 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -49,6 +49,11 @@ class StaticEventHandler : Object native virtual native void WorldTick(WorldEvent 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 From 7fa50c22e576b38cdc6d5f515dffe66e954c7ad2 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 20:26:56 +0200 Subject: [PATCH 48/69] Added player events --- src/events.cpp | 101 +++++++++++++++++++++++++++++++ src/events.h | 38 ++++++++++++ wadsrc/static/zscript/events.txt | 18 ++++++ 3 files changed, 157 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index 23a8a8800..bd78ad128 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -337,6 +337,30 @@ void E_WorldThingDestroyed(AActor* actor) handler->WorldThingDestroyed(actor); } +void E_PlayerEntered(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerEntered(num); +} + +void E_PlayerRespawned(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerRespawned(num); +} + +void E_PlayerDied(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerDied(num); +} + +void E_PlayerDisconnected(int num) +{ + for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) + handler->PlayerDisconnected(num); +} + // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) DEFINE_EVENT_LOOPER(WorldLightning) @@ -348,6 +372,7 @@ IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DBaseEvent, false, false) IMPLEMENT_CLASS(DRenderEvent, false, false) IMPLEMENT_CLASS(DWorldEvent, false, false) +IMPLEMENT_CLASS(DPlayerEvent, false, false) DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle); @@ -357,6 +382,7 @@ DEFINE_FIELD_X(RenderEvent, DRenderEvent, FracTic); DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsReopen); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Damage); @@ -365,6 +391,9 @@ DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageType); DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageFlags); DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle); +DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, PlayerNumber); +DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, IsReturn); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; @@ -486,8 +515,14 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDamaged) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) + DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerEntered) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerRespawned) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDied) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDisconnected) + DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -505,6 +540,7 @@ static DWorldEvent* E_SetupWorldEvent() static DWorldEvent* e = nullptr; if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew(); e->IsSaveGame = savegamerestore; + e->IsReopen = level.FromSnapshot; e->Thing = nullptr; e->Inflictor = nullptr; e->Damage = 0; @@ -669,6 +705,71 @@ void DStaticEventHandler::RenderFrame() } } +static DPlayerEvent* E_SetupPlayerEvent() +{ + static DPlayerEvent* e = nullptr; + if (!e) e = (DPlayerEvent*)RUNTIME_CLASS(DPlayerEvent)->CreateNew(); + e->PlayerNumber = -1; + e->IsReturn = level.FromSnapshot; + return e; +} + +void DStaticEventHandler::PlayerEntered(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerEntered) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerEntered_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerRespawned(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerRespawned) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerRespawned_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerDied(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerDied) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerDied_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerDisconnected(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerDisconnected) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerDisconnected_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + // void DStaticEventHandler::OnDestroy() { diff --git a/src/events.h b/src/events.h index 50a227c77..130f2eb17 100755 --- a/src/events.h +++ b/src/events.h @@ -41,6 +41,14 @@ void E_WorldLightning(); void E_WorldTick(); // called on each render frame once. void E_RenderFrame(); +// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN +void E_PlayerEntered(int num); +// this executes when a player respawns. includes resurrect cheat. +void E_PlayerRespawned(int num); +// this executes when a player dies (partially duplicating worldthingdied, but whatever) +void E_PlayerDied(int num); +// this executes when a player leaves the game +void E_PlayerDisconnected(int num); // serialization stuff void E_SerializeEvents(FSerializer& arc); @@ -89,6 +97,7 @@ public: // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; + // virtual void WorldLoaded(); virtual void WorldUnloaded(); virtual void WorldThingSpawned(AActor*); @@ -98,8 +107,16 @@ public: virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); virtual void WorldTick(); + + // virtual void RenderFrame(); + // + virtual void PlayerEntered(int num); + virtual void PlayerRespawned(int num); + virtual void PlayerDied(int num); + virtual void PlayerDisconnected(int num); + // gets the order of this item. int GetOrder(); }; @@ -153,6 +170,7 @@ class DWorldEvent : public DBaseEvent public: // for loaded/unloaded bool IsSaveGame; + bool IsReopen; // for thingspawned, thingdied, thingdestroyed AActor* Thing; // for thingdied @@ -167,6 +185,7 @@ public: DWorldEvent() { IsSaveGame = false; + IsReopen = false; Thing = nullptr; Inflictor = nullptr; Damage = 0; @@ -175,4 +194,23 @@ public: } }; +class DPlayerEvent : public DBaseEvent +{ + DECLARE_CLASS(DPlayerEvent, DBaseEvent) +public: + // we currently have only one member: player index + // in ZScript, we have global players[] array from which we can + // get both the player itself and player's body, + // so no need to pass it here. + int PlayerNumber; + // we set this to true if level was reopened (RETURN scripts) + bool IsReturn; + + DPlayerEvent() + { + PlayerNumber = -1; + IsReturn = false; + } +}; + #endif \ No newline at end of file diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 3f155c145..e6b826554 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -14,6 +14,8 @@ class WorldEvent : BaseEvent native { // for loaded/unloaded native readonly bool IsSaveGame; + // this will be true if we are re-entering the hub level. + native readonly bool IsReopen; // for thingspawned/thingdied/thingdestroyed native readonly Actor Thing; // for thingdied. can be null @@ -26,6 +28,15 @@ class WorldEvent : BaseEvent native native readonly double DamageAngle; } +class PlayerEvent : BaseEvent native +{ + // this is the player number that caused the event. + // note: you can get player struct from this by using players[e.PlayerNumber] + native readonly int PlayerNumber; + // this will be true if we are re-entering the hub level. + native readonly bool IsReturn; +} + class StaticEventHandler : Object native { // static event handlers CAN register other static event handlers. @@ -48,8 +59,15 @@ class StaticEventHandler : Object native virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void WorldTick(WorldEvent e); + // virtual native void RenderFrame(RenderEvent e); + // + virtual native void PlayerEntered(PlayerEvent e); + virtual native void PlayerRespawned(PlayerEvent e); + virtual native void PlayerDied(PlayerEvent e); + virtual native void PlayerDisconnected(PlayerEvent 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. From 19d2f6a4dbda2c1a6a934491e0e37a2bbdb8d609 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 20:27:57 +0200 Subject: [PATCH 49/69] REOPEN scripts should not be called per player pawn --- src/g_level.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 19c397437..55e6c1140 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1350,12 +1350,15 @@ void G_FinishTravel () if (level.FromSnapshot) { FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); - - // [Nash] run REOPEN scripts upon map re-entry - FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); } } + if (level.FromSnapshot) + { + // [Nash] run REOPEN scripts upon map re-entry + FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); + } + bglobal.FinishTravel (); // make sure that, after travelling has completed, no travelling thinkers are left. From 39355cf45deda5cccffcf49816486cb8740c9ad0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 20:46:10 +0200 Subject: [PATCH 50/69] Implemented player scripts. --- src/b_game.cpp | 4 ++++ src/events.cpp | 16 +++++++++++----- src/events.h | 4 ++-- src/g_game.cpp | 3 +++ src/g_level.cpp | 26 ++++++++++++++++++++++---- src/p_interaction.cpp | 3 +++ 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/b_game.cpp b/src/b_game.cpp index b99b97a60..38fbfafcb 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -61,6 +61,7 @@ Everything that is changed is marked (maybe commented) with "Added by MC" #include "d_netinf.h" #include "d_player.h" #include "doomerrors.h" +#include "events.h" static FRandom pr_botspawn ("BotSpawn"); @@ -418,6 +419,9 @@ void FCajunMaster::RemoveAllBots (bool fromlist) } } } + // [ZZ] run event hook + E_PlayerDisconnected(i); + // FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true); ClearPlayer (i, !fromlist); } diff --git a/src/events.cpp b/src/events.cpp index bd78ad128..02f269db4 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -337,10 +337,15 @@ void E_WorldThingDestroyed(AActor* actor) handler->WorldThingDestroyed(actor); } -void E_PlayerEntered(int num) +void E_PlayerEntered(int num, bool fromhub) { + // this event can happen during savegamerestore. make sure that local handlers don't receive it. + // actually, global handlers don't want it too. + if (savegamerestore && !fromhub) + return; + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - handler->PlayerEntered(num); + handler->PlayerEntered(num, fromhub); } void E_PlayerRespawned(int num) @@ -540,7 +545,7 @@ static DWorldEvent* E_SetupWorldEvent() static DWorldEvent* e = nullptr; if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew(); e->IsSaveGame = savegamerestore; - e->IsReopen = level.FromSnapshot; + e->IsReopen = level.FromSnapshot && !savegamerestore; // each one by itself isnt helpful, but with hub load we have savegamerestore==0 and level.FromSnapshot==1. e->Thing = nullptr; e->Inflictor = nullptr; e->Damage = 0; @@ -710,11 +715,11 @@ static DPlayerEvent* E_SetupPlayerEvent() static DPlayerEvent* e = nullptr; if (!e) e = (DPlayerEvent*)RUNTIME_CLASS(DPlayerEvent)->CreateNew(); e->PlayerNumber = -1; - e->IsReturn = level.FromSnapshot; + e->IsReturn = false; return e; } -void DStaticEventHandler::PlayerEntered(int num) +void DStaticEventHandler::PlayerEntered(int num, bool fromhub) { IFVIRTUAL(DStaticEventHandler, PlayerEntered) { @@ -722,6 +727,7 @@ void DStaticEventHandler::PlayerEntered(int num) if (func == DStaticEventHandler_PlayerEntered_VMPtr) return; DPlayerEvent* e = E_SetupPlayerEvent(); + e->IsReturn = fromhub; e->PlayerNumber = num; VMValue params[2] = { (DStaticEventHandler*)this, e }; GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); diff --git a/src/events.h b/src/events.h index 130f2eb17..05bda85c7 100755 --- a/src/events.h +++ b/src/events.h @@ -42,7 +42,7 @@ void E_WorldTick(); // called on each render frame once. void E_RenderFrame(); // this executes when a player enters the level (once). PlayerEnter+inhub = RETURN -void E_PlayerEntered(int num); +void E_PlayerEntered(int num, bool fromhub); // this executes when a player respawns. includes resurrect cheat. void E_PlayerRespawned(int num); // this executes when a player dies (partially duplicating worldthingdied, but whatever) @@ -112,7 +112,7 @@ public: virtual void RenderFrame(); // - virtual void PlayerEntered(int num); + virtual void PlayerEntered(int num, bool fromhub); virtual void PlayerRespawned(int num); virtual void PlayerDied(int num); virtual void PlayerDisconnected(int num); diff --git a/src/g_game.cpp b/src/g_game.cpp index e5c327472..ef864fdb0 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -91,6 +91,7 @@ #include "g_hub.h" #include "g_levellocals.h" +#include "events.h" static FRandom pr_dmspawn ("DMSpawn"); @@ -1791,6 +1792,8 @@ void G_DoPlayerPop(int playernum) // [RH] Make the player disappear FBehavior::StaticStopMyScripts(players[playernum].mo); + // [ZZ] fire player disconnect hook + E_PlayerDisconnected(playernum); // [RH] Let the scripts know the player left FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true); if (players[playernum].mo != NULL) diff --git a/src/g_level.cpp b/src/g_level.cpp index 55e6c1140..fa6e20ab5 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1256,6 +1256,10 @@ void G_FinishTravel () FPlayerStart *start; int pnum; + // + APlayerPawn* pawns[MAXPLAYERS]; + int pawnsnum = 0; + next = it.Next (); while ( (pawn = next) != NULL) { @@ -1347,16 +1351,30 @@ void G_FinishTravel () { pawn->Speed = pawn->GetDefault()->Speed; } - if (level.FromSnapshot) - { - FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true); - } + // [ZZ] we probably don't want to fire any scripts before all players are in, especially with runNow = true. + pawns[pawnsnum++] = pawn; } + // [ZZ] fire the reopen hook. if (level.FromSnapshot) { // [Nash] run REOPEN scripts upon map re-entry FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); + + for (int i = 0; i < pawnsnum; i++) + { + // [ZZ] fire the enter hook. + E_PlayerEntered(pawns[i]->player - players, true); + // + FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true); + } + } + else + { + for (int i = 0; i < pawnsnum; i++) + { + E_PlayerEntered(pawns[i]->player - players, false); + } } bglobal.FinishTravel (); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index b9c72e128..24b37a56a 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -610,6 +610,9 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) // [RH] Death messages ClientObituary (this, inflictor, source, dmgflags); + // [ZZ] fire player death hook + E_PlayerDied(player - players); + // Death script execution, care of Skull Tag FBehavior::StaticStartTypedScripts (SCRIPT_Death, this, true); From 957a8cb11759cbe4f12c97ba8478e4de5afb62a1 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 21:34:26 +0200 Subject: [PATCH 51/69] Count resurrect cheat as respawn --- src/m_cheat.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 2f99ea61c..958f1a168 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -49,6 +49,7 @@ #include "a_morph.h" #include "g_levellocals.h" #include "virtual.h" +#include "events.h" // [RH] Actually handle the cheat. The cheat code in st_stuff.c now just // writes some bytes to the network data stream, and the network code @@ -347,6 +348,12 @@ void cht_DoCheat (player_t *player, int cheat) P_UndoPlayerMorph(player, player); } + // player is now alive. + // fire E_PlayerRespawned and start the ACS SCRIPT_Respawn. + E_PlayerRespawned(player - players); + // + FBehavior::StaticStartTypedScripts(SCRIPT_Respawn, player->mo, true); + } } break; From dae4a48574ee0c45349093294ae8a358d90cd827 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 21:52:09 +0200 Subject: [PATCH 52/69] G_FinishTravel: only call RETURN/REOPEN on actual hub return as documented, not on every snapshot/savegame load --- src/g_level.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index fa6e20ab5..ae00a80fa 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1356,7 +1356,8 @@ void G_FinishTravel () } // [ZZ] fire the reopen hook. - if (level.FromSnapshot) + // if level is loaded from snapshot, and we don't have savegamerestore, this means we returned from a hub. + if (level.FromSnapshot && !savegamerestore) { // [Nash] run REOPEN scripts upon map re-entry FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); From 2f79f74d2da6c1f963bd24ca69708b1e0ffa2226 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 22:14:22 +0200 Subject: [PATCH 53/69] Fixed condition --- src/g_level.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index ae00a80fa..6ae23473f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1370,7 +1370,7 @@ void G_FinishTravel () FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true); } } - else + else if (!level.FromSnapshot) { for (int i = 0; i < pawnsnum; i++) { From 7f2d97d7efe1a89bf43c85c51a91d46e412dd950 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 22:18:28 +0200 Subject: [PATCH 54/69] Reverted previous commit --- src/g_level.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 6ae23473f..78613d9a4 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1357,7 +1357,7 @@ void G_FinishTravel () // [ZZ] fire the reopen hook. // if level is loaded from snapshot, and we don't have savegamerestore, this means we returned from a hub. - if (level.FromSnapshot && !savegamerestore) + if (level.FromSnapshot) { // [Nash] run REOPEN scripts upon map re-entry FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false); @@ -1370,7 +1370,7 @@ void G_FinishTravel () FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true); } } - else if (!level.FromSnapshot) + else { for (int i = 0; i < pawnsnum; i++) { From 5d8b3e80840995c2903a20feab9273bd6b0a1d5a Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 22:21:54 +0200 Subject: [PATCH 55/69] Fixed PlayerEntered for non-travel enters --- src/p_mobj.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f22f63937..25cf35059 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5426,6 +5426,9 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) { if (state == PST_ENTER || (state == PST_LIVE && !savegamerestore)) { + // [ZZ] fire non-hub ENTER event + // level.time is a hack to make sure that we don't call it on dummy player initialization during hub return. + if (!level.time) E_PlayerEntered(p - players, false); FBehavior::StaticStartTypedScripts (SCRIPT_Enter, p->mo, true); } else if (state == PST_REBORN) From 490159f6df6f5869434619cb0de9f3a200bf322b Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 22:37:22 +0200 Subject: [PATCH 56/69] Removed duplicate PlayerEntered call --- src/g_level.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index 78613d9a4..db6254063 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1370,13 +1370,6 @@ void G_FinishTravel () FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true); } } - else - { - for (int i = 0; i < pawnsnum; i++) - { - E_PlayerEntered(pawns[i]->player - players, false); - } - } bglobal.FinishTravel (); From 27c5e21a1dbc4a57c6bedb5caa6d46e69e3c3b4e Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 09:04:01 +0200 Subject: [PATCH 57/69] Moved E_InitStaticHandlers(true) a bit higher in the initialization so that local scripts receive PlayerEntered properly --- src/events.cpp | 4 ++++ src/g_level.cpp | 4 ++-- src/p_setup.cpp | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 02f269db4..141db3fdf 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -197,6 +197,8 @@ void E_InitStaticHandlers(bool map) if (map) // don't initialize map handlers if restoring from savegame. { + Printf("Initializing map handlers\n"); + // delete old handlers if any. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { @@ -211,6 +213,7 @@ void E_InitStaticHandlers(bool map) PClass* type = PClass::FindClass(typestring); if (!type || E_IsStaticType(type)) // don't init the really global stuff here. continue; + Printf("global -> %s\n", typestring.GetChars()); E_InitStaticHandler(type, typestring, false); } @@ -218,6 +221,7 @@ void E_InitStaticHandlers(bool map) { FString typestring = level.info->EventHandlers[i]; PClass* type = PClass::FindClass(typestring); + Printf("level -> %s\n", typestring.GetChars()); E_InitStaticHandler(type, typestring, true); } } diff --git a/src/g_level.cpp b/src/g_level.cpp index db6254063..8b9e8d37e 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1021,6 +1021,7 @@ void G_DoLoadLevel (int position, bool autosave) } level.maptime = 0; + P_SetupLevel (level.MapName, position); AM_LevelInit(); @@ -1062,6 +1063,7 @@ void G_DoLoadLevel (int position, bool autosave) } level.starttime = gametic; + G_UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level. G_FinishTravel (); // For each player, if they are viewing through a player, make sure it is themselves. @@ -1073,8 +1075,6 @@ void G_DoLoadLevel (int position, bool autosave) } } StatusBar->AttachToPlayer (&players[consoleplayer]); - // [ZZ] init per-map static handlers - E_InitStaticHandlers(true); // unsafe world load E_WorldLoadedUnsafe(); // regular world load (savegames are handled internally) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index df41345f4..066fba6d4 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -78,6 +78,7 @@ #ifndef NO_EDATA #include "edata.h" #endif +#include "events.h" #include "fragglescript/t_fs.h" @@ -3627,6 +3628,10 @@ void P_SetupLevel (const char *lumpname, int position) I_Error("Unable to open map '%s'\n", lumpname); } + // [ZZ] init per-map static handlers. we need to call this before everything is set up because otherwise scripts don't receive PlayerEntered event + // (which happens at god-knows-what stage in this function, but definitely not the last part, because otherwise it'd work to put E_InitStaticHandlers before the player spawning) + E_InitStaticHandlers(true); + // generate a checksum for the level, to be included and checked with savegames. map->GetChecksum(level.md5); // find map num From 9bb4cf1c031894ea2cf4e9092479055e46e0751e Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 12:28:40 +0200 Subject: [PATCH 58/69] User input events first take --- src/d_main.cpp | 3 + src/events.cpp | 240 +++++++++++++++++++++++++---- src/events.h | 102 ++++++++++--- src/posix/cocoa/i_input.mm | 5 + src/posix/sdl/i_input.cpp | 5 + src/win32/i_input.cpp | 5 + wadsrc/static/zscript/events.txt | 250 ++++++++++++++++++++++++++++++- 7 files changed, 557 insertions(+), 53 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index ba1de1bd2..a0456d6a0 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -287,6 +287,9 @@ void D_ProcessEvents (void) continue; // console ate the event if (M_Responder (ev)) continue; // menu ate the event + // check events + if (E_Responder(ev)) // [ZZ] ZScript ate the event + continue; G_Responder (ev); } } diff --git a/src/events.cpp b/src/events.cpp index 141db3fdf..f04fdaa00 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -15,13 +15,15 @@ bool E_RegisterHandler(DStaticEventHandler* handler) return false; if (E_CheckHandler(handler)) return false; + + handler->OnRegister(); // link into normal list // update: link at specific position based on order. DStaticEventHandler* before = nullptr; for (DStaticEventHandler* existinghandler = E_FirstEventHandler; existinghandler; existinghandler = existinghandler->next) { - if (existinghandler->GetOrder() > handler->GetOrder()) + if (existinghandler->Order > handler->Order) { before = existinghandler; break; @@ -71,6 +73,9 @@ bool E_UnregisterHandler(DStaticEventHandler* handler) return false; if (!E_CheckHandler(handler)) return false; + + handler->OnUnregister(); + // link out of normal list if (handler->prev) handler->prev->next = handler->next; @@ -197,8 +202,6 @@ void E_InitStaticHandlers(bool map) if (map) // don't initialize map handlers if restoring from savegame. { - Printf("Initializing map handlers\n"); - // delete old handlers if any. for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) { @@ -213,7 +216,6 @@ void E_InitStaticHandlers(bool map) PClass* type = PClass::FindClass(typestring); if (!type || E_IsStaticType(type)) // don't init the really global stuff here. continue; - Printf("global -> %s\n", typestring.GetChars()); E_InitStaticHandler(type, typestring, false); } @@ -221,7 +223,6 @@ void E_InitStaticHandlers(bool map) { FString typestring = level.info->EventHandlers[i]; PClass* type = PClass::FindClass(typestring); - Printf("level -> %s\n", typestring.GetChars()); E_InitStaticHandler(type, typestring, true); } } @@ -370,6 +371,45 @@ void E_PlayerDisconnected(int num) handler->PlayerDisconnected(num); } +bool E_Responder(event_t* ev) +{ + if (ev->type == EV_GUI_Event) + { + // iterate handlers back to front by order, and give them this event. + for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) + { + if (handler->IsUiProcessor && handler->UiProcess(ev)) + return true; // event was processed + } + } + else + { + // not sure if we want to handle device changes, but whatevs. + for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) + { + if (!handler->IsUiProcessor && handler->InputProcess(ev)) + return true; // event was processed + } + } + + return false; +} + +bool E_CheckUiProcessors() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsUiProcessor) + { + //Printf("E_CheckUiProcessors = true\n"); + return true; + } + } + + //Printf("E_CheckUiProcessors = false\n"); + return false; +} + // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) DEFINE_EVENT_LOOPER(WorldLightning) @@ -382,6 +422,11 @@ IMPLEMENT_CLASS(DBaseEvent, false, false) IMPLEMENT_CLASS(DRenderEvent, false, false) IMPLEMENT_CLASS(DWorldEvent, false, false) IMPLEMENT_CLASS(DPlayerEvent, false, false) +IMPLEMENT_CLASS(DUiEvent, false, false) +IMPLEMENT_CLASS(DInputEvent, false, false) + +DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, Order); +DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, IsUiProcessor); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle); @@ -403,6 +448,22 @@ DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle); DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, PlayerNumber); DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, IsReturn); +DEFINE_FIELD_X(UiEvent, DUiEvent, Type); +DEFINE_FIELD_X(UiEvent, DUiEvent, KeyString); +DEFINE_FIELD_X(UiEvent, DUiEvent, KeyChar); +DEFINE_FIELD_X(UiEvent, DUiEvent, MouseX); +DEFINE_FIELD_X(UiEvent, DUiEvent, MouseY); +DEFINE_FIELD_X(UiEvent, DUiEvent, IsShift); +DEFINE_FIELD_X(UiEvent, DUiEvent, IsAlt); +DEFINE_FIELD_X(UiEvent, DUiEvent, IsCtrl); + +DEFINE_FIELD_X(InputEvent, DInputEvent, Type); +DEFINE_FIELD_X(InputEvent, DInputEvent, KeyScan); +DEFINE_FIELD_X(InputEvent, DInputEvent, KeyString); +DEFINE_FIELD_X(InputEvent, DInputEvent, KeyChar); +DEFINE_FIELD_X(InputEvent, DInputEvent, MouseX); +DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; @@ -515,6 +576,9 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister) return 0; \ } +DEFINE_EMPTY_HANDLER(DStaticEventHandler, OnRegister) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, OnUnregister) + DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLoaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned) @@ -532,11 +596,8 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerRespawned) DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDied) DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDisconnected) -DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder) -{ - PARAM_SELF_PROLOGUE(DStaticEventHandler); - ACTION_RETURN_INT(0); -} +DEFINE_EMPTY_HANDLER(DStaticEventHandler, UiProcess); +DEFINE_EMPTY_HANDLER(DStaticEventHandler, InputProcess); // =========================================== // @@ -544,6 +605,30 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder) // // =========================================== +void DStaticEventHandler::OnRegister() +{ + IFVIRTUAL(DStaticEventHandler, OnRegister) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_OnRegister_VMPtr) + return; + VMValue params[1] = { (DStaticEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::OnUnregister() +{ + IFVIRTUAL(DStaticEventHandler, OnUnregister) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_OnUnregister_VMPtr) + return; + VMValue params[1] = { (DStaticEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + static DWorldEvent* E_SetupWorldEvent() { static DWorldEvent* e = nullptr; @@ -780,28 +865,125 @@ void DStaticEventHandler::PlayerDisconnected(int num) } } +static DUiEvent* E_SetupUiEvent() +{ + static DUiEvent* e = nullptr; + if (!e) e = (DUiEvent*)RUNTIME_CLASS(DUiEvent)->CreateNew(); + e->Type = EV_GUI_None; + e->IsShift = false; + e->IsAlt = false; + e->IsCtrl = false; + e->MouseX = e->MouseY = 0; + e->KeyChar = 0; + e->KeyString = ""; + return e; +} + +bool DStaticEventHandler::UiProcess(event_t* ev) +{ + IFVIRTUAL(DStaticEventHandler, UiProcess) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_UiProcess_VMPtr) + return false; + DUiEvent* e = E_SetupUiEvent(); + + // + e->Type = (EGUIEvent)ev->subtype; + // we don't want the modders to remember what weird fields mean what for what events. + switch (e->Type) + { + case EV_GUI_None: + break; + case EV_GUI_KeyDown: + case EV_GUI_KeyRepeat: + case EV_GUI_KeyUp: + e->KeyChar = ev->data1; + e->KeyString.Format("%c", e->KeyChar); + e->IsShift = !!(ev->data3 & GKM_SHIFT); + e->IsAlt = !!(ev->data3 & GKM_ALT); + e->IsCtrl = !!(ev->data3 & GKM_CTRL); + break; + case EV_GUI_Char: + e->KeyChar = ev->data1; + e->KeyString.Format("%c", e->KeyChar); + e->IsAlt = !!ev->data2; // only true for Win32, not sure about SDL + break; + default: // mouse event + // note: SDL input doesn't seem to provide these at all + e->MouseX = ev->x; + e->MouseY = ev->y; + e->IsShift = !!(ev->data3 & GKM_SHIFT); + e->IsAlt = !!(ev->data3 & GKM_ALT); + e->IsCtrl = !!(ev->data3 & GKM_CTRL); + break; + } + + int processed; + VMReturn results[1] = { &processed }; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, results, 1, nullptr); + return !!processed; + } + + return false; +} + +static DInputEvent* E_SetupInputEvent() +{ + static DInputEvent* e = nullptr; + if (!e) e = (DInputEvent*)RUNTIME_CLASS(DInputEvent)->CreateNew(); + e->Type = EV_None; + e->KeyScan = 0; + e->KeyChar = 0; + e->KeyString = ""; + e->MouseX = e->MouseY = 0; + return e; +} + +bool DStaticEventHandler::InputProcess(event_t* ev) +{ + IFVIRTUAL(DStaticEventHandler, InputProcess) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_InputProcess_VMPtr) + return false; + DInputEvent* e = E_SetupInputEvent(); + + // + e->Type = (EGenericEvent)ev->type; + // we don't want the modders to remember what weird fields mean what for what events. + switch (e->Type) + { + case EV_None: + break; + case EV_KeyDown: + case EV_KeyUp: + e->KeyScan = ev->data1; + e->KeyChar = ev->data2; + e->KeyString.Format("%c", e->KeyChar); + break; + case EV_Mouse: + e->MouseX = ev->x; + e->MouseY = ev->y; + break; + default: + break; // EV_DeviceChange = wat? + } + + int processed; + VMReturn results[1] = { &processed }; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, results, 1, nullptr); + return !!processed; + } + + return false; +} + // void DStaticEventHandler::OnDestroy() { E_UnregisterHandler(this); 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; -} \ No newline at end of file diff --git a/src/events.h b/src/events.h index 05bda85c7..7658d5f91 100755 --- a/src/events.h +++ b/src/events.h @@ -3,6 +3,8 @@ #include "dobject.h" #include "serializer.h" +#include "d_event.h" +#include "d_gui.h" class DStaticEventHandler; @@ -49,6 +51,11 @@ void E_PlayerRespawned(int num); void E_PlayerDied(int num); // this executes when a player leaves the game void E_PlayerDisconnected(int num); +// this executes on events. +bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess + +// check if there is anything that should receive GUI events +bool E_CheckUiProcessors(); // serialization stuff void E_SerializeEvents(FSerializer& arc); @@ -67,17 +74,17 @@ public: { prev = 0; next = 0; - order = 0; - haveorder = false; + Order = 0; + IsUiProcessor = false; } DStaticEventHandler* prev; DStaticEventHandler* next; virtual bool IsStatic() { return true; } - // order is cached to avoid calling the VM for sorting too much - int order; - bool haveorder; + // + int Order; + bool IsUiProcessor; // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields void Serialize(FSerializer& arc) override @@ -91,34 +98,42 @@ public: { Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars()); } - /* do nothing */ + + arc("Order", Order); + arc("IsUiProcessor", IsUiProcessor); } // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; // - virtual void WorldLoaded(); - virtual void WorldUnloaded(); - virtual void WorldThingSpawned(AActor*); - virtual void WorldThingDied(AActor*, AActor*); - virtual void WorldThingRevived(AActor*); - virtual void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle); - virtual void WorldThingDestroyed(AActor*); - virtual void WorldLightning(); - virtual void WorldTick(); + void OnRegister(); // you can set order and IsUi here. + void OnUnregister(); // - virtual void RenderFrame(); + void WorldLoaded(); + void WorldUnloaded(); + void WorldThingSpawned(AActor*); + void WorldThingDied(AActor*, AActor*); + void WorldThingRevived(AActor*); + void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle); + void WorldThingDestroyed(AActor*); + void WorldLightning(); + void WorldTick(); // - virtual void PlayerEntered(int num, bool fromhub); - virtual void PlayerRespawned(int num); - virtual void PlayerDied(int num); - virtual void PlayerDisconnected(int num); + void RenderFrame(); - // gets the order of this item. - int GetOrder(); + // + void PlayerEntered(int num, bool fromhub); + void PlayerRespawned(int num); + void PlayerDied(int num); + void PlayerDisconnected(int num); + + // + // return true if handled. + virtual bool InputProcess(event_t* ev); + virtual bool UiProcess(event_t* ev); }; class DEventHandler : public DStaticEventHandler { @@ -213,4 +228,47 @@ public: } }; +class DUiEvent : public DBaseEvent +{ + DECLARE_CLASS(DUiEvent, DBaseEvent) +public: + // this essentially translates event_t UI events to ZScript. + EGUIEvent Type; + // for keys/chars/whatever + FString KeyString; + int KeyChar; + // for mouse + int MouseX; + int MouseY; + // global (?) + bool IsShift; + bool IsCtrl; + bool IsAlt; + + DUiEvent() + { + Type = EV_GUI_None; + } +}; + +class DInputEvent : public DBaseEvent +{ + DECLARE_CLASS(DInputEvent, DBaseEvent) +public: + // this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!) + EGenericEvent Type; + // for keys + int KeyScan; + FString KeyString; + int KeyChar; + // for mouse + int MouseX; + int MouseY; + + DInputEvent() + { + Type = EV_None; + } +}; + #endif \ No newline at end of file diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 703280615..7b5faa80e 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -47,6 +47,7 @@ #include "doomdef.h" #include "doomstat.h" #include "v_video.h" +#include "events.h" #undef Class @@ -94,6 +95,10 @@ void CheckGUICapture() ? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon) : (MENU_On == menuactive || MENU_OnNoPause == menuactive); + // [ZZ] check active event handlers that want the UI processing + if (!wantCapture && E_CheckUiProcessors()) + wantCapture = true; + if (wantCapture != GUICapture) { GUICapture = wantCapture; diff --git a/src/posix/sdl/i_input.cpp b/src/posix/sdl/i_input.cpp index 372b23446..1d47dd6e0 100644 --- a/src/posix/sdl/i_input.cpp +++ b/src/posix/sdl/i_input.cpp @@ -17,6 +17,7 @@ #include "dikeys.h" #include "templates.h" #include "s_sound.h" +#include "events.h" static void I_CheckGUICapture (); static void I_CheckNativeMouse (); @@ -154,6 +155,10 @@ static void I_CheckGUICapture () wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); } + // [ZZ] check active event handlers that want the UI processing + if (!wantCapt && E_CheckUiProcessors()) + wantCapt = true; + if (wantCapt != GUICapture) { GUICapture = wantCapt; diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp index 1e6390392..0788e9415 100644 --- a/src/win32/i_input.cpp +++ b/src/win32/i_input.cpp @@ -101,6 +101,7 @@ #include "d_event.h" #include "v_text.h" #include "version.h" +#include "events.h" // Prototypes and declarations. #include "rawinput.h" @@ -187,6 +188,10 @@ static void I_CheckGUICapture () wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); } + // [ZZ] check active event handlers that want the UI processing + if (!wantCapt && E_CheckUiProcessors()) + wantCapt = true; + if (wantCapt != GUICapture) { GUICapture = wantCapt; diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index e6b826554..bbbe06534 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -37,6 +37,241 @@ class PlayerEvent : BaseEvent native native readonly bool IsReturn; } +class UiEvent : BaseEvent native +{ + // d_gui.h + enum EGUIEvent + { + Type_None, + Type_KeyDown, + Type_KeyRepeat, + Type_KeyUp, + Type_Char, + Type_FirstMouseEvent, // ? + Type_MouseMove, + Type_LButtonDown, + Type_LButtonUp, + Type_LButtonClick, + Type_MButtonDown, + Type_MButtonUp, + Type_MButtonClick, + Type_RButtonDown, + Type_RButtonUp, + Type_RButtonClick, + Type_WheelUp, + Type_WheelDown, + Type_WheelRight, // ??? + Type_WheelLeft, // ??? + Type_BackButtonDown, // ??? + Type_BackButtonUp, // ??? + Type_FwdButtonDown, // ??? + Type_FwdButtonUp, // ??? + Type_LastMouseEvent + } + + // for KeyDown, KeyRepeat, KeyUp + enum ESpecialGUIKeys + { + Key_PgDn = 1, + Key_PgUp = 2, + Key_Home = 3, + Key_End = 4, + Key_Left = 5, + Key_Right = 6, + Key_Alert = 7, // ASCII bell + Key_Backspace = 8, // ASCII + Key_Tab = 9, // ASCII + Key_LineFeed = 10, // ASCII + Key_Down = 10, + Key_VTab = 11, // ASCII + Key_Up = 11, + Key_FormFeed = 12, // ASCII + Key_Return = 13, // ASCII + Key_F1 = 14, + Key_F2 = 15, + Key_F3 = 16, + Key_F4 = 17, + Key_F5 = 18, + Key_F6 = 19, + Key_F7 = 20, + Key_F8 = 21, + Key_F9 = 22, + Key_F10 = 23, + Key_F11 = 24, + Key_F12 = 25, + Key_Del = 26, + Key_Escape = 27, // ASCII + Key_Free1 = 28, + Key_Free2 = 29, + Key_Back = 30, // browser back key + Key_CEscape = 31 // color escape + } + + // + native readonly EGUIEvent Type; + // + native readonly String KeyString; + native readonly int KeyChar; + // + native readonly int MouseX; + native readonly int MouseY; + // + /* // this can't be exposed yet: SDL driver doesn't set these at all + native readonly bool IsShift; + native readonly bool IsCtrl; + native readonly bool IsAlt; + */ +} + +class InputEvent : BaseEvent native +{ + enum EGenericEvent + { + Type_None, + Type_KeyDown, + Type_KeyUp, + Type_Mouse, + Type_GUI, // unused, kept for completeness + Type_DeviceChange + } + + // ew. + enum EDoomInputKeys + { + Key_Pause = 0xc5, // DIK_PAUSE + Key_RightArrow = 0xcd, // DIK_RIGHT + Key_LeftArrow = 0xcb, // DIK_LEFT + Key_UpArrow = 0xc8, // DIK_UP + Key_DownArrow = 0xd0, // DIK_DOWN + Key_Escape = 0x01, // DIK_ESCAPE + Key_Enter = 0x1c, // DIK_RETURN + Key_Space = 0x39, // DIK_SPACE + Key_Tab = 0x0f, // DIK_TAB + Key_F1 = 0x3b, // DIK_F1 + Key_F2 = 0x3c, // DIK_F2 + Key_F3 = 0x3d, // DIK_F3 + Key_F4 = 0x3e, // DIK_F4 + Key_F5 = 0x3f, // DIK_F5 + Key_F6 = 0x40, // DIK_F6 + Key_F7 = 0x41, // DIK_F7 + Key_F8 = 0x42, // DIK_F8 + Key_F9 = 0x43, // DIK_F9 + Key_F10 = 0x44, // DIK_F10 + Key_F11 = 0x57, // DIK_F11 + Key_F12 = 0x58, // DIK_F12 + Key_Grave = 0x29, // DIK_GRAVE + + Key_Backspace = 0x0e, // DIK_BACK + + Key_Equals = 0x0d, // DIK_EQUALS + Key_Minus = 0x0c, // DIK_MINUS + + Key_LShift = 0x2A, // DIK_LSHIFT + Key_LCtrl = 0x1d, // DIK_LCONTROL + Key_LAlt = 0x38, // DIK_LMENU + + Key_RShift = Key_LSHIFT, + Key_RCtrl = Key_LCTRL, + Key_RAlt = Key_LALT, + + Key_Ins = 0xd2, // DIK_INSERT + Key_Del = 0xd3, // DIK_DELETE + Key_End = 0xcf, // DIK_END + Key_Home = 0xc7, // DIK_HOME + Key_PgUp = 0xc9, // DIK_PRIOR + Key_PgDn = 0xd1, // DIK_NEXT + + Key_Mouse1 = 0x100, + Key_Mouse2 = 0x101, + Key_Mouse3 = 0x102, + Key_Mouse4 = 0x103, + Key_Mouse5 = 0x104, + Key_Mouse6 = 0x105, + Key_Mouse7 = 0x106, + Key_Mouse8 = 0x107, + + Key_FirstJoyButton = 0x108, + Key_Joy1 = (Key_FirstJoyButton+0), + Key_Joy2 = (Key_FirstJoyButton+1), + Key_Joy3 = (Key_FirstJoyButton+2), + Key_Joy4 = (Key_FirstJoyButton+3), + Key_Joy5 = (Key_FirstJoyButton+4), + Key_Joy6 = (Key_FirstJoyButton+5), + Key_Joy7 = (Key_FirstJoyButton+6), + Key_Joy8 = (Key_FirstJoyButton+7), + Key_LastJoyButton = 0x187, + Key_JoyPOV1_Up = 0x188, + Key_JoyPOV1_Right = 0x189, + Key_JoyPOV1_Down = 0x18a, + Key_JoyPOV1_Left = 0x18b, + Key_JoyPOV2_Up = 0x18c, + Key_JoyPOV3_Up = 0x190, + Key_JoyPOV4_Up = 0x194, + + Key_MWheelUp = 0x198, + Key_MWheelDown = 0x199, + Key_MWheelRight = 0x19A, + Key_MWheelLeft = 0x19B, + + Key_JoyAxis1Plus = 0x19C, + Key_JoyAxis1Minus = 0x19D, + Key_JoyAxis2Plus = 0x19E, + Key_JoyAxis2Minus = 0x19F, + Key_JoyAxis3Plus = 0x1A0, + Key_JoyAxis3Minus = 0x1A1, + Key_JoyAxis4Plus = 0x1A2, + Key_JoyAxis4Minus = 0x1A3, + Key_JoyAxis5Plus = 0x1A4, + Key_JoyAxis5Minus = 0x1A5, + Key_JoyAxis6Plus = 0x1A6, + Key_JoyAxis6Minus = 0x1A7, + Key_JoyAxis7Plus = 0x1A8, + Key_JoyAxis7Minus = 0x1A9, + Key_JoyAxis8Plus = 0x1AA, + Key_JoyAxis8Minus = 0x1AB, + Num_JoyAxisButtons = 8, + + Key_Pad_LThumb_Right = 0x1AC, + Key_Pad_LThumb_Left = 0x1AD, + Key_Pad_LThumb_Down = 0x1AE, + Key_Pad_LThumb_Up = 0x1AF, + + Key_Pad_RThumb_Right = 0x1B0, + Key_Pad_RThumb_Left = 0x1B1, + Key_Pad_RThumb_Down = 0x1B2, + Key_Pad_RThumb_Up = 0x1B3, + + Key_Pad_DPad_Up = 0x1B4, + Key_Pad_DPad_Down = 0x1B5, + Key_Pad_DPad_Left = 0x1B6, + Key_Pad_DPad_Right = 0x1B7, + Key_Pad_Start = 0x1B8, + Key_Pad_Back = 0x1B9, + Key_Pad_LThumb = 0x1BA, + Key_Pad_RThumb = 0x1BB, + Key_Pad_LShoulder = 0x1BC, + Key_Pad_RShoulder = 0x1BD, + Key_Pad_LTrigger = 0x1BE, + Key_Pad_RTrigger = 0x1BF, + Key_Pad_A = 0x1C0, + Key_Pad_B = 0x1C1, + Key_Pad_X = 0x1C2, + Key_Pad_Y = 0x1C3, + + Num_Keys = 0x1C4 + } + + // + native readonly EGenericEvent Type; + // + native readonly int KeyScan; // as in EDoomInputKeys enum + native readonly String KeyString; + native readonly int KeyChar; // ASCII char (if any) + // + native readonly int MouseX; + native readonly int MouseY; +} + class StaticEventHandler : Object native { // static event handlers CAN register other static event handlers. @@ -47,6 +282,11 @@ class StaticEventHandler : Object native protected static native bool Register(StaticEventHandler handler); protected static native bool Unregister(StaticEventHandler handler); + + // these are called when the handler gets registered or unregistered + // you can set Order/IsUiProcessor here. + virtual native void OnRegister(); + virtual native void OnUnregister(); // actual handlers are here virtual native void WorldLoaded(WorldEvent e); @@ -68,10 +308,16 @@ class StaticEventHandler : Object native virtual native void PlayerDied(PlayerEvent e); virtual native void PlayerDisconnected(PlayerEvent e); - // this function should return a value that will be queried on Register() to decide the relative order of this handler to every other. + // + virtual native bool UiProcess(UiEvent e); + virtual native bool InputProcess(InputEvent 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. - virtual native int GetOrder(); + native int Order; + // this value will be queried on user input to decide whether to send UiProcess to this handler. + native bool IsUiProcessor; } class EventHandler : StaticEventHandler native From b45af599c52edb967c5ec1ade4853201b53bf8d7 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 13:01:15 +0200 Subject: [PATCH 59/69] Explicit handler deinitizliation in P_Shutdown and P_FreeLevelData --- src/events.cpp | 27 +++++++++++++-------------- src/events.h | 2 ++ src/p_setup.cpp | 4 ++++ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index f04fdaa00..040165c88 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -200,15 +200,11 @@ void E_InitStaticHandlers(bool map) if (savegamerestore) return; + // just make sure + E_Shutdown(map); + if (map) // don't initialize map handlers if restoring from savegame. { - // delete old handlers if any. - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { - if (!handler->IsStatic()) - handler->Destroy(); - } - // load non-static handlers from gameinfo for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) { @@ -228,13 +224,6 @@ void E_InitStaticHandlers(bool map) } else { - // delete old static handlers if any. - for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { - if (handler->IsStatic()) - handler->Destroy(); - } - for (unsigned int i = 0; i < gameinfo.EventHandlers.Size(); i++) { FString typestring = gameinfo.EventHandlers[i]; @@ -246,6 +235,16 @@ void E_InitStaticHandlers(bool map) } } +void E_Shutdown(bool map) +{ + // delete handlers. + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + { + if (handler->IsStatic() == !map) + handler->Destroy(); + } +} + #define DEFINE_EVENT_LOOPER(name) void E_##name() \ { \ for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) \ diff --git a/src/events.h b/src/events.h index 7658d5f91..408a2a152 100755 --- a/src/events.h +++ b/src/events.h @@ -18,6 +18,8 @@ bool E_CheckHandler(DStaticEventHandler* handler); bool E_IsStaticType(PClass* type); // init static handlers void E_InitStaticHandlers(bool map); +// shutdown handlers +void E_Shutdown(bool map); // called right after the map has loaded (approximately same time as OPEN ACS scripts) void E_WorldLoaded(); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 066fba6d4..ce2662513 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3424,6 +3424,8 @@ extern polyblock_t **PolyBlockMap; void P_FreeLevelData () { + // [ZZ] delete per-map event handlers + E_Shutdown(true); P_FreeMapDataBackup(); interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level. Renderer->CleanLevelData(); @@ -4189,6 +4191,8 @@ void P_Init () static void P_Shutdown () { + // [ZZ] delete global event handlers + E_Shutdown(false); R_DeinitSpriteData (); P_DeinitKeyMessages (); P_FreeLevelData (); From 0d96517f5f1a16632659aa570e974fd020d7c59d Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 13:29:17 +0200 Subject: [PATCH 60/69] Implemented RenderOverlay hook that executes directly after level and statusbar --- src/d_main.cpp | 2 ++ src/events.cpp | 15 +++++++++++++++ src/events.h | 3 +++ wadsrc/static/zscript/events.txt | 1 + 4 files changed, 21 insertions(+) diff --git a/src/d_main.cpp b/src/d_main.cpp index 5b091a6ac..2a4b44dec 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -900,6 +900,8 @@ void D_Display () { NetUpdate (); // send out any new accumulation // normal update + // draw ZScript UI stuff + E_RenderOverlay(); C_DrawConsole (hw2d); // draw console M_Drawer (); // menu is drawn even on top of everything FStat::PrintStat (); diff --git a/src/events.cpp b/src/events.cpp index 040165c88..b169cee01 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -411,6 +411,7 @@ bool E_CheckUiProcessors() // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) +DEFINE_EVENT_LOOPER(RenderOverlay) DEFINE_EVENT_LOOPER(WorldLightning) DEFINE_EVENT_LOOPER(WorldTick) @@ -589,6 +590,7 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderOverlay) DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerEntered) DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerRespawned) @@ -798,6 +800,19 @@ void DStaticEventHandler::RenderFrame() } } +void DStaticEventHandler::RenderOverlay() +{ + IFVIRTUAL(DStaticEventHandler, RenderOverlay) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_RenderOverlay_VMPtr) + return; + DRenderEvent* e = E_SetupRenderEvent(); + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + static DPlayerEvent* E_SetupPlayerEvent() { static DPlayerEvent* e = nullptr; diff --git a/src/events.h b/src/events.h index 408a2a152..a116782c2 100755 --- a/src/events.h +++ b/src/events.h @@ -45,6 +45,8 @@ void E_WorldLightning(); void E_WorldTick(); // called on each render frame once. void E_RenderFrame(); +// called after everything's been rendered, but before console/menus +void E_RenderOverlay(); // this executes when a player enters the level (once). PlayerEnter+inhub = RETURN void E_PlayerEntered(int num, bool fromhub); // this executes when a player respawns. includes resurrect cheat. @@ -125,6 +127,7 @@ public: // void RenderFrame(); + void RenderOverlay(); // void PlayerEntered(int num, bool fromhub); diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index bbbe06534..f96d6e6dc 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -301,6 +301,7 @@ class StaticEventHandler : Object native // virtual native void RenderFrame(RenderEvent e); + virtual native void RenderOverlay(RenderEvent e); // virtual native void PlayerEntered(PlayerEvent e); From b4565c3800652d03f2e6cf7be39ba52258512b9c Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 16:15:53 +0200 Subject: [PATCH 61/69] Exposed Shift/Ctrl/Alt to the scripts --- wadsrc/static/zscript/events.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index f96d6e6dc..3d8b61984 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -116,11 +116,9 @@ class UiEvent : BaseEvent native native readonly int MouseX; native readonly int MouseY; // - /* // this can't be exposed yet: SDL driver doesn't set these at all native readonly bool IsShift; native readonly bool IsCtrl; native readonly bool IsAlt; - */ } class InputEvent : BaseEvent native From 08f1731ded73c6141347f28e56b2a315823ec9d7 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 17:39:26 +0200 Subject: [PATCH 62/69] Added keyboard modifiers for mouse events in SDL backend. --- src/posix/sdl/i_input.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/posix/sdl/i_input.cpp b/src/posix/sdl/i_input.cpp index 1d47dd6e0..759da062c 100644 --- a/src/posix/sdl/i_input.cpp +++ b/src/posix/sdl/i_input.cpp @@ -336,6 +336,12 @@ void MessagePump (const SDL_Event &sev) event.subtype = sev.type == SDL_MOUSEBUTTONDOWN ? EV_GUI_LButtonDown : EV_GUI_LButtonUp; event.subtype += (sev.button.button - 1) * 3; } + + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); + D_PostEvent(&event); } break; @@ -345,6 +351,10 @@ void MessagePump (const SDL_Event &sev) { event.type = EV_GUI_Event; event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown; + SDL_Keymod kmod = SDL_GetModState(); + event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((kmod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((kmod & KMOD_ALT) ? GKM_ALT : 0); D_PostEvent (&event); } else From 03f7c39ea7209e06eb1779e79fffa01602bf6449 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 20:34:34 +0200 Subject: [PATCH 63/69] Fixed mouse input in event handlers. Added RequireMouse field in event handler to signify that native mouse should be turned on for certain handlers. --- src/d_main.cpp | 3 +-- src/events.cpp | 18 +++++++++++------- src/events.h | 4 ++++ src/posix/cocoa/i_input.mm | 3 +++ src/win32/i_mouse.cpp | 4 ++++ wadsrc/static/zscript/events.txt | 2 ++ 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2a4b44dec..2ed553d0b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -310,8 +310,7 @@ void D_PostEvent (const event_t *ev) return; } events[eventhead] = *ev; - if (ev->type == EV_Mouse && !paused && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling - ) + if (ev->type == EV_Mouse && !paused && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !E_CheckUiProcessors()) { if (Button_Mlook.bDown || freelook) { diff --git a/src/events.cpp b/src/events.cpp index b169cee01..fe081f6c2 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -386,7 +386,7 @@ bool E_Responder(event_t* ev) // not sure if we want to handle device changes, but whatevs. for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) { - if (!handler->IsUiProcessor && handler->InputProcess(ev)) + if (handler->InputProcess(ev)) return true; // event was processed } } @@ -397,15 +397,18 @@ bool E_Responder(event_t* ev) bool E_CheckUiProcessors() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) - { if (handler->IsUiProcessor) - { - //Printf("E_CheckUiProcessors = true\n"); return true; - } - } - //Printf("E_CheckUiProcessors = false\n"); + return false; +} + +bool E_CheckRequireMouse() +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + if (handler->IsUiProcessor && handler->RequireMouse) + return true; + return false; } @@ -427,6 +430,7 @@ IMPLEMENT_CLASS(DInputEvent, false, false) DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, Order); DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, IsUiProcessor); +DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, RequireMouse); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle); diff --git a/src/events.h b/src/events.h index a116782c2..1ec6d068a 100755 --- a/src/events.h +++ b/src/events.h @@ -60,6 +60,8 @@ bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess // check if there is anything that should receive GUI events bool E_CheckUiProcessors(); +// check if we need native mouse due to UiProcessors +bool E_CheckRequireMouse(); // serialization stuff void E_SerializeEvents(FSerializer& arc); @@ -89,6 +91,7 @@ public: // int Order; bool IsUiProcessor; + bool RequireMouse; // serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields void Serialize(FSerializer& arc) override @@ -105,6 +108,7 @@ public: arc("Order", Order); arc("IsUiProcessor", IsUiProcessor); + arc("RequireMouse", RequireMouse); } // destroy handler. this unlinks EventHandler from the list automatically. diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm index 7b5faa80e..dae6b8072 100644 --- a/src/posix/cocoa/i_input.mm +++ b/src/posix/cocoa/i_input.mm @@ -186,6 +186,9 @@ void CheckNativeMouse() && (MENU_On == menuactive || MENU_OnNoPause == menuactive); } + if (!wantNative && E_CheckRequireMouse()) + wantNative = true; + I_SetNativeMouse(wantNative); } diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index b4f82fdb3..d13ef2445 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -18,6 +18,7 @@ #include "win32iface.h" #include "rawinput.h" #include "menu/menu.h" +#include "events.h" // MACROS ------------------------------------------------------------------ @@ -282,6 +283,9 @@ void I_CheckNativeMouse(bool preferNative) } } + if (!want_native && E_CheckRequireMouse()) + want_native = true; + //Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse); if (want_native != NativeMouse) diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 3d8b61984..690b1a6da 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -317,6 +317,8 @@ class StaticEventHandler : Object native native int Order; // this value will be queried on user input to decide whether to send UiProcess to this handler. native bool IsUiProcessor; + // this value determines whether mouse input is required. + native bool RequireMouse; } class EventHandler : StaticEventHandler native From f816537992058e11879c5dbad6c6252d3bd03a80 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 20:44:27 +0200 Subject: [PATCH 64/69] Setting Order directly (while the event handler is registered) will result in all sorts of broken behavior. Made readonly. --- src/events.cpp | 12 ++++++++++++ wadsrc/static/zscript/events.txt | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index fe081f6c2..7102ef3b8 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -468,6 +468,18 @@ DEFINE_FIELD_X(InputEvent, DInputEvent, KeyChar); DEFINE_FIELD_X(InputEvent, DInputEvent, MouseX); DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY); +DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) +{ + PARAM_SELF_PROLOGUE(DStaticEventHandler); + PARAM_INT(order); + + if (E_CheckHandler(self)) + return 0; + + self->Order = order; + return 0; +} + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 690b1a6da..fe0d45e7d 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -314,7 +314,8 @@ class StaticEventHandler : Object native // 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. - native int Order; + native readonly int Order; + native void SetOrder(int order); // this value will be queried on user input to decide whether to send UiProcess to this handler. native bool IsUiProcessor; // this value determines whether mouse input is required. From b18b71c06586f39ebca9f4c494246fb4e2963101 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 20:49:45 +0200 Subject: [PATCH 65/69] Mouse coordinates for UI mouse events are actually data1/data2, not x/y --- src/events.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 7102ef3b8..73f440947 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -941,8 +941,9 @@ bool DStaticEventHandler::UiProcess(event_t* ev) break; default: // mouse event // note: SDL input doesn't seem to provide these at all - e->MouseX = ev->x; - e->MouseY = ev->y; + //Printf("Mouse data: %d, %d, %d, %d\n", ev->x, ev->y, ev->data1, ev->data2); + e->MouseX = ev->data1; + e->MouseY = ev->data2; e->IsShift = !!(ev->data3 & GKM_SHIFT); e->IsAlt = !!(ev->data3 & GKM_ALT); e->IsCtrl = !!(ev->data3 & GKM_CTRL); From eb7548d63957f7523431a57eac922ce41e889eb0 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Fri, 3 Feb 2017 20:54:42 +0200 Subject: [PATCH 66/69] Printf doesn't work with FString on GCC --- src/c_console.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/c_console.cpp b/src/c_console.cpp index eb4c55d02..1b4cbd36a 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -1338,7 +1338,7 @@ DEFINE_ACTION_FUNCTION(_Console, Printf) { PARAM_PROLOGUE; FString s = FStringFormat(param, defaultparam, numparam, ret, numret); - Printf("%s\n", s); + Printf("%s\n", s.GetChars()); return 0; } From 77546ad5c2c585bb7f4611856f3d1d961fdd4aff Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 6 Feb 2017 15:52:20 +0200 Subject: [PATCH 67/69] Added non-playsim console-called event --- src/events.cpp | 72 ++++++++++++++++++++++++++++++++ src/events.h | 26 ++++++++++-- wadsrc/static/zscript/events.txt | 12 ++++++ 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/events.cpp b/src/events.cpp index 73f440947..4535f98f5 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -5,6 +5,7 @@ #include "gi.h" #include "v_text.h" #include "actor.h" +#include "c_dispatch.h" DStaticEventHandler* E_FirstEventHandler = nullptr; DStaticEventHandler* E_LastEventHandler = nullptr; @@ -394,6 +395,12 @@ bool E_Responder(event_t* ev) return false; } +void E_Console(int player, FString name, int arg1, int arg2, int arg3) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->ConsoleProcess(player, name, arg1, arg2, arg3); +} + bool E_CheckUiProcessors() { for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) @@ -427,6 +434,7 @@ IMPLEMENT_CLASS(DWorldEvent, false, false) IMPLEMENT_CLASS(DPlayerEvent, false, false) IMPLEMENT_CLASS(DUiEvent, false, false) IMPLEMENT_CLASS(DInputEvent, false, false) +IMPLEMENT_CLASS(DConsoleEvent, false, false) DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, Order); DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, IsUiProcessor); @@ -468,6 +476,10 @@ DEFINE_FIELD_X(InputEvent, DInputEvent, KeyChar); DEFINE_FIELD_X(InputEvent, DInputEvent, MouseX); DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY); +DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Player) +DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Name) +DEFINE_FIELD_X(ConsoleEvent, DConsoleEvent, Args) + DEFINE_ACTION_FUNCTION(DStaticEventHandler, SetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -616,6 +628,8 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDisconnected) DEFINE_EMPTY_HANDLER(DStaticEventHandler, UiProcess); DEFINE_EMPTY_HANDLER(DStaticEventHandler, InputProcess); +DEFINE_EMPTY_HANDLER(DStaticEventHandler, ConsoleProcess); + // =========================================== // // Event handlers @@ -1012,9 +1026,67 @@ bool DStaticEventHandler::InputProcess(event_t* ev) return false; } +static DConsoleEvent* E_SetupConsoleEvent() +{ + static DConsoleEvent* e = nullptr; + if (!e) e = (DConsoleEvent*)RUNTIME_CLASS(DConsoleEvent)->CreateNew(); + e->Player = -1; + e->Name = ""; + for (int i = 0; i < countof(e->Args); i++) + e->Args[i] = 0; + return e; +} + +void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3) +{ + IFVIRTUAL(DStaticEventHandler, ConsoleProcess) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_ConsoleProcess_VMPtr) + return; + DConsoleEvent* e = E_SetupConsoleEvent(); + + // + e->Player = player; + e->Name = name; + e->Args[0] = arg1; + e->Args[1] = arg2; + e->Args[2] = arg3; + + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + // void DStaticEventHandler::OnDestroy() { E_UnregisterHandler(this); Super::OnDestroy(); } + +// console stuff +// this is kinda like puke, except it distinguishes between local events and playsim events. +CCMD(event) +{ + int argc = argv.argc(); + + if (argc < 2 || argc > 5) + { + Printf("Usage: event [arg1] [arg2] [arg3]\n"); + } + else + { + int arg[3] = { 0, 0, 0 }; + int argn = MIN(argc - 2, countof(arg)); + for (int i = 0; i < argn; i++) + arg[i] = atoi(argv[2 + i]); + // call locally + E_Console(-1, argv[1], arg[0], arg[1], arg[2]); + } +} + +CCMD(netevent) +{ + +} \ No newline at end of file diff --git a/src/events.h b/src/events.h index 1ec6d068a..71c8a27f6 100755 --- a/src/events.h +++ b/src/events.h @@ -57,6 +57,8 @@ void E_PlayerDied(int num); void E_PlayerDisconnected(int num); // this executes on events. bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess +// this executes on console/net events. +void E_Console(int player, FString name, int arg1, int arg2, int arg3); // check if there is anything that should receive GUI events bool E_CheckUiProcessors(); @@ -139,10 +141,12 @@ public: void PlayerDied(int num); void PlayerDisconnected(int num); - // // return true if handled. - virtual bool InputProcess(event_t* ev); - virtual bool UiProcess(event_t* ev); + bool InputProcess(event_t* ev); + bool UiProcess(event_t* ev); + + // + void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3); }; class DEventHandler : public DStaticEventHandler { @@ -280,4 +284,20 @@ public: } }; +class DConsoleEvent : public DBaseEvent +{ + DECLARE_CLASS(DConsoleEvent, DBaseEvent) +public: + // player that activated this event. note that it's always -1 for non-playsim events (i.e. these not called with netevent) + int Player; + // + FString Name; + int Args[3]; + + DConsoleEvent() + { + Player = -1; + } +}; + #endif \ No newline at end of file diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index fe0d45e7d..24707055f 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -270,6 +270,15 @@ class InputEvent : BaseEvent native native readonly int MouseY; } +class ConsoleEvent : BaseEvent native +{ + // for net events, this will be the activator. + // for UI events, this is always -1, and you need to check if level is loaded and use players[consoleplayer]. + native readonly int Player; + native readonly String Name; + native readonly int Args[3]; +} + class StaticEventHandler : Object native { // static event handlers CAN register other static event handlers. @@ -311,6 +320,9 @@ class StaticEventHandler : Object native virtual native bool UiProcess(UiEvent e); virtual native bool InputProcess(InputEvent e); + // + virtual native void ConsoleProcess(ConsoleEvent 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. From 52d9077477f13e2a0468eef2b425cd83a81b1f24 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 6 Feb 2017 16:02:44 +0200 Subject: [PATCH 68/69] Added playsim event (netevent CCMD) --- src/d_net.cpp | 12 ++++++++++++ src/d_protocol.h | 1 + src/events.cpp | 19 +++++++++++++++++++ src/version.h | 2 +- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/d_net.cpp b/src/d_net.cpp index 93f6a621b..8b18efc7c 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -64,6 +64,7 @@ #include "a_keys.h" #include "intermission/intermission.h" #include "g_levellocals.h" +#include "events.h" EXTERN_CVAR (Int, disableautosave) EXTERN_CVAR (Int, autosavecount) @@ -2678,6 +2679,17 @@ void Net_DoCommand (int type, BYTE **stream, int player) G_ChangeLevel(NULL, 0, 0); break; + case DEM_NETEVENT: + { + FString ename = ReadString(stream); + int argn = ReadByte(stream); + int arg[3] = { 0, 0, 0 }; + for (int i = 0; i < argn; i++) + arg[i] = ReadLong(stream); + E_Console(player, ename, arg[0], arg[1], arg[2]); + } + break; + default: I_Error ("Unknown net command: %d", type); break; diff --git a/src/d_protocol.h b/src/d_protocol.h index 2813b14dc..27af1dae2 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -159,6 +159,7 @@ enum EDemoCommand DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT DEM_REMOVE, // 68 DEM_FINISHGAME, // 69 + DEM_NETEVENT // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int }; // The following are implemented by cht_DoCheat in m_cheat.cpp diff --git a/src/events.cpp b/src/events.cpp index 4535f98f5..17cec3685 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -6,6 +6,7 @@ #include "v_text.h" #include "actor.h" #include "c_dispatch.h" +#include "d_net.h" DStaticEventHandler* E_FirstEventHandler = nullptr; DStaticEventHandler* E_LastEventHandler = nullptr; @@ -1088,5 +1089,23 @@ CCMD(event) CCMD(netevent) { + int argc = argv.argc(); + if (argc < 2 || argc > 5) + { + Printf("Usage: event [arg1] [arg2] [arg3]\n"); + } + else + { + int arg[3] = { 0, 0, 0 }; + int argn = MIN(argc - 2, countof(arg)); + for (int i = 0; i < argn; i++) + arg[i] = atoi(argv[2 + i]); + // call networked + Net_WriteByte(DEM_NETEVENT); + Net_WriteString(argv[1]); + Net_WriteByte(argn); + for (int i = 0; i < argn; i++) + Net_WriteLong(arg[i]); + } } \ No newline at end of file diff --git a/src/version.h b/src/version.h index 8ed9e56aa..e50bdfd8d 100644 --- a/src/version.h +++ b/src/version.h @@ -61,7 +61,7 @@ const char *GetVersionString(); // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. // Otherwise, it should be safe to leave it alone. -#define DEMOGAMEVERSION 0x21E +#define DEMOGAMEVERSION 0x21F // Minimum demo version we can play. // Bump it whenever you change or remove existing DEM_ commands. From b23937c924ef29ea8e0c07c60fe16d99f9f15a89 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Mon, 6 Feb 2017 16:14:18 +0200 Subject: [PATCH 69/69] Safety measures: disallow using netevent when not in a level --- src/events.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/events.cpp b/src/events.cpp index 17cec3685..95a5af587 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -1089,11 +1089,17 @@ CCMD(event) CCMD(netevent) { + if (gamestate != GS_LEVEL/* && gamestate != GS_TITLELEVEL*/) // not sure if this should work in title level, but probably not, because this is for actual playing + { + Printf("netevent cannot be used outside of a map.\n"); + return; + } + int argc = argv.argc(); if (argc < 2 || argc > 5) { - Printf("Usage: event [arg1] [arg2] [arg3]\n"); + Printf("Usage: netevent [arg1] [arg2] [arg3]\n"); } else {