Merge remote-tracking branch 'gz/master' into gz_master2

This commit is contained in:
ZZYZX 2017-03-03 23:30:02 +02:00
commit 723f9770a4
211 changed files with 10321 additions and 9256 deletions

View file

@ -1562,7 +1562,7 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
SAFE_RESOLVE(basex, ctx);
// first deal with the simple types
if (ValueType == TypeError || basex->ValueType == TypeError)
if (ValueType == TypeError || basex->ValueType == TypeError || basex->ValueType == nullptr)
{
ScriptPosition.Message(MSG_ERROR, "Trying to cast to invalid type.");
delete this;
@ -6142,10 +6142,81 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
if (Object->ExprType == EFX_Identifier)
{
auto id = static_cast<FxIdentifier *>(Object)->Identifier;
// If the left side is a class name for a static member function call it needs to be resolved manually
// because the resulting value type would cause problems in nearly every other place where identifiers are being used.
ccls = FindStructType(static_cast<FxIdentifier *>(Object)->Identifier, ctx);
if (ccls != nullptr) static_cast<FxIdentifier *>(Object)->noglobal = true;
ccls = FindStructType(id, ctx);
if (ccls != nullptr)
{
static_cast<FxIdentifier *>(Object)->noglobal = true;
}
else
{
PType *type;
// Another special case to deal with here is constants assigned to non-struct types. The code below cannot deal with them so it needs to be done here explicitly.
// Thanks to the messed up search logic of the type system, which doesn't allow any search by type name for the basic types at all,
// we have to do this manually, though and check for all types that may have values attached explicitly.
// (What's the point of attached fields to types if you cannot even search for the types...???)
switch (id)
{
default:
type = nullptr;
break;
case NAME_Byte:
case NAME_uint8:
type = TypeUInt8;
break;
case NAME_sByte:
case NAME_int8:
type = TypeSInt8;
break;
case NAME_uShort:
case NAME_uint16:
type = TypeUInt16;
break;
case NAME_Short:
case NAME_int16:
type = TypeSInt16;
break;
case NAME_Int:
type = TypeSInt32;
break;
case NAME_uInt:
type = TypeUInt32;
break;
case NAME_Float:
type = TypeFloat32;
break;
case NAME_Double:
type = TypeFloat64;
break;
}
if (type != nullptr)
{
auto sym = type->Symbols.FindSymbol(Identifier, true);
if (sym != nullptr)
{
// non-struct symbols must be constant numbers and can only be defined internally.
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
auto sn = static_cast<PSymbolConstNumeric*>(sym);
VMValue vmv;
if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value;
else vmv = sn->Float;
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
delete this;
return x->Resolve(ctx);
}
}
}
}
SAFE_RESOLVE(Object, ctx);
@ -6420,7 +6491,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
ExpEmit ob = obj->Emit(build);
ob.Free(build);
ExpEmit meta(build, REGT_POINTER);
build->Emit(OP_META, meta.RegNum, ob.RegNum);
build->Emit(OP_CLSS, meta.RegNum, ob.RegNum);
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
return meta;
@ -6571,7 +6642,7 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
case CVAR_String:
build->Emit(OP_LKP, addr.RegNum, build->GetConstantAddress(&static_cast<FStringCVar *>(CVar)->Value, ATAG_GENERIC));
build->Emit(OP_LS, dest.RegNum, addr.RegNum, nul);
build->Emit(OP_LCS, dest.RegNum, addr.RegNum, nul);
break;
case CVAR_DummyBool:
@ -9013,7 +9084,7 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build)
ExpEmit op = Self->Emit(build);
op.Free(build);
ExpEmit to(build, REGT_POINTER);
build->Emit(OP_META, to.RegNum, op.RegNum);
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
return to;
}
@ -9054,7 +9125,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
if (Self->IsObject())
{
ExpEmit to(build, REGT_POINTER);
build->Emit(OP_META, to.RegNum, op.RegNum);
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
op = to;
op.Free(build);
}

View file

