From 980c9863058c8ab1d0894f9525676440073c2572 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Nov 2016 19:20:31 +0100 Subject: [PATCH] - allow defining native fields through scripts. Internally this only requires exporting the address, but not the entire field. - added new VARF_Transient flag so that the decision whether to serialize a field does not depend solely on its native status. It may actually make a lot of sense to use the auto-serializer for native fields, too, as this would eliminate a lot of maintenance code. - defined (u)int8/16 as aliases to the byte and short types (Can't we not just get rid of this naming convention already...?) - exporting the fields of Actor revealed a few name clashes between them and some global types, so Actor.Sector was renamed to CurSector and Actor.Inventory was renamed to Actor.Inv. --- src/__autostart.cpp | 6 +- src/autosegs.h | 4 + src/dobjtype.cpp | 22 +- src/dobjtype.h | 7 +- src/namedef.h | 4 + src/p_mobj.cpp | 317 +++++++++++------------ src/p_pspr.cpp | 8 +- src/p_user.cpp | 2 +- src/sc_man_scanner.re | 4 + src/sc_man_tokens.h | 4 + src/scripting/codegeneration/codegen.cpp | 23 +- src/scripting/thingdef.h | 1 + src/scripting/thingdef_data.cpp | 55 ++++ src/scripting/vm/vm.h | 40 +++ src/scripting/zscript/zcc_compile.cpp | 43 ++- src/scripting/zscript/zcc_compile.h | 2 +- src/scripting/zscript/zcc_parser.cpp | 4 + src/zzautozend.cpp | 4 + wadsrc/static/zscript/actor.txt | 162 ++++++++++++ wadsrc/static/zscript/base.txt | 6 +- wadsrc/static/zscript/doom/bossbrain.txt | 2 +- wadsrc/static/zscript/shared/player.txt | 2 +- 22 files changed, 520 insertions(+), 202 deletions(-) diff --git a/src/__autostart.cpp b/src/__autostart.cpp index 280c3b13d..3daabbeae 100644 --- a/src/__autostart.cpp +++ b/src/__autostart.cpp @@ -53,7 +53,7 @@ // for initialized read-only data.) #pragma comment(linker, "/merge:.areg=.rdata /merge:.creg=.rdata /merge:.greg=.rdata") -#pragma comment(linker, "/merge:.yreg=.rdata") +#pragma comment(linker, "/merge:.yreg=.rdata /merge:.freg=.rdata") #pragma section(".areg$a",read) __declspec(allocate(".areg$a")) void *const ARegHead = 0; @@ -64,6 +64,9 @@ __declspec(allocate(".creg$a")) void *const CRegHead = 0; #pragma section(".greg$a",read) __declspec(allocate(".greg$a")) void *const GRegHead = 0; +#pragma section(".freg$a",read) +__declspec(allocate(".freg$a")) void *const FRegHead = 0; + #pragma section(".yreg$a",read) __declspec(allocate(".yreg$a")) void *const YRegHead = 0; @@ -97,6 +100,7 @@ __declspec(allocate(".yreg$a")) void *const YRegHead = 0; void *const ARegHead __attribute__((section(SECTION_AREG))) = 0; void *const CRegHead __attribute__((section(SECTION_CREG))) = 0; +void *const FRegHead __attribute__((section(SECTION_FREG))) = 0; void *const GRegHead __attribute__((section(SECTION_GREG))) = 0; void *const YRegHead __attribute__((section(SECTION_YREG))) = 0; diff --git a/src/autosegs.h b/src/autosegs.h index 08abe7cd3..f38e3628e 100644 --- a/src/autosegs.h +++ b/src/autosegs.h @@ -49,6 +49,10 @@ extern REGINFO ARegTail; extern REGINFO CRegHead; extern REGINFO CRegTail; +// List of class fields +extern REGINFO FRegHead; +extern REGINFO FRegTail; + // List of properties extern REGINFO GRegHead; extern REGINFO GRegTail; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 420dbc515..5afb8a578 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -613,8 +613,8 @@ void PType::StaticInit() TypeVector3->AddField(NAME_X, TypeFloat64); TypeVector3->AddField(NAME_Y, TypeFloat64); TypeVector3->AddField(NAME_Z, TypeFloat64); - // allow accessing xy as a vector2. This is marked native because it's not supposed to be serialized. - TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Native, 0)); + // allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient + TypeVector3->Symbols.AddSymbol(new PField(NAME_XY, TypeVector2, VARF_Transient, 0)); TypeTable.AddType(TypeVector3); TypeVector3->loadOp = OP_LV3; TypeVector3->storeOp = OP_SV3; @@ -2240,7 +2240,7 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArrayFlags & VARF_Native)) + if (!(field->Flags & VARF_Transient)) { field->Type->SetDefaultValue(base, unsigned(offset + field->Offset), special); } @@ -2257,7 +2257,7 @@ void PStruct::SetPointer(void *base, unsigned offset, TArray *special) c { for (const PField *field : Fields) { - if (!(field->Flags & VARF_Native)) + if (!(field->Flags & VARF_Transient)) { field->Type->SetPointer(base, unsigned(offset + field->Offset), special); } @@ -2307,8 +2307,8 @@ void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArrayFlags & VARF_Native)) + // Skip fields without or with native serialization + if (!(field->Flags & VARF_Transient)) { field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset); } @@ -2394,7 +2394,7 @@ PField *PStruct::AddField(FName name, PType *type, DWORD flags) PField *PStruct::AddNativeField(FName name, PType *type, size_t address, DWORD flags, int bitvalue) { - PField *field = new PField(name, type, flags|VARF_Native, address, bitvalue); + PField *field = new PField(name, type, flags|VARF_Native|VARF_Transient, address, bitvalue); if (Symbols.AddSymbol(field) == nullptr) { // name is already in use @@ -2495,8 +2495,7 @@ PField::PField() PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue) : PSymbol(name), Offset(offset), Type(type), Flags(flags) { - BitValue = bitvalue; - if (bitvalue != -1) + if (bitvalue != 0) { BitValue = 0; unsigned val = bitvalue; @@ -2519,6 +2518,7 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue I_FatalError("Trying to create an invalid bit field element: %s", name.GetChars()); } } + else BitValue = -1; } /* PPrototype *************************************************************/ @@ -2692,10 +2692,10 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void * if (type != NULL) { RecurseWriteFields(type->ParentClass, ar, addr); - // Don't write this part if it has no non-native variables + // Don't write this part if it has no non-transient variables for (unsigned i = 0; i < type->Fields.Size(); ++i) { - if (!(type->Fields[i]->Flags & VARF_Native)) + if (!(type->Fields[i]->Flags & VARF_Transient)) { // Tag this section with the class it came from in case // a more-derived class has variables that shadow a less- diff --git a/src/dobjtype.h b/src/dobjtype.h index f464e36f8..76d6e7585 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -19,7 +19,7 @@ enum VARF_Optional = (1<<0), // func param is optional VARF_Method = (1<<1), // func has an implied self parameter VARF_Action = (1<<2), // func has implied owner and state parameters - VARF_Native = (1<<3), // func is native code/don't auto serialize field + VARF_Native = (1<<3), // func is native code, field is natively defined VARF_ReadOnly = (1<<4), // field is read only, do not write to it VARF_Private = (1<<5), // field is private to containing class VARF_Protected = (1<<6), // field is only accessible by containing class and children. @@ -33,6 +33,7 @@ enum VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. VARF_Override = (1<<15), // overrides a virtual function from the parent class. VARF_Ref = (1<<16), // argument is passed by reference. + VARF_Transient = (1<<17) // don't auto serialize field. }; // Symbol information ------------------------------------------------------- @@ -610,7 +611,7 @@ class PField : public PSymbol DECLARE_CLASS(PField, PSymbol); HAS_OBJECT_POINTERS public: - PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = -1); + PField(FName name, PType *type, DWORD flags = 0, size_t offset = 0, int bitvalue = 0); size_t Offset; PType *Type; @@ -700,7 +701,7 @@ public: bool HasNativeFields; virtual PField *AddField(FName name, PType *type, DWORD flags=0); - virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = -1); + virtual PField *AddNativeField(FName name, PType *type, size_t address, DWORD flags = 0, int bitvalue = 0); size_t PropagateMark(); diff --git a/src/namedef.h b/src/namedef.h index 5ee98119a..545bf0260 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -695,6 +695,10 @@ xx(uShort) xx(Int) xx(uInt) xx(Bool) +xx(uint8) +xx(int8) +xx(uint16) +xx(int16) xx(Float) xx(Float32) xx(Float64) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index b7da3e2c5..181399655 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -156,171 +156,166 @@ AActor::~AActor () extern FFlagDef InternalActorFlagDefs[]; extern FFlagDef ActorFlagDefs[]; +DEFINE_FIELD(AActor, player) +DEFINE_FIELD_NAMED(AActor, __Pos, pos) +DEFINE_FIELD_NAMED(AActor, __Pos.X, x) +DEFINE_FIELD_NAMED(AActor, __Pos.Y, y) +DEFINE_FIELD_NAMED(AActor, __Pos.Z, z) +DEFINE_FIELD(AActor, Prev) +DEFINE_FIELD(AActor, SpriteAngle) +DEFINE_FIELD(AActor, SpriteRotation) +DEFINE_FIELD(AActor, VisibleStartAngle) +DEFINE_FIELD(AActor, VisibleStartPitch) +DEFINE_FIELD(AActor, VisibleEndAngle) +DEFINE_FIELD(AActor, VisibleEndPitch) +DEFINE_FIELD_NAMED(AActor, Angles.Yaw, angle) +DEFINE_FIELD_NAMED(AActor, Angles.Pitch, pitch) +DEFINE_FIELD_NAMED(AActor, Angles.Roll, roll) +DEFINE_FIELD(AActor, Vel) +DEFINE_FIELD_NAMED(AActor, Vel.X, velx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, vely) +DEFINE_FIELD_NAMED(AActor, Vel.Z, velz) +DEFINE_FIELD_NAMED(AActor, Vel.X, momx) +DEFINE_FIELD_NAMED(AActor, Vel.Y, momy) +DEFINE_FIELD_NAMED(AActor, Vel.Z, momz) +DEFINE_FIELD(AActor, Speed) +DEFINE_FIELD(AActor, FloatSpeed) +DEFINE_FIELD(AActor, sprite) +DEFINE_FIELD(AActor, frame) +DEFINE_FIELD(AActor, Scale) +DEFINE_FIELD_NAMED(AActor, Scale.X, scalex) +DEFINE_FIELD_NAMED(AActor, Scale.Y, scaley) +DEFINE_FIELD(AActor, RenderStyle) +DEFINE_FIELD(AActor, picnum) +DEFINE_FIELD(AActor, Alpha) +DEFINE_FIELD(AActor, fillcolor) +DEFINE_FIELD_NAMED(AActor, Sector, CurSector) // clashes with type 'sector'. +DEFINE_FIELD(AActor, subsector) +DEFINE_FIELD(AActor, ceilingz) +DEFINE_FIELD(AActor, floorz) +DEFINE_FIELD(AActor, dropoffz) +DEFINE_FIELD(AActor, floorsector) +DEFINE_FIELD(AActor, floorpic) +DEFINE_FIELD(AActor, floorterrain) +DEFINE_FIELD(AActor, ceilingsector) +DEFINE_FIELD(AActor, ceilingpic) +DEFINE_FIELD(AActor, Height) +DEFINE_FIELD(AActor, radius) +DEFINE_FIELD(AActor, projectilepassheight) +DEFINE_FIELD(AActor, tics) +DEFINE_FIELD_NAMED(AActor, state, curstate) // clashes with type 'state'. +DEFINE_FIELD_NAMED(AActor, DamageVal, Damage) // name differs for historic reasons +DEFINE_FIELD(AActor, projectileKickback) +DEFINE_FIELD(AActor, VisibleToTeam) +DEFINE_FIELD(AActor, special1) +DEFINE_FIELD(AActor, special2) +DEFINE_FIELD(AActor, specialf1) +DEFINE_FIELD(AActor, specialf2) +DEFINE_FIELD(AActor, weaponspecial) +DEFINE_FIELD(AActor, health) +DEFINE_FIELD(AActor, movedir) +DEFINE_FIELD(AActor, visdir) +DEFINE_FIELD(AActor, movecount) +DEFINE_FIELD(AActor, strafecount) +DEFINE_FIELD(AActor, target) +DEFINE_FIELD(AActor, master) +DEFINE_FIELD(AActor, tracer) +DEFINE_FIELD(AActor, LastHeard) +DEFINE_FIELD(AActor, lastenemy) +DEFINE_FIELD(AActor, LastLookActor) +DEFINE_FIELD(AActor, reactiontime) +DEFINE_FIELD(AActor, threshold) +DEFINE_FIELD(AActor, DefThreshold) +DEFINE_FIELD(AActor, SpawnPoint) +DEFINE_FIELD(AActor, SpawnAngle) +DEFINE_FIELD(AActor, StartHealth) +DEFINE_FIELD(AActor, WeaveIndexXY) +DEFINE_FIELD(AActor, WeaveIndexZ) +DEFINE_FIELD(AActor, skillrespawncount) +DEFINE_FIELD(AActor, args) +DEFINE_FIELD(AActor, Mass) +DEFINE_FIELD(AActor, special) +DEFINE_FIELD(AActor, tid) +DEFINE_FIELD(AActor, TIDtoHate) +DEFINE_FIELD(AActor, waterlevel) +DEFINE_FIELD(AActor, Score) +DEFINE_FIELD(AActor, accuracy) +DEFINE_FIELD(AActor, stamina) +DEFINE_FIELD(AActor, meleerange) +DEFINE_FIELD(AActor, PainThreshold) +DEFINE_FIELD(AActor, Gravity) +DEFINE_FIELD(AActor, Floorclip) +DEFINE_FIELD(AActor, DamageType) +DEFINE_FIELD(AActor, DamageTypeReceived) +DEFINE_FIELD(AActor, FloatBobPhase) +DEFINE_FIELD(AActor, RipperLevel) +DEFINE_FIELD(AActor, RipLevelMin) +DEFINE_FIELD(AActor, RipLevelMax) +DEFINE_FIELD(AActor, Species) +DEFINE_FIELD(AActor, alternative) +DEFINE_FIELD(AActor, goal) +DEFINE_FIELD(AActor, MinMissileChance) +DEFINE_FIELD(AActor, LastLookPlayerNumber) +DEFINE_FIELD(AActor, SpawnFlags) +DEFINE_FIELD(AActor, meleethreshold) +DEFINE_FIELD(AActor, maxtargetrange) +DEFINE_FIELD(AActor, bouncefactor) +DEFINE_FIELD(AActor, wallbouncefactor) +DEFINE_FIELD(AActor, bouncecount) +DEFINE_FIELD(AActor, Friction) +DEFINE_FIELD(AActor, FastChaseStrafeCount) +DEFINE_FIELD(AActor, pushfactor) +DEFINE_FIELD(AActor, lastpush) +DEFINE_FIELD(AActor, activationtype) +DEFINE_FIELD(AActor, lastbump) +DEFINE_FIELD(AActor, DesignatedTeam) +DEFINE_FIELD(AActor, BlockingMobj) +DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, PoisonDamage) +DEFINE_FIELD(AActor, PoisonDamageType) +DEFINE_FIELD(AActor, PoisonDuration) +DEFINE_FIELD(AActor, PoisonPeriod) +DEFINE_FIELD(AActor, PoisonDamageReceived) +DEFINE_FIELD(AActor, PoisonDamageTypeReceived) +DEFINE_FIELD(AActor, PoisonDurationReceived) +DEFINE_FIELD(AActor, PoisonPeriodReceived) +DEFINE_FIELD(AActor, Poisoner) +DEFINE_FIELD_NAMED(AActor, Inventory, Inv) // clashes with type 'Inventory'. +DEFINE_FIELD(AActor, smokecounter) +DEFINE_FIELD(AActor, FriendPlayer) +DEFINE_FIELD(AActor, Translation) +DEFINE_FIELD(AActor, AttackSound) +DEFINE_FIELD(AActor, DeathSound) +DEFINE_FIELD(AActor, SeeSound) +DEFINE_FIELD(AActor, PainSound) +DEFINE_FIELD(AActor, ActiveSound) +DEFINE_FIELD(AActor, UseSound) +DEFINE_FIELD(AActor, BounceSound) +DEFINE_FIELD(AActor, WallBounceSound) +DEFINE_FIELD(AActor, CrushPainSound) +DEFINE_FIELD(AActor, MaxDropOffHeight) +DEFINE_FIELD(AActor, MaxStepHeight) +DEFINE_FIELD(AActor, PainChance) +DEFINE_FIELD(AActor, PainType) +DEFINE_FIELD(AActor, DeathType) +DEFINE_FIELD(AActor, DamageFactor) +DEFINE_FIELD(AActor, DamageMultiply) +DEFINE_FIELD(AActor, TeleFogSourceType) +DEFINE_FIELD(AActor, TeleFogDestType) +DEFINE_FIELD(AActor, SpawnState) +DEFINE_FIELD(AActor, SeeState) +DEFINE_FIELD(AActor, MeleeState) +DEFINE_FIELD(AActor, MissileState) +DEFINE_FIELD(AActor, ConversationRoot) +DEFINE_FIELD(AActor, Conversation) +DEFINE_FIELD(AActor, DecalGenerator) + + void AActor::InitNativeFields() { - PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); - PType *TypeActorClass = NewClassPointer(RUNTIME_CLASS(AActor)); - PType *TypeInventory = NewPointer(RUNTIME_CLASS(AInventory)); - PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); - auto TypeSector = NewPointer(NewNativeStruct("Sector", nullptr)); - PType *array5 = NewArray(TypeSInt32, 5); - auto meta = RUNTIME_CLASS(AActor); - - meta->AddNativeField("Player", TypePlayer, myoffsetof(AActor, player)); - meta->AddNativeField("Pos", TypeVector3, myoffsetof(AActor, __Pos), VARF_ReadOnly); - meta->AddNativeField(NAME_X, TypeFloat64, myoffsetof(AActor, __Pos.X), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField(NAME_Y, TypeFloat64, myoffsetof(AActor, __Pos.Y), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField(NAME_Z, TypeFloat64, myoffsetof(AActor, __Pos.Z), VARF_ReadOnly | VARF_Deprecated); // must remain read-only! - meta->AddNativeField("Prev", TypeVector3, myoffsetof(AActor, Prev)); - meta->AddNativeField("spriteAngle", TypeFloat64, myoffsetof(AActor, SpriteAngle)); - meta->AddNativeField("spriteRotation", TypeFloat64, myoffsetof(AActor, SpriteRotation)); - meta->AddNativeField(NAME_VisibleStartAngle, TypeFloat64, myoffsetof(AActor, VisibleStartAngle)); - meta->AddNativeField(NAME_VisibleStartPitch, TypeFloat64, myoffsetof(AActor, VisibleStartPitch)); - meta->AddNativeField(NAME_VisibleEndAngle, TypeFloat64, myoffsetof(AActor, VisibleEndAngle)); - meta->AddNativeField(NAME_VisibleEndPitch, TypeFloat64, myoffsetof(AActor, VisibleEndPitch)); - meta->AddNativeField(NAME_Angle, TypeFloat64, myoffsetof(AActor, Angles.Yaw)); - meta->AddNativeField(NAME_Pitch, TypeFloat64, myoffsetof(AActor, Angles.Pitch)); - meta->AddNativeField(NAME_Roll, TypeFloat64, myoffsetof(AActor, Angles.Roll)); - meta->AddNativeField("Vel", TypeVector3, myoffsetof(AActor, Vel)); - meta->AddNativeField(NAME_VelX, TypeFloat64, myoffsetof(AActor, Vel.X), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_VelY, TypeFloat64, myoffsetof(AActor, Vel.Y), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_VelZ, TypeFloat64, myoffsetof(AActor, Vel.Z), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomX, TypeFloat64, myoffsetof(AActor, Vel.X), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomY, TypeFloat64, myoffsetof(AActor, Vel.Y), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_MomZ, TypeFloat64, myoffsetof(AActor, Vel.Z), VARF_ReadOnly | VARF_Deprecated); - meta->AddNativeField(NAME_Speed, TypeFloat64, myoffsetof(AActor, Speed)); - meta->AddNativeField("FloatSpeed", TypeFloat64, myoffsetof(AActor, FloatSpeed)); - meta->AddNativeField("sprite", TypeSpriteID, myoffsetof(AActor, sprite)); - meta->AddNativeField("frame", TypeUInt8, myoffsetof(AActor, frame)); - meta->AddNativeField("Scale", TypeVector2, myoffsetof(AActor, Scale)); - meta->AddNativeField(NAME_ScaleX, TypeFloat64, myoffsetof(AActor, Scale.X), VARF_Deprecated); - meta->AddNativeField(NAME_ScaleY, TypeFloat64, myoffsetof(AActor, Scale.Y), VARF_Deprecated); - //FRenderStyle RenderStyle; // how do we expose this? - meta->AddNativeField("picnum", TypeSInt32, myoffsetof(AActor, picnum)); // Do we need a variable type 'texture' to do this? - meta->AddNativeField(NAME_Alpha, TypeFloat64, myoffsetof(AActor, Alpha)); - meta->AddNativeField("fillcolor", TypeColor, myoffsetof(AActor, fillcolor)); - meta->AddNativeField("Sector", TypeSector, myoffsetof(AActor, Sector)); - //meta->AddNativeField("Subsector", TypeSubsector, myoffsetof(AActor, subsector)); - meta->AddNativeField(NAME_CeilingZ, TypeFloat64, myoffsetof(AActor, ceilingz)); - meta->AddNativeField(NAME_FloorZ, TypeFloat64, myoffsetof(AActor, floorz)); - meta->AddNativeField("DropoffZ", TypeFloat64, myoffsetof(AActor, dropoffz), VARF_ReadOnly); - meta->AddNativeField("floorsector", TypeSector, myoffsetof(AActor, floorsector)); - meta->AddNativeField("floorpic", TypeTextureID, myoffsetof(AActor, floorpic)); - meta->AddNativeField("floorterrain", TypeSInt32, myoffsetof(AActor, floorterrain)); - meta->AddNativeField("ceilingsector", TypeSector, myoffsetof(AActor, ceilingsector)); - meta->AddNativeField("ceilingpic", TypeSInt32, myoffsetof(AActor, ceilingpic)); // Do we need a variable type 'texture' to do this? - meta->AddNativeField(NAME_Height, TypeFloat64, myoffsetof(AActor, Height)); - meta->AddNativeField(NAME_Radius, TypeFloat64, myoffsetof(AActor, radius), VARF_ReadOnly); - meta->AddNativeField("projectilepassheight",TypeFloat64, myoffsetof(AActor, projectilepassheight)); - meta->AddNativeField("tics", TypeSInt32, myoffsetof(AActor, tics)); - meta->AddNativeField("CurState", TypeState, myoffsetof(AActor, state), VARF_ReadOnly); // has to be renamed on the script side because it clashes with the same named type. - meta->AddNativeField(NAME_Damage, TypeSInt32, myoffsetof(AActor, DamageVal), VARF_ReadOnly); - meta->AddNativeField("projectilekickback", TypeSInt32, myoffsetof(AActor, projectileKickback)); - //DWORD VisibleToTeam; - meta->AddNativeField("special1", TypeSInt32, myoffsetof(AActor, special1)); - meta->AddNativeField("special2", TypeSInt32, myoffsetof(AActor, special2)); - meta->AddNativeField("specialf1", TypeFloat64, myoffsetof(AActor, specialf1)); - meta->AddNativeField("specialf2", TypeFloat64, myoffsetof(AActor, specialf2)); - meta->AddNativeField("weaponspecial", TypeSInt32, myoffsetof(AActor, weaponspecial)); - meta->AddNativeField(NAME_Health, TypeSInt32, myoffsetof(AActor, health)); - meta->AddNativeField("movedir", TypeUInt8, myoffsetof(AActor, movedir)); - meta->AddNativeField("visdir", TypeSInt8, myoffsetof(AActor, visdir)); - meta->AddNativeField("movecount", TypeSInt16, myoffsetof(AActor, movecount)); - meta->AddNativeField("strafecount", TypeSInt16, myoffsetof(AActor, strafecount)); - meta->AddNativeField(NAME_Target, TypeActor, myoffsetof(AActor, target)); - meta->AddNativeField(NAME_Master, TypeActor, myoffsetof(AActor, master)); - meta->AddNativeField(NAME_Tracer, TypeActor, myoffsetof(AActor, tracer)); - meta->AddNativeField("LastHeard", TypeActor, myoffsetof(AActor, LastHeard)); - meta->AddNativeField("LastEnemy", TypeActor, myoffsetof(AActor, lastenemy)); - meta->AddNativeField("LastLookActor", TypeActor, myoffsetof(AActor, LastLookActor)); - meta->AddNativeField(NAME_ReactionTime, TypeSInt32, myoffsetof(AActor, reactiontime)); - meta->AddNativeField(NAME_Threshold, TypeSInt32, myoffsetof(AActor, threshold)); - meta->AddNativeField(NAME_DefThreshold, TypeSInt32, myoffsetof(AActor, DefThreshold), VARF_ReadOnly); - meta->AddNativeField("SpawnPoint", TypeVector3, myoffsetof(AActor, SpawnPoint), VARF_ReadOnly); - meta->AddNativeField("SpawnAngle", TypeUInt16, myoffsetof(AActor, SpawnAngle), VARF_ReadOnly); - meta->AddNativeField("StartHealth", TypeSInt32, myoffsetof(AActor, StartHealth)); - meta->AddNativeField("WeaveIndexXY", TypeUInt16, myoffsetof(AActor, WeaveIndexXY)); - meta->AddNativeField("WeaveIndexZ", TypeUInt16, myoffsetof(AActor, WeaveIndexZ)); - meta->AddNativeField("skillrespawncount", TypeSInt32, myoffsetof(AActor, skillrespawncount)); - meta->AddNativeField(NAME_Args, array5, myoffsetof(AActor, args)); - meta->AddNativeField(NAME_Mass, TypeSInt32, myoffsetof(AActor, Mass)); - meta->AddNativeField(NAME_Special, TypeSInt32, myoffsetof(AActor, special)); - meta->AddNativeField(NAME_TID, TypeSInt32, myoffsetof(AActor, tid), VARF_ReadOnly); - meta->AddNativeField(NAME_TIDtoHate, TypeSInt32, myoffsetof(AActor, TIDtoHate), VARF_ReadOnly); - meta->AddNativeField(NAME_WaterLevel, TypeSInt32, myoffsetof(AActor, waterlevel), VARF_ReadOnly); - meta->AddNativeField(NAME_Score, TypeSInt32, myoffsetof(AActor, Score)); - meta->AddNativeField(NAME_Accuracy, TypeSInt32, myoffsetof(AActor, accuracy)); - meta->AddNativeField(NAME_Stamina, TypeSInt32, myoffsetof(AActor, stamina)); - meta->AddNativeField(NAME_MeleeRange, TypeFloat64, myoffsetof(AActor, meleerange)); - meta->AddNativeField("PainThreshold", TypeSInt32, myoffsetof(AActor, PainThreshold)); - meta->AddNativeField("Gravity", TypeFloat64, myoffsetof(AActor, Gravity)); - meta->AddNativeField("FloorClip", TypeFloat64, myoffsetof(AActor, Floorclip)); - meta->AddNativeField("DamageType", TypeName, myoffsetof(AActor, DamageType)); - meta->AddNativeField("DamageTypeReceived", TypeName, myoffsetof(AActor, DamageTypeReceived)); - meta->AddNativeField("FloatBobPhase", TypeUInt8, myoffsetof(AActor, FloatBobPhase)); - meta->AddNativeField("RipperLevel", TypeSInt32, myoffsetof(AActor, RipperLevel)); - meta->AddNativeField("RipLevelMin", TypeSInt32, myoffsetof(AActor, RipLevelMin)); - meta->AddNativeField("RipLevelMax", TypeSInt32, myoffsetof(AActor, RipLevelMax)); - meta->AddNativeField("Species", TypeName, myoffsetof(AActor, Species)); - meta->AddNativeField("Alternative", TypeActor, myoffsetof(AActor, alternative)); - meta->AddNativeField("goal", TypeActor, myoffsetof(AActor, goal)); - meta->AddNativeField("MinMissileChance", TypeUInt8, myoffsetof(AActor, MinMissileChance)); - meta->AddNativeField("LastLookPlayerNumber",TypeSInt8, myoffsetof(AActor, LastLookPlayerNumber)); - meta->AddNativeField("SpawnFlags", TypeUInt32, myoffsetof(AActor, SpawnFlags)); - meta->AddNativeField("meleethreshold", TypeFloat64, myoffsetof(AActor, meleethreshold)); - meta->AddNativeField("maxtargetrange", TypeFloat64, myoffsetof(AActor, maxtargetrange)); - meta->AddNativeField("bouncefactor", TypeFloat64, myoffsetof(AActor, bouncefactor)); - meta->AddNativeField("wallbouncefactor", TypeFloat64, myoffsetof(AActor, wallbouncefactor)); - meta->AddNativeField("bouncecount", TypeSInt32, myoffsetof(AActor, bouncecount)); - meta->AddNativeField("friction", TypeFloat64, myoffsetof(AActor, Friction)); - meta->AddNativeField("FastChaseStrafeCount",TypeSInt32, myoffsetof(AActor, FastChaseStrafeCount)); - meta->AddNativeField("pushfactor", TypeFloat64, myoffsetof(AActor, pushfactor)); - meta->AddNativeField("lastpush", TypeSInt32, myoffsetof(AActor, lastpush)); - meta->AddNativeField("activationtype", TypeSInt32, myoffsetof(AActor, activationtype)); - meta->AddNativeField("lastbump", TypeSInt32, myoffsetof(AActor, lastbump)); - meta->AddNativeField("DesignatedTeam", TypeSInt32, myoffsetof(AActor, DesignatedTeam)); - meta->AddNativeField("BlockingMobj", TypeActor, myoffsetof(AActor, BlockingMobj)); - //line_t *BlockingLine; // Line that blocked the last move - meta->AddNativeField("PoisonDamage", TypeSInt32, myoffsetof(AActor, PoisonDamage)); - meta->AddNativeField("PoisonDamageType", TypeName, myoffsetof(AActor, PoisonDamageType)); - meta->AddNativeField("PoisonDuration", TypeSInt32, myoffsetof(AActor, PoisonDuration)); - meta->AddNativeField("PoisonPeriod", TypeSInt32, myoffsetof(AActor, PoisonPeriod)); - meta->AddNativeField("PoisonDamageReceived",TypeSInt32, myoffsetof(AActor, PoisonDamageReceived)); - meta->AddNativeField("PoisonDamageTypeReceived", TypeName, myoffsetof(AActor, PoisonDamageTypeReceived)); - meta->AddNativeField("PoisonDurationReceived", TypeSInt32, myoffsetof(AActor, PoisonDurationReceived)); - meta->AddNativeField("PoisonPeriodReceived", TypeSInt32, myoffsetof(AActor, PoisonPeriodReceived)); - meta->AddNativeField("Poisoner", TypeActor, myoffsetof(AActor, Poisoner)); - meta->AddNativeField("Inv", TypeInventory, myoffsetof(AActor, Inventory)); // Needs to be renamed because it hides the actual type. - meta->AddNativeField("smokecounter", TypeUInt8, myoffsetof(AActor, smokecounter)); - meta->AddNativeField("FriendPlayer", TypeUInt8, myoffsetof(AActor, FriendPlayer)); - meta->AddNativeField("Translation", TypeUInt32, myoffsetof(AActor, Translation)); - meta->AddNativeField("AttackSound", TypeSound, myoffsetof(AActor, AttackSound)); - meta->AddNativeField("DeathSound", TypeSound, myoffsetof(AActor, DeathSound)); - meta->AddNativeField("SeeSound", TypeSound, myoffsetof(AActor, SeeSound)); - meta->AddNativeField("PainSound", TypeSound, myoffsetof(AActor, PainSound)); - meta->AddNativeField("ActiveSound", TypeSound, myoffsetof(AActor, ActiveSound)); - meta->AddNativeField("UseSound", TypeSound, myoffsetof(AActor, UseSound)); - meta->AddNativeField("BounceSound", TypeSound, myoffsetof(AActor, BounceSound)); - meta->AddNativeField("WallBounceSound", TypeSound, myoffsetof(AActor, WallBounceSound)); - meta->AddNativeField("CrushPainSound", TypeSound, myoffsetof(AActor, CrushPainSound)); - meta->AddNativeField("MaxDropoffHeight", TypeFloat64, myoffsetof(AActor, MaxDropOffHeight)); - meta->AddNativeField("MaxStepHeight", TypeFloat64, myoffsetof(AActor, MaxStepHeight)); - meta->AddNativeField("PainChance", TypeSInt16, myoffsetof(AActor, PainChance)); - meta->AddNativeField("PainType", TypeName, myoffsetof(AActor, PainType)); - meta->AddNativeField("DeathType", TypeName, myoffsetof(AActor, DeathType)); - meta->AddNativeField("DamageFactor", TypeFloat64, myoffsetof(AActor, DamageFactor)); - meta->AddNativeField("DamageMultiply", TypeFloat64, myoffsetof(AActor, DamageMultiply)); - meta->AddNativeField("TelefogSourceType", TypeActorClass, myoffsetof(AActor, TeleFogSourceType)); - meta->AddNativeField("TelefogDestType", TypeActorClass, myoffsetof(AActor, TeleFogDestType)); - meta->AddNativeField("SpawnState", TypeState, myoffsetof(AActor, SpawnState), VARF_ReadOnly); - meta->AddNativeField("SeeState", TypeState, myoffsetof(AActor, SeeState), VARF_ReadOnly); - meta->AddNativeField("MeleeState", TypeState, myoffsetof(AActor, MeleeState)); - meta->AddNativeField("MissileState", TypeState, myoffsetof(AActor, MissileState)); - //int ConversationRoot; // THe root of the current dialogue - //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is "used." + // needs to be done manually until it can be given a proper type. meta->AddNativeField("DecalGenerator", NewPointer(TypeVoid), myoffsetof(AActor, DecalGenerator)); - //FDecalBase *DecalGenerator; // synthesize a symbol for each flag from the flag name tables to avoid redundant declaration of them. for (size_t i = 0; ActorFlagDefs[i].flagbit != 0xffffffff; i++) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index b5f569108..f1cc8e792 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -200,7 +200,7 @@ DPSprite *player_t::FindPSprite(int layer) return pspr; } -DEFINE_ACTION_FUNCTION(_Player, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -220,7 +220,7 @@ void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending) player->GetPSprite(id)->SetState(state, pending); } -DEFINE_ACTION_FUNCTION(_Player, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -291,7 +291,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) return pspr; } -DEFINE_ACTION_FUNCTION(_Player, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +DEFINE_ACTION_FUNCTION(_PlayerInfo, GetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_INT(id); @@ -1653,7 +1653,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i P_SetPsprite(player, PSP_FLASH, flashstate + index, true); } -DEFINE_ACTION_FUNCTION(_Player, SetSafeFlash) +DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash) { PARAM_SELF_STRUCT_PROLOGUE(player_t); PARAM_OBJECT(weapon, AWeapon); diff --git a/src/p_user.cpp b/src/p_user.cpp index 84fcbd313..5b25fd713 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3147,7 +3147,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player) void P_InitPlayerForScript() { - PStruct *pstruct = NewNativeStruct("Player", nullptr); + PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr); pstruct->Size = sizeof(player_t); pstruct->Align = alignof(player_t); PArray *parray = NewArray(pstruct, MAXPLAYERS); diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 194582d73..59113e4a7 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -111,6 +111,10 @@ std2: 'sbyte' { RET(TK_SByte); } 'short' { RET(TK_Short); } 'ushort' { RET(TK_UShort); } + 'int8' { RET(TK_Int8); } + 'uint8' { RET(TK_UInt8); } + 'int16' { RET(TK_Int16); } + 'uint16' { RET(TK_UInt16); } 'int' { RET(TK_Int); } 'uint' { RET(TK_UInt); } 'long' { RET(TK_Long); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 801d02be3..8ea05d7e4 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -55,6 +55,10 @@ xx(TK_Byte, "'byte'") xx(TK_SByte, "'sbyte'") xx(TK_Short, "'short'") xx(TK_UShort, "'ushort'") +xx(TK_Int8, "'int8'") +xx(TK_UInt8, "'uint8'") +xx(TK_Int16, "'int16'") +xx(TK_UInt16, "'uint16'") xx(TK_Int, "'int'") xx(TK_UInt, "'uint'") xx(TK_Long, "'long'") diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 3f8f09eb7..1cc16214c 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -4082,7 +4082,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) build->Emit(OP_JMP, 1); auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1); for (auto addr : patchspots) build->Backpatch(addr, ctarget); - list.Clear(); + list.DeleteAndClear(); list.ShrinkToFit(); return to; } @@ -5232,6 +5232,8 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) // The result register needs to be in-use when we return. // It should have been freed earlier, so restore its in-use flag. resultreg.Reuse(build); + choices.DeleteAndClear(); + choices.ShrinkToFit(); return resultreg; } @@ -6303,7 +6305,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) { auto parentfield = static_cast(classx)->membervar; // PFields are garbage collected so this will be automatically taken care of later. - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -6313,7 +6316,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ExprType == EFX_GlobalVariable) { auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->membervar = newfield; classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -6323,7 +6327,8 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) else if (classx->ExprType == EFX_StackVariable) { auto parentfield = static_cast(classx)->membervar; - auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset, membervar->BitValue); + auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset); + newfield->BitValue = membervar->BitValue; static_cast(classx)->ReplaceField(newfield); classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away. auto x = classx->Resolve(ctx); @@ -7382,7 +7387,7 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build) assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); assert(((PSymbolVMFunction *)sym)->Function != nullptr); callfunc = ((PSymbolVMFunction *)sym)->Function; - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); if (EmitTail) @@ -7661,7 +7666,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) ExpEmit reg; if (CheckEmitCast(build, EmitTail, reg)) { - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); return reg; } @@ -7704,7 +7709,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { count += EmitParameter(build, ArgList[i], ScriptPosition); } - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); // Get a constant register for this function @@ -7905,7 +7910,7 @@ ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build) } build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop); - ArgList.Clear(); + ArgList.DeleteAndClear(); ArgList.ShrinkToFit(); return to; } @@ -8311,7 +8316,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build) build->BackpatchToHere(addr); } if (!defaultset) build->BackpatchToHere(DefaultAddress); - Content.Clear(); + Content.DeleteAndClear(); Content.ShrinkToFit(); return ExpEmit(); } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 5bad10c36..dd8529252 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -147,6 +147,7 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) //========================================================================== AFuncDesc *FindFunction(PStruct *cls, const char * string); +FieldDesc *FindField(PStruct *cls, const char * string); FxExpression *ParseExpression(FScanner &sc, PClassActor *cls, bool mustresolve = false); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 23aba902f..d50f73bd3 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -46,6 +46,7 @@ static TArray properties; static TArray AFTable; +static TArray FieldTable; //========================================================================== // @@ -613,6 +614,37 @@ AFuncDesc *FindFunction(PStruct *cls, const char * string) return nullptr; } +//========================================================================== +// +// Find a function by name using a binary search +// +//========================================================================== + +FieldDesc *FindField(PStruct *cls, const char * string) +{ + int min = 0, max = FieldTable.Size() - 1; + + while (min <= max) + { + int mid = (min + max) / 2; + int lexval = stricmp(cls->TypeName.GetChars(), FieldTable[mid].ClassName + 1); + if (lexval == 0) lexval = stricmp(string, FieldTable[mid].FieldName); + if (lexval == 0) + { + return &FieldTable[mid]; + } + else if (lexval > 0) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return nullptr; +} + //========================================================================== // @@ -651,6 +683,14 @@ static int funccmp(const void * a, const void * b) return res; } +static int fieldcmp(const void * a, const void * b) +{ + // +1 to get past the prefix letter of the native class name, which gets omitted by the FName for the class. + int res = stricmp(((FieldDesc*)a)->ClassName + 1, ((FieldDesc*)b)->ClassName + 1); + if (res == 0) res = stricmp(((FieldDesc*)a)->FieldName, ((FieldDesc*)b)->FieldName); + return res; +} + //========================================================================== // // Initialization @@ -716,4 +756,19 @@ void InitThingdef() AFTable.ShrinkToFit(); qsort(&AFTable[0], AFTable.Size(), sizeof(AFTable[0]), funccmp); } + + FieldTable.Clear(); + if (FieldTable.Size() == 0) + { + FAutoSegIterator probe(FRegHead, FRegTail); + + while (*++probe != NULL) + { + FieldDesc *afield = (FieldDesc *)*probe; + FieldTable.Push(*afield); + } + FieldTable.ShrinkToFit(); + qsort(&FieldTable[0], FieldTable.Size(), sizeof(FieldTable[0]), fieldcmp); + } + } diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 7d56b32db..f2edca9b9 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -1013,6 +1013,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ +struct FieldDesc +{ + const char *ClassName; + const char *FieldName; + unsigned FieldOffset; + unsigned FieldSize; + int BitValue; +}; + struct AFuncDesc { const char *ClassName; @@ -1023,12 +1032,17 @@ struct AFuncDesc #if defined(_MSC_VER) #pragma section(".areg$u",read) +#pragma section(".freg$u",read) #define MSVC_ASEG __declspec(allocate(".areg$u")) +#define MSVC_FSEG __declspec(allocate(".freg$u")) #define GCC_ASEG +#define GCC_FSEG #else #define MSVC_ASEG +#define MSVC_FSEG #define GCC_ASEG __attribute__((section(SECTION_AREG))) __attribute__((used)) +#define GCC_FSEG __attribute__((section(SECTION_FREG))) __attribute__((used)) #endif // Macros to handle action functions. These are here so that I don't have to @@ -1043,6 +1057,32 @@ struct AFuncDesc MSVC_ASEG AFuncDesc const *const cls##_##name##_HookPtr GCC_ASEG = &cls##_##name##_Hook; \ static int AF_##cls##_##name(VM_ARGS) +// cls is the scripted class name, icls the internal one (e.g. player_t vs. Player) +#define DEFINE_FIELD_X(cls, icls, name) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), 0 }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD_X_BIT(cls, icls, name, bitval) \ + static const FieldDesc VMField_##icls##_##name = { "A" #cls, #name, (unsigned)myoffsetof(icls, name), (unsigned)sizeof(icls::name), bitval }; \ + extern FieldDesc const *const VMField_##icls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##icls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD(cls, name) \ + static const FieldDesc VMField_##cls##_##name = { #cls, #name, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##name##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##name##_HookPtr GCC_FSEG = &VMField_##cls##_##name; + +#define DEFINE_FIELD_NAMED(cls, name, scriptname) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), 0 }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + +#define DEFINE_FIELD_BIT(cls, name, scriptname, bitval) \ + static const FieldDesc VMField_##cls##_##scriptname = { #cls, #scriptname, (unsigned)myoffsetof(cls, name), (unsigned)sizeof(cls::name), bitval }; \ + extern FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr; \ + MSVC_FSEG FieldDesc const *const VMField_##cls##_##scriptname##_HookPtr GCC_FSEG = &VMField_##cls##_##scriptname; + class AActor; void CallAction(VMFrameStack *stack, VMFunction *vmfunc, AActor *self); #define CALL_ACTION(name, self) CallAction(stack, AActor_##name##_VMPtr, self); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index c76df32e3..72bfcf735 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1186,6 +1186,7 @@ void ZCCCompiler::CompileAllFields() // Create copies of the arrays which can be altered auto Classes = this->Classes; auto Structs = this->Structs; + TMap HasNativeChildren; // first step: Look for native classes with native children. // These may not have any variables added to them because it'd clash with the native definitions. @@ -1200,8 +1201,8 @@ void ZCCCompiler::CompileAllFields() { if (ac->ParentClass == c->Type() && ac->Size != TentativeClass) { - Error(c->cls, "Trying to add fields to class '%s' with native children", c->Type()->TypeName.GetChars()); - Classes.Delete(i--); + // Only set a marker here, so that we can print a better message when the actual fields get added. + HasNativeChildren.Insert(ac, true); break; } } @@ -1236,7 +1237,7 @@ void ZCCCompiler::CompileAllFields() type->Size = Classes[i]->Type()->ParentClass->Size; } } - if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false)) + if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type))) { // Remove from the list if all fields got compiled. Classes.Delete(i--); @@ -1263,11 +1264,12 @@ void ZCCCompiler::CompileAllFields() // //========================================================================== -bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct) +bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren) { while (Fields.Size() > 0) { auto field = Fields[0]; + FieldDesc *fd = nullptr; PType *fieldtype = DetermineType(type, field, field->Names->Name, field->Type, true, true); @@ -1289,8 +1291,9 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Native) { - // todo: get the native address of this field. + varflags |= VARF_Native | VARF_Transient; } + if (field->Flags & ZCC_Meta) { varflags |= VARF_ReadOnly; // metadata implies readonly @@ -1312,8 +1315,32 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel { thisfieldtype = ResolveArraySize(thisfieldtype, name->ArraySize, &type->Symbols); } - - type->AddField(name->Name, thisfieldtype, varflags); + + if (varflags & VARF_Native) + { + fd = FindField(type, FName(name->Name).GetChars()); + if (fd == nullptr) + { + Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + } + else if (thisfieldtype->Size != fd->FieldSize) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else + { + type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } + } + else if (hasnativechildren) + { + Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", type->TypeName.GetChars(), fd->FieldSize, FName(name->Name).GetChars()); + } + else + { + type->AddField(name->Name, thisfieldtype, varflags); + } } name = static_cast(name->SiblingNext); } while (name != field->Names); @@ -2133,7 +2160,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool afd = FindFunction(c->Type(), FName(f->Name).GetChars()); if (afd == nullptr) { - Error(f, "The function '%s' has not been exported from the executable.", FName(f->Name).GetChars()); + Error(f, "The function '%s.%s' has not been exported from the executable.", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()); } else { diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index 84e314353..9599b4b96 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -91,7 +91,7 @@ private: bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols); void CompileAllFields(); - bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct); + bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index de3d2c7e1..37fd8ff0c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -137,6 +137,10 @@ static void InitTokenMap() TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short); TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort); + TOKENDEF2(TK_Int8, ZCC_SBYTE, NAME_int8); + TOKENDEF2(TK_UInt8, ZCC_BYTE, NAME_uint8); + TOKENDEF2(TK_Int16, ZCC_SHORT, NAME_int16); + TOKENDEF2(TK_UInt16, ZCC_USHORT, NAME_uint16); TOKENDEF2(TK_Int, ZCC_INT, NAME_Int); TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt); TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool); diff --git a/src/zzautozend.cpp b/src/zzautozend.cpp index 5567b1ddd..18c020310 100644 --- a/src/zzautozend.cpp +++ b/src/zzautozend.cpp @@ -43,6 +43,9 @@ __declspec(allocate(".areg$z")) void *const ARegTail = 0; #pragma section(".creg$z",read) __declspec(allocate(".creg$z")) void *const CRegTail = 0; +#pragma section(".freg$z",read) +__declspec(allocate(".freg$z")) void *const FRegTail = 0; + #pragma section(".greg$z",read) __declspec(allocate(".greg$z")) void *const GRegTail = 0; @@ -56,6 +59,7 @@ __declspec(allocate(".yreg$z")) void *const YRegTail = 0; void *const ARegTail __attribute__((section(SECTION_AREG))) = 0; void *const CRegTail __attribute__((section(SECTION_CREG))) = 0; +void *const FRegTail __attribute__((section(SECTION_FREG))) = 0; void *const GRegTail __attribute__((section(SECTION_GREG))) = 0; void *const YRegTail __attribute__((section(SECTION_YREG))) = 0; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index db86647c3..da9db687c 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -5,6 +5,168 @@ class Actor : Thinker native const ONCEILINGZ = 2147483647.0; const FLOATRANDZ = ONCEILINGZ-1; + // flags are not defined here, the native fields for those get synthesized from the internal tables. + + // for some comments on these fields, see their native representations in actor.h. + native PlayerInfo Player; + native readonly vector3 Pos; + native vector3 Prev; + native double spriteAngle; + native double spriteRotation; + native double VisibleStartAngle; + native double VisibleStartPitch; + native double VisibleEndAngle; + native double VisibleEndPitch; + native double Angle; + native double Pitch; + native double Roll; + native vector3 Vel; + native double Speed; + native double FloatSpeed; + native SpriteID sprite; + native uint8 frame; + native vector2 Scale; + native TextureID picnum; + native double Alpha; + native color fillcolor; + native Sector CurSector; + native double CeilingZ; + native double FloorZ; + native double DropoffZ; + native Sector floorsector; + native TextureID floorpic; + native int floorterrain; + native Sector ceilingsector; + native TextureID ceilingpic; + native double Height; + native readonly double Radius; + native double projectilepassheight; + native int tics; + native readonly State CurState; + native readonly int Damage; + native int projectilekickback; + native int special1; + native int special2; + native double specialf1; + native double specialf2; + native int weaponspecial; + native int Health; + native uint8 movedir; + native int8 visdir; + native int16 movecount; + native int16 strafecount; + native Actor Target; + native Actor Master; + native Actor Tracer; + native Actor LastHeard; + native Actor LastEnemy; + native Actor LastLookActor; + native int ReactionTime; + native int Threshold; + native readonly int DefThreshold; + native readonly vector3 SpawnPoint; + native readonly uint16 SpawnAngle; + native int StartHealth; + native uint8 WeaveIndexXY; + native uint8 WeaveIndexZ; + native int skillrespawncount; + native int Args[5]; + native int Mass; + native int Special; + native readonly int TID; + native readonly int TIDtoHate; + native readonly int WaterLevel; + native int Score; + native int Accuracy; + native int Stamina; + native double MeleeRange; + native int PainThreshold; + native double Gravity; + native double FloorClip; + native name DamageType; + native name DamageTypeReceived; + native uint8 FloatBobPhase; + native int RipperLevel; + native int RipLevelMin; + native int RipLevelMax; + native name Species; + native Actor Alternative; + native Actor goal; + native uint8 MinMissileChance; + native int8 LastLookPlayerNumber; + native uint SpawnFlags; + native double meleethreshold; + native double maxtargetrange; + native double bouncefactor; + native double wallbouncefactor; + native int bouncecount; + native double friction; + native int FastChaseStrafeCount; + native double pushfactor; + native int lastpush; + native int activationtype; + native int lastbump; + native int DesignatedTeam; + native Actor BlockingMobj; + native int PoisonDamage; + native name PoisonDamageType; + native int PoisonDuration; + native int PoisonPeriod; + native int PoisonDamageReceived; + native name PoisonDamageTypeReceived; + native int PoisonDurationReceived; + native int PoisonPeriodReceived; + native Actor Poisoner; + native Inventory Inv; + native uint8 smokecounter; + native uint8 FriendPlayer; + native uint Translation; + native sound AttackSound; + native sound DeathSound; + native sound SeeSound; + native sound PainSound; + native sound ActiveSound; + native sound UseSound; + native sound BounceSound; + native sound WallBounceSound; + native sound CrushPainSound; + native double MaxDropoffHeight; + native double MaxStepHeight; + native int16 PainChance; + native name PainType; + native name DeathType; + native double DamageFactor; + native double DamageMultiply; + native Class TelefogSourceType; + native Class TelefogDestType; + native readonly State SpawnState; + native readonly State SeeState; + native State MeleeState; + native State MissileState; + + // need some definition work first + //FRenderStyle RenderStyle; + //line_t *BlockingLine; // Line that blocked the last move + //int ConversationRoot; // THe root of the current dialogue + //DecalBase DecalGenerator; + + // deprecated things. + native readonly deprecated double X; + native readonly deprecated double Y; + native readonly deprecated double Z; + native readonly deprecated double VelX; + native readonly deprecated double VelY; + native readonly deprecated double VelZ; + native readonly deprecated double MomX; + native readonly deprecated double MomY; + native readonly deprecated double MomZ; + native deprecated double ScaleX; + native deprecated double ScaleY; + + //int ConversationRoot; // THe root of the current dialogue; + //FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.; + + Default { Scale 1; diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 7a2790726..b3f48acae 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -47,4 +47,8 @@ class SpotState : Object native { native static SpotState GetSpotState(); native SpecialSpot GetNextInList(class type, int skipcounter); -} \ No newline at end of file +} + +struct Sector native +{ +} diff --git a/wadsrc/static/zscript/doom/bossbrain.txt b/wadsrc/static/zscript/doom/bossbrain.txt index cde600701..e6a13317f 100644 --- a/wadsrc/static/zscript/doom/bossbrain.txt +++ b/wadsrc/static/zscript/doom/bossbrain.txt @@ -374,7 +374,7 @@ extend class Actor } // Make it act as if it was around when the player first made noise // (if the player has made noise). - newmobj.LastHeard = newmobj.Sector.SoundTarget; + newmobj.LastHeard = newmobj.CurSector.SoundTarget; if (newmobj.SeeState != null && newmobj.LookForPlayers (true)) { diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 4f9e84333..71cdb8479 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -77,7 +77,7 @@ class PSprite : Object native { } -struct Player native +struct PlayerInfo native // this is what internally is player_t { native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index);