diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 06cd5dbfab..9478393c0e 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -258,6 +258,14 @@ void DThinker::PostBeginPlay () { } +DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay) +{ + PARAM_SELF_PROLOGUE(DThinker); + self->VMSuperCall(); + self->PostBeginPlay(); + return 0; +} + void DThinker::PostSerialize() { } @@ -421,6 +429,14 @@ void DThinker::Tick () { } +DEFINE_ACTION_FUNCTION(DThinker, Tick) +{ + PARAM_SELF_PROLOGUE(DThinker); + self->VMSuperCall(); + self->Tick(); + return 0; +} + size_t DThinker::PropagateMark() { // Do not choke on partially initialized objects (as happens when loading a savegame fails) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 313052c6b1..d1a273ef25 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4112,6 +4112,15 @@ void AActor::Tick () } } +DEFINE_ACTION_FUNCTION(AActor, Tick) +{ + PARAM_SELF_PROLOGUE(AActor); + self->VMSuperCall(); + self->Tick(); + return 0; +} + + //========================================================================== // // AActor :: CheckNoDelay @@ -4580,6 +4589,15 @@ void AActor::BeginPlay () } } +DEFINE_ACTION_FUNCTION(AActor, BeginPlay) +{ + PARAM_SELF_PROLOGUE(AActor); + self->VMSuperCall(); + self->BeginPlay(); + return 0; +} + + void AActor::PostBeginPlay () { if (Renderer != NULL) @@ -4635,6 +4653,15 @@ void AActor::Activate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Activate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->VMSuperCall(); + self->Activate(activator); + return 0; +} + void AActor::Deactivate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) @@ -4655,6 +4682,15 @@ void AActor::Deactivate (AActor *activator) } } +DEFINE_ACTION_FUNCTION(AActor, Deactivate) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(activator, AActor); + self->VMSuperCall(); + self->Deactivate(activator); + return 0; +} + // // P_RemoveMobj diff --git a/src/p_user.cpp b/src/p_user.cpp index 6f58f3cc84..ad0bb6ba4a 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1280,22 +1280,18 @@ void APlayerPawn::PlayRunning () void APlayerPawn::PlayAttacking () { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking"); - // Without the type cast this picks the 'void *' assignment... + VINDEX(APlayerPawn, PlayAttacking); VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::PlayAttacking2 () { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(APlayerPawn), "PlayAttacking2"); - // Without the type cast this picks the 'void *' assignment... + VINDEX(APlayerPawn, PlayAttacking2); VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::ThrowPoisonBag () diff --git a/src/virtual.h b/src/virtual.h index e0679df740..01541cebab 100644 --- a/src/virtual.h +++ b/src/virtual.h @@ -35,6 +35,9 @@ VMEXPORTED_NATIVES_START VMEXPORTED_NATIVES_FUNC(Destroy) VMEXPORTED_NATIVES_FUNC(Tick) VMEXPORTED_NATIVES_FUNC(PostBeginPlay) + VMEXPORTED_NATIVES_FUNC(BeginPlay) + VMEXPORTED_NATIVES_FUNC(Activate) + VMEXPORTED_NATIVES_FUNC(Deactivate) VMEXPORTED_NATIVES_END @@ -48,6 +51,15 @@ inline int GetVirtualIndex(PClass *cls, const char *funcname) return VIndex; } +#define VINDEX(cls, funcname) \ + static int VIndex = -1; \ + if (VIndex < 0) { \ + VIndex = GetVirtualIndex(RUNTIME_CLASS(cls), #funcname); \ + if (VIndex < 0) I_Error("Unable to find virtual function in " #cls, #funcname); \ + } + +#define VFUNC this->GetClass()->Virtuals[VIndex] + template class DVMObject : public T { @@ -84,28 +96,103 @@ public: { if (this->ObjectFlags & OF_SuperCall) { - this->ObjectFlags &= OF_SuperCall; + this->ObjectFlags &= ~OF_SuperCall; ExportedNatives::Get()->template Destroy(this); } else { - static int VIndex = -1; - if (VIndex < 0) VIndex = GetVirtualIndex(RUNTIME_CLASS(DObject), "Destroy"); + VINDEX(DObject, Destroy); // Without the type cast this picks the 'void *' assignment... VMValue params[1] = { (DObject*)this }; VMFrameStack stack; - stack.Call(this->GetClass()->Virtuals[VIndex], params, 1, nullptr, 0, nullptr); + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } } void Tick() { - ExportedNatives::Get()->template Tick(this); + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Tick(this); + } + else + { + VINDEX(DThinker, Tick); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } } void PostBeginPlay() { - ExportedNatives::Get()->template PostBeginPlay(this); + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template PostBeginPlay(this); + } + else + { + VINDEX(DThinker, PostBeginPlay); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } } + + void BeginPlay() + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template BeginPlay(this); + } + else + { + VINDEX(AActor, BeginPlay); + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); + } + } + + void Activate(AActor *activator) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Activate(this, activator); + } + else + { + VINDEX(AActor, Activate); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); + } + } + + void Deactivate(AActor *activator) + { + if (this->ObjectFlags & OF_SuperCall) + { + this->ObjectFlags &= ~OF_SuperCall; + ExportedNatives::Get()->template Deactivate(this, activator); + } + else + { + VINDEX(AActor, Deactivate); + // Without the type cast this picks the 'void *' assignment... + VMValue params[2] = { (DObject*)this, (DObject*)activator }; + VMFrameStack stack; + stack.Call(VFUNC, params, 2, nullptr, 0, nullptr); + } + } + }; template @@ -130,7 +217,13 @@ VMEXPORT_NATIVES_END(DObject) VMEXPORT_NATIVES_START(DThinker, DObject) VMEXPORT_NATIVES_FUNC(Tick) VMEXPORT_NATIVES_FUNC(PostBeginPlay) - VMEXPORT_NATIVES_END(DThinker) +VMEXPORT_NATIVES_END(DThinker) + +VMEXPORT_NATIVES_START(AActor, DThinker) + VMEXPORT_NATIVES_FUNC(BeginPlay) + VMEXPORT_NATIVES_FUNC(Activate) + VMEXPORT_NATIVES_FUNC(Deactivate) +VMEXPORT_NATIVES_END(AActor) /* VMEXPORT_NATIVES_START(AActor, DThinker) diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 99ca89c8e8..53f0475135 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -62,7 +62,10 @@ class Actor : Thinker native { return sin(fb * (180./32)) * 8; } - + + virtual native void BeginPlay(); + virtual native void Activate(Actor activator); + virtual native void Deactivate(Actor activator); native static readonly GetDefaultByType(class cls); native static double deltaangle(double ang1, double ang2); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 1089476a1a..7a27907263 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -10,6 +10,8 @@ class Object native class Thinker : Object native { + virtual native void Tick(); + virtual native void PostBeginPlay(); } class ThinkerIterator : Object native