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.
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())
{
goto basereturn;

View file

@ -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;

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

View file

@ -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);

View file

@ -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)
{

View file

@ -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);

View file

@ -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));

View file

@ -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[];

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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")
{
}

View file

@ -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";
}
}

View file

@ -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<BloodActor> newtype);
native static BloodActor InsertSprite(sectortype pSector, int nStat, Class<BloodActor> 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.