- 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.
This commit is contained in:
Christoph Oelckers 2016-11-22 19:20:31 +01:00
parent ab5c11064a
commit 980c986305
22 changed files with 520 additions and 202 deletions

View file

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

View file

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

View file

@ -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, TArray<FTypeAndOffset
{
for (const PField *field : Fields)
{
if (!(field->Flags & 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<size_t> *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 TArray<PField
for (unsigned i = 0; i < fields.Size(); ++i)
{
const PField *field = fields[i];
// Skip fields with native serialization
if (!(field->Flags & 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-

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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'")

View file

@ -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<FxStructMember *>(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<FxStructMember *>(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<FxGlobalVariable *>(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<FxGlobalVariable *>(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<FxStackVariable *>(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<FxStackVariable *>(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();
}

View file

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

View file

@ -46,6 +46,7 @@
static TArray<FPropertyInfo*> properties;
static TArray<AFuncDesc> AFTable;
static TArray<FieldDesc> 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);
}
}

View file

@ -1013,6 +1013,15 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
typedef int(*actionf_p)(VMFrameStack *stack, VMValue *param, TArray<VMValue> &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);

View file

@ -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<PClass*, bool> 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<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct)
bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &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<ZCC_VarDeclarator *> &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<ZCC_VarDeclarator *> &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<ZCC_VarName*>(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
{

View file

@ -91,7 +91,7 @@ private:
bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols);
void CompileAllFields();
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct);
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &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);

View file

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

View file

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

View file

@ -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<Actor> TelefogSourceType;
native Class<Actor> 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;

View file

@ -47,4 +47,8 @@ class SpotState : Object native
{
native static SpotState GetSpotState();
native SpecialSpot GetNextInList(class<Actor> type, int skipcounter);
}
}
struct Sector native
{
}

View file

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

View file

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