@ -846,6 +846,7 @@ void FFunctionBuildList::Build()
{
int errorcount = 0;
int codesize = 0;
int datasize = 0;
FILE *dump = nullptr;
if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w");
@ -927,6 +928,8 @@ void FFunctionBuildList::Build()
{
DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len());
codesize += sfunc->CodeSize;
datasize += sfunc->LineInfoCount * sizeof(FStatementInfo) + sfunc->ExtraSpace + sfunc->NumKonstD * sizeof(int) +
sfunc->NumKonstA * sizeof(void*) + sfunc->NumKonstF * sizeof(double) + sfunc->NumKonstS * sizeof(FString);
}
sfunc->Unsafe = ctx.Unsafe;
}
@ -944,10 +947,11 @@ void FFunctionBuildList::Build()
}
if (dump != nullptr)
{
fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4);
fprintf(dump, "\n*************************************************************************\n%i code bytes\n%i data bytes", codesize * 4, datasize);
fclose(dump);
}
FScriptPosition::StrictErrors = false;
mItems.Clear();
mItems.ShrinkToFit();
FxAlloc.FreeAllBlocks();
}

View file

@ -223,7 +223,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
{
extra.DeathHeight = ((AActor*)(type->Defaults))->Height;
}
type->DeathHeight = extra.DeathHeight;
((AActor*)(type->Defaults))->FloatVar("DeathHeight") = extra.DeathHeight;
}
bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]);
}
@ -262,7 +262,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
}
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->Height;
type->BurnHeight = extra.BurnHeight;
((AActor*)(type->Defaults))->FloatVar("BurnHeight") = extra.BurnHeight;
bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]);
}
@ -445,18 +445,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
{
sc.MustGetNumber ();
bag.Info->ExplosionRadius = sc.Number;
defaults->IntVar(NAME_ExplosionRadius) = sc.Number;
extra.bExplosive = true;
}
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
{
sc.MustGetNumber ();
bag.Info->ExplosionDamage = sc.Number;
defaults->IntVar(NAME_ExplosionDamage) = sc.Number;
extra.bExplosive = true;
}
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
{
bag.Info->DontHurtShooter = true;
defaults->BoolVar(NAME_DontHurtShooter) = true;
}
else if (def == DEF_Projectile && sc.Compare ("Damage"))
{
@ -483,7 +483,7 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (sc.Compare ("Mass"))
{
sc.MustGetFloat ();
defaults->Mass = SDWORD(sc.Float);
defaults->Mass = int32_t(sc.Float);
}
else if (sc.Compare ("Translation1"))
{
@ -541,11 +541,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
{
sc.MustGetString ();
bag.Info->PickupMsg = sc.String;
inv->StringVar(NAME_PickupMsg) = sc.String;
}
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
{
inv->BoolVar("Respawnable") = true;
inv->BoolVar(NAME_Respawnable) = true;
}
else if (def == DEF_BreakableDecoration && sc.Compare ("SolidOnDeath"))
{

View file

@ -52,7 +52,6 @@
#include "backend/codegen.h"
#include "w_wad.h"
#include "v_video.h"
#include "version.h"
#include "v_text.h"
#include "m_argv.h"
@ -828,7 +827,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
if (i > 0) sc.MustGetStringName(",");
if (f->Flags & VARF_Meta)
{
addr = ((char*)bag.Info) + f->Offset;
addr = ((char*)bag.Info->Meta) + f->Offset;
}
else
{
@ -868,7 +867,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
{
sc.MustGetString();
*(FString*)addr = sc.String;
*(FString*)addr = strbin1(sc.String);
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{

View file

@ -54,7 +54,6 @@
#include "i_system.h"
#include "colormatcher.h"
#include "backend/codegen.h"
#include "version.h"
#include "templates.h"
#include "backend/vmbuilder.h"
@ -316,9 +315,7 @@ do_stop:
do
{
sc.MustGetString();
#ifdef DYNLIGHT
AddStateLight(&state, sc.String);
#endif
AddStateLight(&state, sc.String);
}
while (sc.CheckString(","));
sc.MustGetStringName(")");

View file

@ -57,10 +57,16 @@
#include "v_video.h"
#include "c_bind.h"
#include "menu/menu.h"
#include "teaminfo.h"
#include "r_data/sprites.h"
#include "serializer.h"
static TArray<FPropertyInfo*> properties;
static TArray<AFuncDesc> AFTable;
static TArray<FieldDesc> FieldTable;
extern int BackbuttonTime;
extern float BackbuttonAlpha;
static AWeapon *wpnochg;
//==========================================================================
//
@ -311,6 +317,9 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7),
DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7),
DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, FORCEZERORADIUSDMG, AActor, flags7),
DEFINE_FLAG(MF7, NOINFIGHTSPECIES, AActor, flags7),
DEFINE_FLAG(MF7, FORCEINFIGHTING, AActor, flags7),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -331,6 +340,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF, XFLIP, AActor, renderflags),
DEFINE_FLAG(RF, YFLIP, AActor, renderflags),
DEFINE_FLAG(RF, INTERPOLATEANGLES, AActor, renderflags),
DEFINE_FLAG(RF, DONTINTERPOLATE, AActor, renderflags),
// Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
@ -347,6 +357,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG2(BOUNCE_MBF, MBFBOUNCER, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_AutoOffFloorOnly, BOUNCEAUTOOFFFLOORONLY, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_UseBounceState, USEBOUNCESTATE, AActor, BounceFlags),
DEFINE_FLAG2(BOUNCE_NotOnShootables, DONTBOUNCEONSHOOTABLES, AActor, BounceFlags),
};
// These won't be accessible through bitfield variables
@ -420,6 +431,8 @@ static FFlagDef InventoryFlagDefs[] =
DEFINE_FLAG(IF, TRANSFER, AInventory, ItemFlags),
DEFINE_FLAG(IF, NOTELEPORTFREEZE, AInventory, ItemFlags),
DEFINE_FLAG(IF, NOSCREENBLINK, AInventory, ItemFlags),
DEFINE_FLAG(IF, ISARMOR, AInventory, ItemFlags),
DEFINE_FLAG(IF, ISHEALTH, AInventory, ItemFlags),
DEFINE_DUMMY_FLAG(FORCERESPAWNINSURVIVAL, false),
@ -729,7 +742,7 @@ static int fieldcmp(const void * a, const void * b)
void InitThingdef()
{
// Create all global variables here because this cannot be done on the script side and really isn't worth adding support for.
// Also create all special fields here that cannot be declared by script syntax.
// Also create all special fields here that cannot be declared by script syntax plus the pointer serializers. Doing all these with class overrides would be a bit messy.
auto secplanestruct = NewNativeStruct("Secplane", nullptr);
secplanestruct->Size = sizeof(secplane_t);
@ -738,18 +751,62 @@ void InitThingdef()
auto sectorstruct = NewNativeStruct("Sector", nullptr);
sectorstruct->Size = sizeof(sector_t);
sectorstruct->Align = alignof(sector_t);
NewPointer(sectorstruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(sector_t **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<sector_t>(ar, key, *(sector_t **)addr, nullptr);
return true;
}
);
auto linestruct = NewNativeStruct("Line", nullptr);
linestruct->Size = sizeof(line_t);
linestruct->Align = alignof(line_t);
NewPointer(linestruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(line_t **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<line_t>(ar, key, *(line_t **)addr, nullptr);
return true;
}
);
auto sidestruct = NewNativeStruct("Side", nullptr);
sidestruct->Size = sizeof(side_t);
sidestruct->Align = alignof(side_t);
NewPointer(sidestruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(side_t **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<side_t>(ar, key, *(side_t **)addr, nullptr);
return true;
}
);
auto vertstruct = NewNativeStruct("Vertex", nullptr);
vertstruct->Size = sizeof(vertex_t);
vertstruct->Align = alignof(vertex_t);
NewPointer(vertstruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(vertex_t **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<vertex_t>(ar, key, *(vertex_t **)addr, nullptr);
return true;
}
);
auto sectorportalstruct = NewNativeStruct("SectorPortal", nullptr);
sectorportalstruct->Size = sizeof(FSectorPortal);
@ -759,6 +816,44 @@ void InitThingdef()
playerclassstruct->Size = sizeof(FPlayerClass);
playerclassstruct->Align = alignof(FPlayerClass);
auto playerskinstruct = NewNativeStruct("PlayerSkin", nullptr);
playerskinstruct->Size = sizeof(FPlayerSkin);
playerskinstruct->Align = alignof(FPlayerSkin);
auto teamstruct = NewNativeStruct("Team", nullptr);
teamstruct->Size = sizeof(FTeam);
teamstruct->Align = alignof(FTeam);
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
pstruct->Size = sizeof(player_t);
pstruct->Align = alignof(player_t);
NewPointer(pstruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(player_t **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<player_t>(ar, key, *(player_t **)addr, nullptr);
return true;
}
);
auto fontstruct = NewNativeStruct("FFont", nullptr);
fontstruct->Size = sizeof(FFont);
fontstruct->Align = alignof(FFont);
NewPointer(fontstruct, false)->InstallHandlers(
[](FSerializer &ar, const char *key, const void *addr)
{
ar(key, *(FFont **)addr);
},
[](FSerializer &ar, const char *key, void *addr)
{
Serialize<FFont>(ar, key, *(FFont **)addr, nullptr);
return true;
}
);
// set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well...
// As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up.
sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native);
@ -798,6 +893,14 @@ void InitThingdef()
PField *plrclsf = new PField("PlayerClasses", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PlayerClasses);
Namespaces.GlobalNamespace->Symbols.AddSymbol(plrclsf);
auto plrskn = NewPointer(NewResizableArray(playerskinstruct), false);
PField *plrsknf = new PField("PlayerSkins", plrskn, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Skins);
Namespaces.GlobalNamespace->Symbols.AddSymbol(plrsknf);
auto teamst = NewPointer(NewResizableArray(teamstruct), false);
PField *teamf = new PField("Teams", teamst, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&Teams);
Namespaces.GlobalNamespace->Symbols.AddSymbol(teamf);
auto bindcls = NewNativeStruct("KeyBindings", nullptr);
PField *binding = new PField("Bindings", bindcls, VARF_Native | VARF_Static, (intptr_t)&Bindings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(binding);
@ -815,9 +918,6 @@ void InitThingdef()
Namespaces.GlobalNamespace->Symbols.AddSymbol(gi);
// set up a variable for the global players array.
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
pstruct->Size = sizeof(player_t);
pstruct->Align = alignof(player_t);
PArray *parray = NewArray(pstruct, MAXPLAYERS);
PField *fieldptr = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
@ -829,7 +929,10 @@ void InitThingdef()
fieldptr = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("gameaction", TypeUInt8, VARF_Native | VARF_Static, (intptr_t)&gameaction);
fieldptr = new PField("gameaction", TypeUInt32, VARF_Native | VARF_Static, (intptr_t)&gameaction);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("gamestate", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gamestate);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("skyflatnum", TypeTextureID, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&skyflatnum);
@ -888,11 +991,23 @@ void InitThingdef()
fieldptr = new PField("OptionMenuSettings", NewStruct("FOptionMenuSettings", nullptr), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&OptionSettings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("demoplayback", TypeBool, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&demoplayback);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("BackbuttonTime", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&BackbuttonTime);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("BackbuttonAlpha", TypeFloat32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&BackbuttonAlpha);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
// Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag.
// It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution'
// is to create a static variable from it and reference that in the script. Yuck!!!
static AWeapon *wpnochg = WP_NOCHANGE;
wpnochg = WP_NOCHANGE;
fieldptr = new PField("WP_NOCHANGE", NewPointer(RUNTIME_CLASS(AWeapon), false), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&wpnochg);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
@ -1195,10 +1310,20 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
ACTION_RETURN_STRING(s);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
DEFINE_ACTION_FUNCTION(FStringStruct, Left)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_INT((int)self->Len());
PARAM_UINT(len);
FString s = self->Left(len);
ACTION_RETURN_STRING(s);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Truncate)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
PARAM_UINT(len);
self->Truncate(len);
return 0;
}
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
@ -1221,3 +1346,10 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
ACTION_RETURN_INT(0);
ACTION_RETURN_INT((*self)[pos]);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Filter)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_STRING(strbin1(*self));
}

