reference event callbacks by name, not by internal index.

This is needed to allow writing new callbacks.
This commit is contained in:
Christoph Oelckers 2023-10-06 00:26:25 +02:00
parent 47f09c61fc
commit 11f094c7fb
14 changed files with 92 additions and 20 deletions

View file

@ -1639,6 +1639,23 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
// don't go through the entire list if the types are the same. // don't go through the entire list if the types are the same.
goto basereturn; 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<FxConstant*>(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()) else if (basex->ValueType == TypeNullPtr && ValueType->isPointer())
{ {
goto basereturn; goto basereturn;

View file

@ -506,6 +506,13 @@ public:
isresolved = true; 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) FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
{ {
value.pointer = nullptr; value.pointer = nullptr;

View file

@ -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 // Sorting helpers

View file

@ -75,6 +75,7 @@ PStruct *TypeStringStruct;
PStruct* TypeQuaternionStruct; PStruct* TypeQuaternionStruct;
PPointer *TypeNullPtr; PPointer *TypeNullPtr;
PPointer *TypeVoidPtr; PPointer *TypeVoidPtr;
PPointer* TypeVMFunction;
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
@ -322,6 +323,7 @@ void PType::StaticInit()
TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID); TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID);
TypeVoidPtr = NewPointer(TypeVoid, false); 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. 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); TypeStringStruct = NewStruct("Stringstruct", nullptr, true);
TypeQuaternionStruct = NewStruct("QuatStruct", nullptr, true); TypeQuaternionStruct = NewStruct("QuatStruct", nullptr, true);

View file

@ -697,6 +697,8 @@ extern PPointer *TypeFont;
extern PStateLabel *TypeStateLabel; extern PStateLabel *TypeStateLabel;
extern PPointer *TypeNullPtr; extern PPointer *TypeNullPtr;
extern PPointer *TypeVoidPtr; extern PPointer *TypeVoidPtr;
extern PPointer* TypeVMFunction;
inline FString &DObject::StringVar(FName field) inline FString &DObject::StringVar(FName field)
{ {

View file

@ -797,6 +797,7 @@ class AActor;
class PFunction; class PFunction;
VMFunction *FindVMFunction(PClass *cls, const char *name); 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); #define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
FString FStringFormat(VM_ARGS, int offset = 0); FString FStringFormat(VM_ARGS, int offset = 0);

View file

@ -66,8 +66,8 @@ int ZCCRazeCompiler::Compile()
CompileAllConstants(); CompileAllConstants();
CompileAllFields(); CompileAllFields();
CompileAllProperties(); CompileAllProperties();
InitDefaults();
InitFunctions(); InitFunctions();
InitDefaults();
return FScriptPosition::ErrorCounter; return FScriptPosition::ErrorCounter;
} }
@ -608,6 +608,16 @@ void ZCCRazeCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *
{ {
*(FName*)addr = GetStringConst(ex, ctx); *(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) else if (f->Type == TypeSound)
{ {
*(FSoundID*)addr = S_FindSound(GetStringConst(ex, ctx)); *(FSoundID*)addr = S_FindSound(GetStringConst(ex, ctx));

View file

@ -184,6 +184,7 @@ void actFireVector(DBloodActor* shooter, double offset, double zoffset, DVector3
void actPostSprite(DBloodActor* actor, int status); void actPostSprite(DBloodActor* actor, int status);
void actPostProcess(void); void actPostProcess(void);
void MakeSplash(DBloodActor *actor); void MakeSplash(DBloodActor *actor);
void callActorFunction(VMFunction* funcID, DBloodActor* actor);
extern const int16_t DudeDifficulty[]; extern const int16_t DudeDifficulty[];

View file

@ -268,7 +268,7 @@ DEF_ANIMATOR(LeechStateTimer) // 20
DEF_ANIMATOR(DropVoodooCb) // unused DEF_ANIMATOR(DropVoodooCb) // unused
DEF_ANIMATOR(callbackMakeMissileBlocking) DEF_ANIMATOR(callbackMakeMissileBlocking)
DEF_ANIMATOR(GenDudeUpdate) DEF_ANIMATOR(callbackGenDudeUpdate)
DEF_ANIMATOR(callbackUniMissileBurst) DEF_ANIMATOR(callbackUniMissileBurst)
enum EFeatureFlags enum EFeatureFlags

View file

@ -2462,7 +2462,7 @@ void useObjResizer(DBloodActor* sourceactor, int targType, sectortype* targSect,
targetactor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; targetactor->genDudeExtra.updReq[kGenDudePropertyAttack] = true;
targetactor->genDudeExtra.updReq[kGenDudePropertyMass] = true; targetactor->genDudeExtra.updReq[kGenDudePropertyMass] = true;
targetactor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = 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: case kDudeModernCustomBurning:
objActor->genDudeExtra.updReq[kGenDudePropertyWeapon] = true; objActor->genDudeExtra.updReq[kGenDudePropertyWeapon] = true;
objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true;
evPostActor(objActor, kGenDudeUpdTimeRate, AF(GenDudeUpdate)); evPostActor(objActor, kGenDudeUpdTimeRate, AF(callbackGenDudeUpdate));
break; break;
} }
return true; return true;
@ -7629,7 +7629,7 @@ bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodAc
objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true; objActor->genDudeExtra.updReq[kGenDudePropertyDmgScale] = true;
objActor->genDudeExtra.updReq[kGenDudePropertyStates] = true; objActor->genDudeExtra.updReq[kGenDudePropertyStates] = true;
objActor->genDudeExtra.updReq[kGenDudePropertyAttack] = true; objActor->genDudeExtra.updReq[kGenDudePropertyAttack] = true;
evPostActor(objActor, kGenDudeUpdTimeRate, AF(GenDudeUpdate)); evPostActor(objActor, kGenDudeUpdTimeRate, AF(callbackGenDudeUpdate));
break; break;
} }
return true; return true;

View file

@ -408,11 +408,21 @@ DBloodActor* actFireMissile(DBloodActor* actor, double xyoff, double zoff, DVect
DBloodActor* spawned; DBloodActor* spawned;
VMReturn ret((void**)&spawned); VMReturn ret((void**)&spawned);
VMValue param[] = { actor, xyoff, zoff, dv.X, dv.Y, dv.Z, ty}; 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 spawned;
} }
return nullptr; return nullptr;
} }
void callActorFunction(VMFunction* funcID, DBloodActor* actor)
{
if (funcID)
{
VMValue param[] = { actor };
VMCall(funcID, param, 1, nullptr, 0);
}
}
END_BLD_NS END_BLD_NS

