From 11f094c7fb19bf594ecbfa304d7201fc39b768f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 6 Oct 2023 00:26:25 +0200 Subject: [PATCH] reference event callbacks by name, not by internal index. This is needed to allow writing new callbacks. --- source/common/scripting/backend/codegen.cpp | 17 +++++++++++++++ source/common/scripting/backend/codegen.h | 7 +++++++ source/common/scripting/core/imports.cpp | 17 +++++++++++++++ source/common/scripting/core/types.cpp | 2 ++ source/common/scripting/core/types.h | 2 ++ source/common/scripting/vm/vm.h | 1 + source/core/zcc_compile_raze.cpp | 12 ++++++++++- source/games/blood/src/actor.h | 1 + source/games/blood/src/blood.h | 2 +- source/games/blood/src/nnexts.cpp | 6 +++--- source/games/blood/src/vmexports.cpp | 12 ++++++++++- wadsrc/static/zscript/engine/base.zs | 5 +++++ .../zscript/games/blood/actors/missiles.zs | 21 +++++++++---------- .../static/zscript/games/blood/bloodactor.zs | 7 ++++--- 14 files changed, 92 insertions(+), 20 deletions(-) diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index 9711abf72..4b9ffb083 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -1639,6 +1639,23 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) // don't go through the entire list if the types are the same. goto basereturn; } + else if ((basex->ValueType == TypeString || basex->ValueType == TypeName) && ValueType == TypeVMFunction && basex->isConstant()) + { + FxExpression* x = new FxStringCast(basex); + x = x->Resolve(ctx); + basex = nullptr; + auto c = static_cast(x)->GetValue().GetString().GetChars(); + auto func = FindVMFunction(c); + if (func == nullptr) + { + ScriptPosition.Message(MSG_ERROR, "VM function %s not found", c); + delete this; + return nullptr; + } + auto newx = new FxConstant(func, ScriptPosition); + delete this; + return newx->Resolve(ctx); + } else if (basex->ValueType == TypeNullPtr && ValueType->isPointer()) { goto basereturn; diff --git a/source/common/scripting/backend/codegen.h b/source/common/scripting/backend/codegen.h index 2781adbe5..5dd066b57 100644 --- a/source/common/scripting/backend/codegen.h +++ b/source/common/scripting/backend/codegen.h @@ -506,6 +506,13 @@ public: isresolved = true; } + FxConstant(VMFunction* state, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos) + { + value.pointer = state; + ValueType = value.Type = TypeVMFunction; + isresolved = true; + } + FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos) { value.pointer = nullptr; diff --git a/source/common/scripting/core/imports.cpp b/source/common/scripting/core/imports.cpp index eed84980a..08ae1a330 100644 --- a/source/common/scripting/core/imports.cpp +++ b/source/common/scripting/core/imports.cpp @@ -147,6 +147,23 @@ VMFunction *FindVMFunction(PClass *cls, const char *name) } +//========================================================================== +// +// Find an action function in AActor's table from a qualified name +// +//========================================================================== + +VMFunction* FindVMFunction( const char* name) +{ + auto p = strchr(name, '.'); + if (p == nullptr) return nullptr; + std::string clsname(name, p - name); + auto cls = PClass::FindClass(clsname.c_str()); + if (cls == nullptr) return nullptr; + return FindVMFunction(cls, p + 1); +} + + //========================================================================== // // Sorting helpers diff --git a/source/common/scripting/core/types.cpp b/source/common/scripting/core/types.cpp index 6543dde9e..f27faa7ab 100644 --- a/source/common/scripting/core/types.cpp +++ b/source/common/scripting/core/types.cpp @@ -75,6 +75,7 @@ PStruct *TypeStringStruct; PStruct* TypeQuaternionStruct; PPointer *TypeNullPtr; PPointer *TypeVoidPtr; +PPointer* TypeVMFunction; // CODE -------------------------------------------------------------------- @@ -322,6 +323,7 @@ void PType::StaticInit() TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID); TypeVoidPtr = NewPointer(TypeVoid, false); + TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true)); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. TypeStringStruct = NewStruct("Stringstruct", nullptr, true); TypeQuaternionStruct = NewStruct("QuatStruct", nullptr, true); diff --git a/source/common/scripting/core/types.h b/source/common/scripting/core/types.h index 789cc7d3e..850c354a8 100644 --- a/source/common/scripting/core/types.h +++ b/source/common/scripting/core/types.h @@ -697,6 +697,8 @@ extern PPointer *TypeFont; extern PStateLabel *TypeStateLabel; extern PPointer *TypeNullPtr; extern PPointer *TypeVoidPtr; +extern PPointer* TypeVMFunction; + inline FString &DObject::StringVar(FName field) { diff --git a/source/common/scripting/vm/vm.h b/source/common/scripting/vm/vm.h index 6442034c1..2b7344d5d 100644 --- a/source/common/scripting/vm/vm.h +++ b/source/common/scripting/vm/vm.h @@ -797,6 +797,7 @@ class AActor; class PFunction; VMFunction *FindVMFunction(PClass *cls, const char *name); +VMFunction* FindVMFunction(const char* name); #define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name); FString FStringFormat(VM_ARGS, int offset = 0); diff --git a/source/core/zcc_compile_raze.cpp b/source/core/zcc_compile_raze.cpp index 58cbdf9df..233611363 100644 --- a/source/core/zcc_compile_raze.cpp +++ b/source/core/zcc_compile_raze.cpp @@ -66,8 +66,8 @@ int ZCCRazeCompiler::Compile() CompileAllConstants(); CompileAllFields(); CompileAllProperties(); - InitDefaults(); InitFunctions(); + InitDefaults(); return FScriptPosition::ErrorCounter; } @@ -608,6 +608,16 @@ void ZCCRazeCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt * { *(FName*)addr = GetStringConst(ex, ctx); } + else if (f->Type == TypeVMFunction) + { + auto name = GetStringConst(ex, ctx); + auto vmfunc = FindVMFunction(name); + if (!vmfunc) + { + Error(property, "'%s': Unknown function", name); + } + *(void**)addr = vmfunc; + } else if (f->Type == TypeSound) { *(FSoundID*)addr = S_FindSound(GetStringConst(ex, ctx)); diff --git a/source/games/blood/src/actor.h b/source/games/blood/src/actor.h index 99174d089..46d29d41d 100644 --- a/source/games/blood/src/actor.h +++ b/source/games/blood/src/actor.h @@ -184,6 +184,7 @@ void actFireVector(DBloodActor* shooter, double offset, double zoffset, DVector3 void actPostSprite(DBloodActor* actor, int status); void actPostProcess(void); void MakeSplash(DBloodActor *actor); +void callActorFunction(VMFunction* funcID, DBloodActor* actor); extern const int16_t DudeDifficulty[]; diff --git a/source/games/blood/src/blood.h b/source/games/blood/src/blood.h index d89f1e27e..3f391e4b1 100644 --- a/source/games/blood/src/blood.h +++ b/source/games/blood/src/blood.h @@ -268,7 +268,7 @@ DEF_ANIMATOR(LeechStateTimer) // 20 DEF_ANIMATOR(DropVoodooCb) // unused DEF_ANIMATOR(callbackMakeMissileBlocking) -DEF_ANIMATOR(GenDudeUpdate) +DEF_ANIMATOR(callbackGenDudeUpdate) DEF_ANIMATOR(callbackUniMissileBurst) enum EFeatureFlags diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index 497eb9128..6501f3809 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -2462,7 +2462,7 @@ void useObjResizer(DBloodActor* sourceactor, int targType, sectortype* targSect, targetactor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; targetactor->genDudeExtra.updReq[kGenDudePropertyMass] = true; targetactor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; - evPostActor(targetactor, kGenDudeUpdTimeRate, AF(GenDudeUpdate)); + evPostActor(targetactor, kGenDudeUpdTimeRate, AF(callbackGenDudeUpdate)); } @@ -7614,7 +7614,7 @@ bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodAc case kDudeModernCustomBurning: objActor->genDudeExtra.updReq[kGenDudePropertyWeapon] = true; objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; - evPostActor(objActor, kGenDudeUpdTimeRate, AF(GenDudeUpdate)); + evPostActor(objActor, kGenDudeUpdTimeRate, AF(callbackGenDudeUpdate)); break; } return true; @@ -7629,7 +7629,7 @@ bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodAc objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; objActor->genDudeExtra.updReq[kGenDudePropertyStates] = true; objActor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; - evPostActor(objActor, kGenDudeUpdTimeRate, AF(GenDudeUpdate)); + evPostActor(objActor, kGenDudeUpdTimeRate, AF(callbackGenDudeUpdate)); break; } return true; diff --git a/source/games/blood/src/vmexports.cpp b/source/games/blood/src/vmexports.cpp index 48e02b5bb..6165d8659 100644 --- a/source/games/blood/src/vmexports.cpp +++ b/source/games/blood/src/vmexports.cpp @@ -408,11 +408,21 @@ DBloodActor* actFireMissile(DBloodActor* actor, double xyoff, double zoff, DVect DBloodActor* spawned; VMReturn ret((void**)&spawned); VMValue param[] = { actor, xyoff, zoff, dv.X, dv.Y, dv.Z, ty}; - VMCall(func, param, 1, &ret, 1); + VMCall(func, param, 7, &ret, 1); return spawned; } return nullptr; } +void callActorFunction(VMFunction* funcID, DBloodActor* actor) +{ + if (funcID) + { + VMValue param[] = { actor }; + VMCall(funcID, param, 1, nullptr, 0); + } + +} + END_BLD_NS diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index c111acc3d..b012f9762 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -937,3 +937,8 @@ struct QuatStruct native // native double LengthSquared(); // native Quat Unit(); } + +// this struct does not exist. It is just a type for being referenced by an opaque pointer. +struct VMFunction native version("4.10") +{ +} diff --git a/wadsrc/static/zscript/games/blood/actors/missiles.zs b/wadsrc/static/zscript/games/blood/actors/missiles.zs index 3881cc07b..a46ada0a0 100644 --- a/wadsrc/static/zscript/games/blood/actors/missiles.zs +++ b/wadsrc/static/zscript/games/blood/actors/missiles.zs @@ -3,7 +3,7 @@ class BloodMissileBase : BloodActor meta double speed; meta double defclipdist; meta double angleofs; - meta int callbackID; // make this a function name later + meta VMFunction callback; meta int spawnsoundID; meta Sound spawnsound; meta double movementAdd; @@ -16,7 +16,7 @@ class BloodMissileBase : BloodActor property speed: speed; property clipdist: defclipdist; property angleofs: angleofs; - property callbackID: callbackID; + property callback: callback; property spawnsound: spawnsound; property spawnsoundID: spawnsoundID; property movementAdd: movementAdd; @@ -27,7 +27,6 @@ class BloodMissileBase : BloodActor default { - callbackID -1; seqID -1; spawnsoundID -1; seqCallbackID -1; @@ -48,9 +47,9 @@ class BloodMissileBase : BloodActor { self.seqSpawnID(self.seqID, self.seqCallbackID); } - if (self.callbackID > -1) + if (self.callback != null) { - self.evPostActorCallback(0, self.callbackID); + self.evPostActorCallback(0, self.callback); } if (self.spawnsound != 0) { @@ -93,7 +92,7 @@ class BloodMissileFlareRegular : BloodMissileBase scale 0.500000, 0.500000; shade -128; clipdist 8.000000; - callbackID kCallbackFXFlareSpark; + callback "BloodActor.fxFlareSpark"; spawnsoundID 422; } } @@ -106,7 +105,7 @@ class BloodMissileTeslaAlt : BloodMissileBase scale 0.500000, 0.500000; shade -128; clipdist 8.000000; - callbackID kCallbackFXTeslaAlt; + callback "BloodActor.fxTeslaAlt"; } } class BloodMissileFlareAlt : BloodMissileBase @@ -118,14 +117,14 @@ class BloodMissileFlareAlt : BloodMissileBase scale 0.500000, 0.500000; shade -128; clipdist 1.000000; - callbackID kCallbackFXFlareSpark; + callback "BloodActor.fxFlareSpark"; spawnsoundID 422; } override void initMissile(BloodActor spawner) { super.initMissile(spawner); - self.evPostActorCallback(30, kCallbackFXFlareBurst); + self.evPostActorCallback(30, "BloodActor.FlareBurst"); } } class BloodMissileFlameSpray : BloodMissileBase @@ -278,7 +277,7 @@ class BloodMissileLifeLeechRegular : BloodMissileBase scale 0.500000, 0.500000; shade -128; clipdist 4.000000; - callbackID kCallbackFXFlameLick; + callback "BloodActor.fxFlameLick"; } } class BloodMissileLifeLeechAltNormal : BloodMissileBase @@ -301,7 +300,7 @@ class BloodMissileLifeLeechAltSmall : BloodMissileBase scale 0.500000, 0.500000; shade -128; clipdist 4.000000; - callbackID kCallbackFXArcSpark; + callback "BloodActor.fxArcSpark"; } } diff --git a/wadsrc/static/zscript/games/blood/bloodactor.zs b/wadsrc/static/zscript/games/blood/bloodactor.zs index 71c74ac2e..18a328360 100644 --- a/wadsrc/static/zscript/games/blood/bloodactor.zs +++ b/wadsrc/static/zscript/games/blood/bloodactor.zs @@ -365,6 +365,7 @@ native void FireballTrapSeqCallback(); native void MGunFireSeqCallback(); native void MGunOpenSeqCallback(); native void fxFlameLick(); // 0 +native void Remove(); // 1 native void FlareBurst(); // 2 native void fxFlareSpark(); // 3 native void fxFlareSparkLite(); // 4 @@ -408,7 +409,7 @@ native void DropVoodooCb(); // unused native void ChangeType(class newtype); native static BloodActor InsertSprite(sectortype pSector, int nStat, Class cls); native void addX(); - native void evPostActorCallback(int delta, int callback); + native void evPostActorCallback(int delta, VMFunction callback); native double, double getActorExtents(); native int HitScan(double z, vector3 xyz, int clipmask, double clipdist); native void impactMissile(int hitcode); @@ -472,7 +473,7 @@ native void DropVoodooCb(); // unused } if (itemtype is 'BloodFlagBase' && gGameOptions.nGameType == Blood.kTeamplay) { - spawned.evPostActorCallback(1800, AF(returnFlagToBase)); + spawned.evPostActorCallback(1800, "BloodActor.returnFlagToBase"); } double top, bottom; @@ -527,7 +528,7 @@ native void DropVoodooCb(); // unused spawned.cstat |= CSTAT_SPRITE_BLOCK; spawned.xspr.target = null; - spawned.evPostActorCallback(600, AF(Remove)); + spawned.evPostActorCallback(600, "BloodActor.Remove"); spawned.initMissile(self); // handle type specific init.