View file

@ -592,24 +592,13 @@ DEFINE_PROPERTY(health, I, Actor)
defaults->health=id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(gibhealth, I, Actor)
{
PROP_INT_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->GibHealth = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(woundhealth, I, Actor)
{
PROP_INT_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->WoundHealth = id;
defaults->WoundHealth = id;
}
//==========================================================================
@ -888,16 +877,6 @@ DEFINE_PROPERTY(activesound, S, Actor)
defaults->ActiveSound = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(howlsound, S, Actor)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->HowlSound = str;
}
//==========================================================================
//
//==========================================================================
@ -981,75 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor)
defaults->Alpha = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(obituary, S, Actor)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->Obituary = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(hitobituary, S, Actor)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->HitObituary = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(donthurtshooter, 0, Actor)
{
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->DontHurtShooter = true;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(explosionradius, I, Actor)
{
PROP_INT_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->ExplosionRadius = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(explosiondamage, I, Actor)
{
PROP_INT_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->ExplosionDamage = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(deathheight, F, Actor)
{
PROP_DOUBLE_PARM(h, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->DeathHeight = MAX(0., h);
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(burnheight, F, Actor)
{
PROP_DOUBLE_PARM(h, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->BurnHeight = MAX(0., h);
}
//==========================================================================
//
//==========================================================================
@ -1068,16 +978,6 @@ DEFINE_PROPERTY(meleethreshold, F, Actor)
defaults->meleethreshold = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(meleedamage, I, Actor)
{
PROP_INT_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->MeleeDamage = id;
}
//==========================================================================
//
//==========================================================================
@ -1087,36 +987,6 @@ DEFINE_PROPERTY(meleerange, F, Actor)
defaults->meleerange = id;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(meleesound, S, Actor)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->MeleeSound = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(missiletype, S, Actor)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->MissileName = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(missileheight, F, Actor)
{
PROP_DOUBLE_PARM(id, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->MissileHeight = id;
}
//==========================================================================
//
//==========================================================================
@ -1183,13 +1053,11 @@ DEFINE_PROPERTY(bloodcolor, C, Actor)
{
PROP_COLOR_PARM(color, 0);
PalEntry pe = color;
pe.a = CreateBloodTranslation(pe);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->BloodColor = pe;
defaults->BloodColor = color;
defaults->BloodColor.a = 255; // a should not be 0.
defaults->BloodTranslation = TRANSLATION(TRANSLATION_Blood, CreateBloodTranslation(color));
}
//==========================================================================
//
//==========================================================================
@ -1199,26 +1067,23 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor)
PROP_STRING_PARM(str1, 1)
PROP_STRING_PARM(str2, 2)
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
PClassActor *ainfo = static_cast<PClassActor *>(info);
FName blood = str;
// normal blood
ainfo->BloodType = blood;
defaults->NameVar("BloodType") = blood;
if (PROP_PARM_COUNT > 1)
{
blood = str1;
}
// blood splatter
ainfo->BloodType2 = blood;
defaults->NameVar("BloodType2") = blood;
if (PROP_PARM_COUNT > 2)
{
blood = str2;
}
// axe blood
ainfo->BloodType3 = blood;
defaults->NameVar("BloodType3") = blood;
}
//==========================================================================
@ -1413,21 +1278,28 @@ DEFINE_PROPERTY(poisondamagetype, S, Actor)
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(fastspeed, F, Actor)
DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
{
PROP_DOUBLE_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->FastSpeed = i;
defaults->RadiusDamageFactor = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
DEFINE_PROPERTY(selfdamagefactor, F, Actor)
{
PROP_DOUBLE_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->RDFactor = i;
defaults->SelfDamageFactor = i;
}
//==========================================================================
//
//==========================================================================
DEFINE_PROPERTY(stealthalpha, F, Actor)
{
PROP_DOUBLE_PARM(i, 0);
defaults->StealthAlpha = i;
}
//==========================================================================
@ -1436,8 +1308,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
DEFINE_PROPERTY(cameraheight, F, Actor)
{
PROP_DOUBLE_PARM(i, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->CameraHeight = i;
defaults->CameraHeight = i;
}
//==========================================================================
@ -1811,16 +1682,6 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor));
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
{
PROP_STRING_PARM(str, 0);
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
static_cast<PClassActor *>(info)->PickupMsg = str;
}
//==========================================================================
//
//==========================================================================
@ -1855,15 +1716,6 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
defaults->UseSound = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
{
PROP_INT_PARM(i, 0);
defaults->GiveQuest = i;
}
//==========================================================================
//
//==========================================================================
@ -2698,24 +2550,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
bag.DropItemList = di;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
defaults->InvulMode = str;
}
//==========================================================================
//
//==========================================================================
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
{
PROP_STRING_PARM(str, 0);
defaults->HealingRadiusType = str;
}
//==========================================================================
//
//==========================================================================

View file

@ -12,6 +12,7 @@
// these are used in vmexec.h
void FScopeBarrier_ValidateNew(PClass* cls, PFunction* callingfunc);
void FScopeBarrier_ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype);
class DObject;
extern FMemArena ClassDataAllocator;
@ -1035,6 +1036,7 @@ void NullParam(const char *varname);
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass());
#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass());
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
@ -1079,6 +1081,7 @@ void NullParam(const char *varname);
#define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x)
#define PARAM_STATE_ACTION(x) ++paramnum; PARAM_STATE_ACTION_AT(paramnum,x)
#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type)
#define PARAM_POINTERTYPE(x,type) ++paramnum; PARAM_POINTERTYPE_AT(paramnum,x,type)
#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base)
#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type)

View file

@ -109,12 +109,18 @@ begin:
reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts.
NEXTOP;
OP(META):
OP(CLSS):
ASSERTA(a); ASSERTO(B);
reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(META):
ASSERTA(a); ASSERTO(B);
reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(LB):
ASSERTD(a); ASSERTA(B); ASSERTKD(C);
GETADDR(PB,KC,X_READ_NIL);
@ -197,6 +203,16 @@ begin:
GETADDR(PB,RC,X_READ_NIL);
reg.s[a] = *(FString *)ptr;
NEXTOP;
OP(LCS):
ASSERTS(a); ASSERTA(B); ASSERTKD(C);
GETADDR(PB,KC,X_READ_NIL);
reg.s[a] = *(const char **)ptr;
NEXTOP;
OP(LCS_R):
ASSERTS(a); ASSERTA(B); ASSERTD(C);
GETADDR(PB,RC,X_READ_NIL);
reg.s[a] = *(const char **)ptr;
NEXTOP;
OP(LO):
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
GETADDR(PB,KC,X_READ_NIL);

View file

@ -446,7 +446,8 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
{
auto code = static_cast<VMScriptFunction *>(func)->Code;
// handle empty functions consisting of a single return explicitly so that empty virtual callbacks do not need to set up an entire VM frame.
if (code->word == 0x0080804e)
// code cann be null here in case of some non-fatal DECORATE errors.
if (code == nullptr || code->word == 0x0080804e)
{
return 0;
}

View file

@ -23,7 +23,8 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed
xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed
xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed
xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta data address
xx(CLSS, clss, RPRP, NOP, 0, 0), // load a class's descriptor address
// Load from memory. rA = *(rB + rkC)
xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte
@ -52,6 +53,8 @@ xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2
xx(LV2_R, lv2, RVRPRI, NOP, 0, 0),
xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3
xx(LV3_R, lv3, RVRPRI, NOP, 0, 0),
xx(LCS, lcs, RSRPKI, LCS_R, 4, REGT_INT), // load string from char ptr.
xx(LCS_R, lcs, RSRPRI, NOP, 0, 0),
xx(LBIT, lbit, RIRPI8, NOP, 0, 0), // rA = !!(*rB & C) -- *rB is a byte

View file

@ -49,7 +49,6 @@
#include "i_system.h"
#include "gdtoa.h"
#include "backend/vmbuilder.h"
#include "version.h"
static int GetIntConst(FxExpression *ex, FCompileContext &ctx)
{
@ -1040,6 +1039,11 @@ void ZCCCompiler::CompileAllFields()
type->Size = Classes[i]->Type()->ParentClass->Size;
}
}
if (Classes[i]->Type()->ParentClass)
type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize;
else
type->MetaSize = 0;
if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type)))
{
// Remove from the list if all fields got compiled.
@ -1130,11 +1134,6 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
if (field->Flags & ZCC_Meta)
{
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
if (!(field->Flags & ZCC_Native))
{
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars());
}
}
if (field->Type->ArraySize != nullptr)
@ -1155,22 +1154,28 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
if (varflags & VARF_Native)
{
auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type;
fd = FindField(querytype, FName(name->Name).GetChars());
if (fd == nullptr)
if (varflags & VARF_Meta)
{
Error(field, "The member variable '%s.%s' has not been exported from the executable", type->TypeName.GetChars(), FName(name->Name).GetChars());
Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars());
}
else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0)
{
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
{
// for bit fields the type must point to the source variable.
if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32;
type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
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 && fd->BitValue == 0)
{
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
{
// for bit fields the type must point to the source variable.
if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32;
type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
}
}
}
else if (hasnativechildren)
@ -1248,8 +1253,10 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
FString qualifiedname;
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.
// All these will be removed from the symbol table after the compiler finishes to free up the allocated space.
if (prefix == NAME_None) qualifiedname.Format("@property@%s", FName(p->NodeName).GetChars());
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), FName(p->NodeName).GetChars());
FName name = FName(p->NodeName);
if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars());
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars());
fields.ShrinkToFit();
if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields)))
{
@ -1420,22 +1427,19 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
break;
case AST_DynArrayType:
if (allowarraytypes)
{
auto atype = static_cast<ZCC_DynArrayType *>(ztype);
auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true);
if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1)
{
auto atype = static_cast<ZCC_DynArrayType *>(ztype);
auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true);
if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1)
{
Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName());
}
else
{
retval = NewDynArray(ftype);
}
break;
Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName());
}
else
{
retval = NewDynArray(ftype);
}
break;
}
case AST_ClassType:
{
auto ctype = static_cast<ZCC_ClassType *>(ztype);
@ -1755,7 +1759,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
if (f->Flags & VARF_Meta)
{
addr = ((char*)bag.Info) + f->Offset;
addr = ((char*)bag.Info->Meta) + f->Offset;
}
else
{
@ -2250,7 +2254,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
{
auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false);
int flags = 0;
if (type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3)
if ((type->IsA(RUNTIME_CLASS(PStruct)) && type != TypeVector2 && type != TypeVector3) || type->IsA(RUNTIME_CLASS(PDynArray)))
{
// Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly.
type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/);
@ -2711,7 +2715,7 @@ void ZCCCompiler::CompileStates()
state.Misc1 = IntConstFromNode(sl->Offset, c->Type());
state.Misc2 = IntConstFromNode(static_cast<ZCC_Expression *>(sl->Offset->SiblingNext), c->Type());
}
#ifdef DYNLIGHT
if (sl->Lights != nullptr)
{
auto l = sl->Lights;
@ -2721,7 +2725,6 @@ void ZCCCompiler::CompileStates()
l = static_cast<decltype(l)>(l->SiblingNext);
} while (l != sl->Lights);
}
#endif
if (sl->Action != nullptr)
{

View file

@ -285,6 +285,7 @@ static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCPar
tokentype = ZCC_FLOATCONST;
break;
case TK_None: // 'NONE' is a token for SBARINFO but not here.
case TK_Identifier:
value.Int = FName(sc.String);
tokentype = ZCC_IDENTIFIER;