View file

@ -937,3 +937,8 @@ struct QuatStruct native
// native double LengthSquared(); // native double LengthSquared();
// native Quat Unit(); // 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")
{
}

View file

@ -3,7 +3,7 @@ class BloodMissileBase : BloodActor
meta double speed; meta double speed;
meta double defclipdist; meta double defclipdist;
meta double angleofs; meta double angleofs;
meta int callbackID; // make this a function name later meta VMFunction callback;
meta int spawnsoundID; meta int spawnsoundID;
meta Sound spawnsound; meta Sound spawnsound;
meta double movementAdd; meta double movementAdd;
@ -16,7 +16,7 @@ class BloodMissileBase : BloodActor
property speed: speed; property speed: speed;
property clipdist: defclipdist; property clipdist: defclipdist;
property angleofs: angleofs; property angleofs: angleofs;
property callbackID: callbackID; property callback: callback;
property spawnsound: spawnsound; property spawnsound: spawnsound;
property spawnsoundID: spawnsoundID; property spawnsoundID: spawnsoundID;
property movementAdd: movementAdd; property movementAdd: movementAdd;
@ -27,7 +27,6 @@ class BloodMissileBase : BloodActor
default default
{ {
callbackID -1;
seqID -1; seqID -1;
spawnsoundID -1; spawnsoundID -1;
seqCallbackID -1; seqCallbackID -1;
@ -48,9 +47,9 @@ class BloodMissileBase : BloodActor
{ {
self.seqSpawnID(self.seqID, self.seqCallbackID); 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) if (self.spawnsound != 0)
{ {
@ -93,7 +92,7 @@ class BloodMissileFlareRegular : BloodMissileBase
scale 0.500000, 0.500000; scale 0.500000, 0.500000;
shade -128; shade -128;
clipdist 8.000000; clipdist 8.000000;
callbackID kCallbackFXFlareSpark; callback "BloodActor.fxFlareSpark";
spawnsoundID 422; spawnsoundID 422;
} }
} }
@ -106,7 +105,7 @@ class BloodMissileTeslaAlt : BloodMissileBase
scale 0.500000, 0.500000; scale 0.500000, 0.500000;
shade -128; shade -128;
clipdist 8.000000; clipdist 8.000000;
callbackID kCallbackFXTeslaAlt; callback "BloodActor.fxTeslaAlt";
} }
} }
class BloodMissileFlareAlt : BloodMissileBase class BloodMissileFlareAlt : BloodMissileBase
@ -118,14 +117,14 @@ class BloodMissileFlareAlt : BloodMissileBase
scale 0.500000, 0.500000; scale 0.500000, 0.500000;
shade -128; shade -128;
clipdist 1.000000; clipdist 1.000000;
callbackID kCallbackFXFlareSpark; callback "BloodActor.fxFlareSpark";
spawnsoundID 422; spawnsoundID 422;
} }
override void initMissile(BloodActor spawner) override void initMissile(BloodActor spawner)
{ {
super.initMissile(spawner); super.initMissile(spawner);
self.evPostActorCallback(30, kCallbackFXFlareBurst); self.evPostActorCallback(30, "BloodActor.FlareBurst");
} }
} }
class BloodMissileFlameSpray : BloodMissileBase class BloodMissileFlameSpray : BloodMissileBase
@ -278,7 +277,7 @@ class BloodMissileLifeLeechRegular : BloodMissileBase
scale 0.500000, 0.500000; scale 0.500000, 0.500000;
shade -128; shade -128;
clipdist 4.000000; clipdist 4.000000;
callbackID kCallbackFXFlameLick; callback "BloodActor.fxFlameLick";
} }
} }
class BloodMissileLifeLeechAltNormal : BloodMissileBase class BloodMissileLifeLeechAltNormal : BloodMissileBase
@ -301,7 +300,7 @@ class BloodMissileLifeLeechAltSmall : BloodMissileBase
scale 0.500000, 0.500000; scale 0.500000, 0.500000;
shade -128; shade -128;
clipdist 4.000000; clipdist 4.000000;
callbackID kCallbackFXArcSpark; callback "BloodActor.fxArcSpark";
} }
} }

View file

@ -365,6 +365,7 @@ native void FireballTrapSeqCallback();
native void MGunFireSeqCallback(); native void MGunFireSeqCallback();
native void MGunOpenSeqCallback(); native void MGunOpenSeqCallback();
native void fxFlameLick(); // 0 native void fxFlameLick(); // 0
native void Remove(); // 1
native void FlareBurst(); // 2 native void FlareBurst(); // 2
native void fxFlareSpark(); // 3 native void fxFlareSpark(); // 3
native void fxFlareSparkLite(); // 4 native void fxFlareSparkLite(); // 4
@ -408,7 +409,7 @@ native void DropVoodooCb(); // unused
native void ChangeType(class<BloodActor> newtype); native void ChangeType(class<BloodActor> newtype);
native static BloodActor InsertSprite(sectortype pSector, int nStat, Class<BloodActor> cls); native static BloodActor InsertSprite(sectortype pSector, int nStat, Class<BloodActor> cls);
native void addX(); native void addX();
native void evPostActorCallback(int delta, int callback); native void evPostActorCallback(int delta, VMFunction callback);
native double, double getActorExtents(); native double, double getActorExtents();
native int HitScan(double z, vector3 xyz, int clipmask, double clipdist); native int HitScan(double z, vector3 xyz, int clipmask, double clipdist);
native void impactMissile(int hitcode); native void impactMissile(int hitcode);
@ -472,7 +473,7 @@ native void DropVoodooCb(); // unused
} }
if (itemtype is 'BloodFlagBase' && gGameOptions.nGameType == Blood.kTeamplay) if (itemtype is 'BloodFlagBase' && gGameOptions.nGameType == Blood.kTeamplay)
{ {
spawned.evPostActorCallback(1800, AF(returnFlagToBase)); spawned.evPostActorCallback(1800, "BloodActor.returnFlagToBase");
} }
double top, bottom; double top, bottom;
@ -527,7 +528,7 @@ native void DropVoodooCb(); // unused
spawned.cstat |= CSTAT_SPRITE_BLOCK; spawned.cstat |= CSTAT_SPRITE_BLOCK;
spawned.xspr.target = null; spawned.xspr.target = null;
spawned.evPostActorCallback(600, AF(Remove)); spawned.evPostActorCallback(600, "BloodActor.Remove");
spawned.initMissile(self); // handle type specific init. spawned.initMissile(self); // handle type specific init.