This commit is contained in:
Rachael Alexanderson 2017-03-05 18:40:44 -05:00
commit 7ef8ed5867
54 changed files with 864 additions and 349 deletions

View file

@ -644,8 +644,12 @@ bool FConfigFile::ReadConfig (void *file)
continue;
}
// Do not process tail of long line
const bool longline = 255 == strlen(readbuf) && '\n' != readbuf[254];
if (!longline)
const bool longline = (READBUFFERSIZE - 1) == strlen(readbuf) && '\n' != readbuf[READBUFFERSIZE - 2];
if (longline)
{
endpt = start + READBUFFERSIZE - 2;
}
else
{
// Remove white space at end of line
endpt = start + strlen (start) - 1;

View file

@ -1316,6 +1316,7 @@ PPointer::PPointer(PType *pointsat, bool isconst)
: PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst)
{
mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : "");
mVersion = pointsat->mVersion;
SetOps();
}
@ -1518,6 +1519,7 @@ PClassPointer::PClassPointer(PClass *restrict)
// This means we can use the cheapoer non-barriered opcodes here.
loadOp = OP_LOS;
storeOp = OP_SP;
mVersion = restrict->mVersion;
}
//==========================================================================
@ -2522,6 +2524,14 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue
else BitValue = -1;
}
VersionInfo PField::GetVersion()
{
VersionInfo Highest = { 0,0,0 };
if (!(Flags & VARF_Deprecated)) Highest = mVersion;
if (Type->mVersion > Highest) Highest = Type->mVersion;
return Highest;
}
/* PProperty *****************************************************************/
IMPLEMENT_CLASS(PProperty, false, false)
@ -3146,6 +3156,9 @@ void PClass::Derive(PClass *newclass, FName name)
newclass->Symbols.SetParentTable(&this->Symbols);
newclass->TypeName = name;
newclass->mDescriptiveName.Format("Class<%s>", name.GetChars());
newclass->mVersion = mVersion;
newclass->MetaSize = MetaSize;
}
//==========================================================================
@ -3292,7 +3305,6 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
type->bRuntimeClass = true;
Derive(type, name);
type->Size = size;
type->MetaSize = MetaSize;
if (size != TentativeClass)
{
type->InitializeDefaults();

View file

@ -91,6 +91,7 @@ public:
PSymbolTable Symbols;
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
FString mDescriptiveName;
VersionInfo mVersion = { 0,0,0 };
BYTE loadOp, storeOp, moveOp, RegType, RegCount;
PType(unsigned int size = 1, unsigned int align = 1);

View file

@ -193,6 +193,38 @@ public:
};
struct VersionInfo
{
uint16_t major;
uint16_t minor;
uint32_t revision;
bool operator <=(const VersionInfo &o) const
{
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision >= this->revision);
}
bool operator >=(const VersionInfo &o) const
{
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision <= this->revision);
}
bool operator > (const VersionInfo &o) const
{
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision < this->revision);
}
bool operator < (const VersionInfo &o) const
{
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision > this->revision);
}
void operator=(const char *string);
};
// Cannot be a constructor because Lemon would puke on it.
inline VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0)
{
return{ (uint16_t)ma, (uint16_t)mi, (uint32_t)re };
}
// Screenshot buffer image data types
enum ESSType

View file

@ -1463,6 +1463,8 @@ void G_InitLevelLocals ()
level.NextMap = info->NextMap;
level.NextSecretMap = info->NextSecretMap;
level.F1Pic = info->F1Pic;
level.hazardcolor = info->hazardcolor;
level.hazardflash = info->hazardflash;
compatflags.Callback();
compatflags2.Callback();

View file

@ -315,6 +315,8 @@ struct level_info_t
FName Intermission;
FName deathsequence;
FName slideshow;
DWORD hazardcolor;
DWORD hazardflash;
// Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one.

View file

@ -43,6 +43,9 @@ struct FLevelLocals
DWORD fadeto; // The color the palette fades to (usually black)
DWORD outsidefog; // The fog for sectors with sky ceilings
DWORD hazardcolor; // what color strife hazard blends the screen color as
DWORD hazardflash; // what color strife hazard flashes the screen color as
FString Music;
int musicorder;
int cdtrack;

View file

@ -273,6 +273,8 @@ void level_info_t::Reset()
SndSeq = "";
BorderTexture = "";
teamdamage = 0.f;
hazardcolor = 0xff004200;
hazardflash = 0xff00ff00;
specialactions.Clear();
DefaultEnvironment = 0;
PrecacheSounds.Clear();
@ -1200,6 +1202,20 @@ DEFINE_MAP_OPTION(defaultenvironment, false)
info->DefaultEnvironment = id;
}
DEFINE_MAP_OPTION(hazardcolor, true)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->hazardcolor = V_GetColor(NULL, parse.sc);
}
DEFINE_MAP_OPTION(hazardflash, true)
{
parse.ParseAssign();
parse.sc.MustGetString();
info->hazardflash = V_GetColor(NULL, parse.sc);
}
//==========================================================================
//

View file

@ -143,17 +143,26 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
glFinish();
wipestartscreen->Bind(0, false, false);
const auto copyPixels = [&viewport]()
{
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
};
if (FGLRenderBuffers::IsEnabled())
{
GLRenderer->mBuffers->BindCurrentFB();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
copyPixels();
}
else if (gl.legacyMode)
{
copyPixels();
}
else
{
GLint readbuffer = 0;
glGetIntegerv(GL_READ_BUFFER, &readbuffer);
glReadBuffer(GL_FRONT);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height);
copyPixels();
glReadBuffer(readbuffer);
}

View file

@ -9088,6 +9088,35 @@ scriptwait:
}
break;
case PCD_TRANSLATIONRANGE4:
{ // Colourise translation
int start = STACK(5);
int end = STACK(4);
int r = STACK(3);
int g = STACK(2);
int b = STACK(1);
sp -= 5;
if (translation != NULL)
translation->AddColourisation(start, end, r, g, b);
}
break;
case PCD_TRANSLATIONRANGE5:
{ // Tint translation
int start = STACK(6);
int end = STACK(5);
int a = STACK(4);
int r = STACK(3);
int g = STACK(2);
int b = STACK(1);
sp -= 6;
if (translation != NULL)
translation->AddTint(start, end, r, g, b, a);
}
break;
case PCD_ENDTRANSLATION:
if (translation != NULL)
{

View file

@ -779,6 +779,8 @@ public:
/*380*/ PCD_STRCPYTOSCRIPTCHRANGE,
PCD_LSPEC5EX,
PCD_LSPEC5EXRESULT,
PCD_TRANSLATIONRANGE4,
PCD_TRANSLATIONRANGE5,
/*381*/ PCODE_COMMAND_COUNT
};

View file

@ -487,6 +487,56 @@ void FRemapTable::AddDesaturation(int start, int end, double r1, double g1, doub
//
//----------------------------------------------------------------------------
void FRemapTable::AddColourisation(int start, int end, int r, int g, int b)
{
for (int i = start; i < end; ++i)
{
float br = GPalette.BaseColors[i].r;
float bg = GPalette.BaseColors[i].g;
float bb = GPalette.BaseColors[i].b;
float grey = (br * 0.299 + bg * 0.587 + bb * 0.114) / 255.0f;
if (grey > 1.0) grey = 1.0;
br = r * grey;
bg = g * grey;
bb = b * grey;
int j = GPalette.Remap[i];
Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb));
Remap[j] = ColorMatcher.Pick(Palette[j]);
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::AddTint(int start, int end, int r, int g, int b, int amount)
{
for (int i = start; i < end; ++i)
{
float br = GPalette.BaseColors[i].r;
float bg = GPalette.BaseColors[i].g;
float bb = GPalette.BaseColors[i].b;
float a = amount * 0.01f;
float ia = 1.0f - a;
br = br * ia + r * a;
bg = bg * ia + g * a;
bb = bb * ia + b * a;
int j = GPalette.Remap[i];
Palette[j] = PalEntry(j == 0 ? 0 : 255, int(br), int(bg), int(bb));
Remap[j] = ColorMatcher.Pick(Palette[j]);
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
void FRemapTable::AddToTranslation(const char *range)
{
int start,end;
@ -511,19 +561,9 @@ void FRemapTable::AddToTranslation(const char *range)
}
sc.MustGetAnyToken();
Printf(0, "token type: %d", sc.TokenType);
if (sc.TokenType != '[' && sc.TokenType != '%')
{
int pal1,pal2;
sc.TokenMustBe(TK_IntConst);
pal1 = sc.Number;
sc.MustGetToken(':');
sc.MustGetToken(TK_IntConst);
pal2 = sc.Number;
AddIndexRange(start, end, pal1, pal2);
}
else if (sc.TokenType == '[')
if (sc.TokenType == '[')
{
// translation using RGB values
int r1,g1,b1,r2,g2,b2;
@ -596,6 +636,54 @@ void FRemapTable::AddToTranslation(const char *range)
AddDesaturation(start, end, r1, g1, b1, r2, g2, b2);
}
else if (sc.TokenType == '#')
{
// Colourise translation
int r, g, b;
sc.MustGetToken('[');
sc.MustGetToken(TK_IntConst);
r = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
g = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
b = sc.Number;
sc.MustGetToken(']');
AddColourisation(start, end, r, g, b);
}
else if (sc.TokenType == '@')
{
// Tint translation
int a, r, g, b;
sc.MustGetToken(TK_IntConst);
a = sc.Number;
sc.MustGetToken('[');
sc.MustGetToken(TK_IntConst);
r = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
g = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
b = sc.Number;
sc.MustGetToken(']');
AddTint(start, end, r, g, b, a);
}
else
{
int pal1, pal2;
sc.TokenMustBe(TK_IntConst);
pal1 = sc.Number;
sc.MustGetToken(':');
sc.MustGetToken(TK_IntConst);
pal2 = sc.Number;
AddIndexRange(start, end, pal1, pal2);
}
}
catch (CRecoverableError &err)
{

View file

@ -42,6 +42,8 @@ struct FRemapTable
void AddIndexRange(int start, int end, int pal1, int pal2);
void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2);
void AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2);
void AddColourisation(int start, int end, int r, int g, int b);
void AddTint(int start, int end, int r, int g, int b, int amount);
void AddToTranslation(const char * range);
int StoreTranslation(int slot);

View file

@ -42,6 +42,31 @@
// CODE --------------------------------------------------------------------
void VersionInfo::operator=(const char *string)
{
char *endp;
major = (int16_t)clamp<unsigned long long>(strtoull(string, &endp, 10), 0, USHRT_MAX);
if (*endp == '.')
{
minor = (int16_t)clamp<unsigned long long>(strtoull(endp + 1, &endp, 10), 0, USHRT_MAX);
if (*endp == '.')
{
revision = (int16_t)clamp<unsigned long long>(strtoull(endp + 1, &endp, 10), 0, USHRT_MAX);
if (*endp != 0) major = USHRT_MAX;
}
else if (*endp == 0)
{
revision = 0;
}
else major = USHRT_MAX;
}
else if (*endp == 0)
{
minor = revision = 0;
}
else major = USHRT_MAX;
}
//==========================================================================
//
// FScanner Constructor

View file

@ -24,6 +24,10 @@ public:
void OpenString(const char *name, FString buffer);
void OpenLumpNum(int lump);
void Close();
void SetParseVersion(VersionInfo ver)
{
ParseVersion = ver;
}
void SetCMode(bool cmode);
void SetEscape(bool esc);
@ -102,6 +106,7 @@ protected:
BYTE StateMode;
bool StateOptions;
bool Escape;
VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default
};
enum

View file

@ -143,50 +143,38 @@ std2:
'false' { RET(TK_False); }
'none' { RET(TK_None); }
'auto' { RET(TK_Auto); }
'exec' { RET(TK_Exec); }
'property' { RET(TK_Property); }
'native' { RET(TK_Native); }
'var' { RET(TK_Var); }
'out' { RET(TK_Out); }
'ref' { RET(TK_Ref); }
'event' { RET(TK_Event); }
'out' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Out : TK_Identifier); }
'static' { RET(TK_Static); }
'transient' { RET(TK_Transient); }
'final' { RET(TK_Final); }
'throws' { RET(TK_Throws); }
'extend' { RET(TK_Extend); }
'public' { RET(TK_Public); }
'protected' { RET(TK_Protected); }
'private' { RET(TK_Private); }
'transient' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Transient : TK_Identifier); }
'final' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Final : TK_Identifier); }
'extend' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Extend : TK_Identifier); }
'protected' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Protected : TK_Identifier); }
'private' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Private : TK_Identifier); }
'dot' { RET(TK_Dot); }
'cross' { RET(TK_Cross); }
'localized' { RET(TK_Localized); }
'latent' { RET(TK_Latent); }
'singular' { RET(TK_Singular); }
'config' { RET(TK_Config); }
'coerce' { RET(TK_Coerce); }
'optional' { RET(TK_Optional); }
'export' { RET(TK_Export); }
'virtual' { RET(TK_Virtual); }
'override' { RET(TK_Override); }
'vararg' { RET(TK_VarArg); }
'ui' { RET(TK_UI); }
'play' { RET(TK_Play); }
'clearscope' { RET(TK_ClearScope); }
'virtualscope' { RET(TK_VirtualScope); }
'super' { RET(TK_Super); }
'global' { RET(TK_Global); }
'virtual' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Virtual : TK_Identifier); }
'override' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Override : TK_Identifier); }
'vararg' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_VarArg : TK_Identifier); }
'ui' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_UI : TK_Identifier); }
'play' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_Play : TK_Identifier); }
'clearscope' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_ClearScope : TK_Identifier); }
'virtualscope' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_VirtualScope : TK_Identifier); }
'super' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Super : TK_Identifier); }
'stop' { RET(TK_Stop); }
'null' { RET(TK_Null); }
'is' { RET(TK_Is); }
'replaces' { RET(TK_Replaces); }
'is' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Is : TK_Identifier); }
'replaces' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Replaces : TK_Identifier); }
'states' { RET(TK_States); }
'meta' { RET(TK_Meta); }
'deprecated' { RET(TK_Deprecated); }
'action' { RET(TK_Action); }
'readonly' { RET(TK_ReadOnly); }
'let' { RET(TK_Let); }
'meta' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Meta : TK_Identifier); }
'deprecated' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Deprecated : TK_Identifier); }
'version' { RET(ParseVersion >= MakeVersion(2, 4, 0)? TK_Version : TK_Identifier); }
'action' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Action : TK_Identifier); }
'readonly' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_ReadOnly : TK_Identifier); }
'let' { RET(ParseVersion >= MakeVersion(1, 0, 0)? TK_Let : TK_Identifier); }
/* Actor state options */
'bright' { RET(StateOptions ? TK_Bright : TK_Identifier); }
@ -267,6 +255,8 @@ std2:
"^" { RET('^'); }
"|" { RET('|'); }
"?" { RET('?'); }
"#" { RET('#'); }
"@" { RET('@'); }
[ \t\v\f\r]+ { goto std1; }
"\n" { goto newline; }

View file

@ -108,8 +108,6 @@ xx(TK_Singular, "'singular'")
xx(TK_Config, "'config'")
xx(TK_Coerce, "'coerce'")
xx(TK_Iterator, "'iterator'")
xx(TK_Optional, "'optional'")
xx(TK_Export, "'expert'")
xx(TK_Virtual, "'virtual'")
xx(TK_VarArg, "'vararg'")
xx(TK_UI, "'ui'")
@ -138,6 +136,7 @@ xx(TK_Fail, "'fail'")
xx(TK_Wait, "'wait'")
xx(TK_Meta, "'meta'")
xx(TK_Deprecated, "'deprecated'")
xx(TK_Version, "'version'")
xx(TK_ReadOnly, "'readonly'")
xx(TK_CanRaise, "'canraise'")

View file

@ -90,45 +90,24 @@ static const FLOP FxFlops[] =
};
//==========================================================================
//
// [ZZ] Magic methods to be used in vmexec.h for runtime checking of scope
//
//==========================================================================
// this can be imported in vmexec.h
void FScopeBarrier_ValidateNew(PClass* cls, PFunction* callingfunc)
{
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
if (outerside == FScopeBarrier::Side_Virtual)
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context"
ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside));
}
// this can be imported in vmexec.h
void FScopeBarrier_ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype)
{
// [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual.
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
if (outerside == FScopeBarrier::Side_Virtual)
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags);
if (innerside == FScopeBarrier::Side_Virtual)
innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags);
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData))
ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside));
}
//==========================================================================
//
// FCompileContext
//
//==========================================================================
FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump)
: ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg)
FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver)
: ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg), Version(ver)
{
if (Version >= MakeVersion(2, 3))
{
VersionString.Format("ZScript version %d.%d.%d", Version.major, Version.minor, Version.revision);
}
else
{
VersionString = "DECORATE";
}
if (fnc != nullptr) Class = fnc->OwningClass;
}
@ -409,7 +388,7 @@ bool FxExpression::isConstant() const
//
//==========================================================================
VMFunction *FxExpression::GetDirectFunction()
VMFunction *FxExpression::GetDirectFunction(const VersionInfo &ver)
{
return nullptr;
}
@ -5986,6 +5965,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
}
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
{
PField *vsym = static_cast<PField*>(sym);
if (vsym->GetVersion() > ctx.Version)
{
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars());
delete this;
return nullptr;
}
// internally defined global variable
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable\n", Identifier.GetChars());
newex = new FxGlobalVariable(static_cast<PField *>(sym), ScriptPosition);
@ -6045,7 +6033,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor)))
{
ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type.");
delete this;
delete object;
object = nullptr;
return nullptr;
}
@ -6067,21 +6056,66 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
{
PField *vsym = static_cast<PField*>(sym);
if (vsym->GetVersion() > ctx.Version)
{
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars());
delete object;
object = nullptr;
return nullptr;
}
if ((vsym->Flags & VARF_Deprecated) && sym->mVersion >= ctx.Version)
{
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s - deprecated since %d.%d.%d", sym->SymbolName.GetChars(), vsym->mVersion.major, vsym->mVersion.minor, vsym->mVersion.revision);
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
}
// We have 4 cases to consider here:
// 1. The symbol is a static/meta member (not implemented yet) which is always accessible.
// 1. The symbol is a static/meta member which is always accessible.
// 2. This is a static function
// 3. This is an action function with a restricted self pointer
// 4. This is a normal member or unrestricted action function.
if (vsym->Flags & VARF_Deprecated && !ctx.FromDecorate)
{
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
}
if ((vsym->Flags & VARF_Private) && symtbl != &classctx->Symbols)
{
ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars());
delete object;
object = nullptr;
return nullptr;
}
PClass* cls_ctx = dyn_cast<PClass>(classctx);
PClass* cls_target = dyn_cast<PClass>(objtype);
// [ZZ] neither PSymbol, PField or PSymbolTable have the necessary information. so we need to do the more complex check here.
if (vsym->Flags & VARF_Protected)
{
// early break.
if (!cls_ctx || !cls_target)
{
ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars());
delete object;
object = nullptr;
return nullptr;
}
// find the class that declared this field.
PClass* p = cls_target;
while (p)
{
if (&p->Symbols == symtbl)
{
cls_target = p;
break;
}
p = p->ParentClass;
}
if (!cls_ctx->IsDescendantOf(cls_target))
{
ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars());
delete object;
object = nullptr;
return nullptr;
}
}
auto x = isclass ? new FxClassMember(object, vsym, ScriptPosition) : new FxStructMember(object, vsym, ScriptPosition);
object = nullptr;
@ -6810,12 +6844,6 @@ bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
// [ZZ] original check.
bool bWritable = (AddressWritable && !ctx.CheckWritable(membervar->Flags) &&
(!classx->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) || !static_cast<PPointer*>(classx->ValueType)->IsConst));
// [ZZ] self in a const function is not writable.
if (bWritable) // don't do complex checks on early fail
{
if ((classx->ExprType == EFX_Self) && (ctx.Function && (ctx.Function->Variants[0].Flags & VARF_ReadOnly)))
bWritable = false;
}
// [ZZ] implement write barrier between different scopes
if (bWritable)
{
@ -8468,19 +8496,44 @@ PPrototype *FxVMFunctionCall::ReturnProto()
return Function->Variants[0].Proto;
}
bool FxVMFunctionCall::CheckAccessibility(const VersionInfo &ver)
{
if (Function->mVersion > ver && !(Function->Variants[0].Flags & VARF_Deprecated))
{
FString VersionString;
if (ver >= MakeVersion(2, 3))
{
VersionString.Format("ZScript version %d.%d.%d", ver.major, ver.minor, ver.revision);
}
else
{
VersionString = "DECORATE";
}
ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", Function->SymbolName.GetChars(), VersionString.GetChars());
return false;
}
if ((Function->Variants[0].Flags & VARF_Deprecated) && Function->mVersion >= ver)
{
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated function %s - deprecated since %d.%d.%d", Function->SymbolName.GetChars(), Function->mVersion.major, Function->mVersion.minor, Function->mVersion.revision);
return false;
}
return true;
}
//==========================================================================
//
//
//
//==========================================================================
VMFunction *FxVMFunctionCall::GetDirectFunction()
VMFunction *FxVMFunctionCall::GetDirectFunction(const VersionInfo &ver)
{
// If this return statement calls a non-virtual function with no arguments,
// then it can be a "direct" function. That is, the DECORATE
// definition can call that function directly without wrapping
// it inside VM code.
if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual))
if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual) && CheckAccessibility(ver))
{
unsigned imp = Function->GetImplicitArgs();
if (Function->Variants[0].ArgFlags.Size() > imp && !(Function->Variants[0].ArgFlags[imp] & VARF_Optional)) return nullptr;
@ -8509,6 +8562,11 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
int implicit = Function->GetImplicitArgs();
if (!CheckAccessibility(ctx.Version))
{
delete this;
return false;
}
// This should never happen.
if (Self == nullptr && (Function->Variants[0].Flags & VARF_Method))
{
@ -8718,7 +8776,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
}
VMFunction *vmfunc = Function->Variants[0].Implementation;
bool staticcall = (vmfunc->Final || vmfunc->VirtualIndex == ~0u || NoVirtual);
bool staticcall = ((vmfunc->VarFlags & VARF_Final) || vmfunc->VirtualIndex == ~0u || NoVirtual);
count = 0;
// Emit code to pass implied parameters
@ -9345,11 +9403,11 @@ ExpEmit FxSequence::Emit(VMFunctionBuilder *build)
//
//==========================================================================
VMFunction *FxSequence::GetDirectFunction()
VMFunction *FxSequence::GetDirectFunction(const VersionInfo &ver)
{
if (Expressions.Size() == 1)
{
return Expressions[0]->GetDirectFunction();
return Expressions[0]->GetDirectFunction(ver);
}
return nullptr;
}
@ -10331,11 +10389,11 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
return out;
}
VMFunction *FxReturnStatement::GetDirectFunction()
VMFunction *FxReturnStatement::GetDirectFunction(const VersionInfo &ver)
{
if (Args.Size() == 1)
{
return Args[0]->GetDirectFunction();
return Args[0]->GetDirectFunction(ver);
}
return nullptr;
}

View file

@ -86,8 +86,10 @@ struct FCompileContext
bool Unsafe = false;
TDeletingArray<FxLocalVariableDeclaration *> FunctionArgs;
PNamespace *CurGlobals;
VersionInfo Version;
FString VersionString;
FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump);
FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver);
FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants!
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
@ -322,7 +324,7 @@ public:
virtual bool isConstant() const;
virtual bool RequestAddress(FCompileContext &ctx, bool *writable);
virtual PPrototype *ReturnProto();
virtual VMFunction *GetDirectFunction();
virtual VMFunction *GetDirectFunction(const VersionInfo &ver);
virtual bool CheckReturn() { return false; }
virtual int GetBitValue() { return -1; }
bool IsNumeric() const { return ValueType->isNumeric(); }
@ -1712,12 +1714,14 @@ class FxVMFunctionCall : public FxExpression
TArray<ExpEmit> ReturnRegs;
PFunction *CallingFunction;
bool CheckAccessibility(const VersionInfo &ver);
public:
FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual);
~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
VMFunction *GetDirectFunction();
VMFunction *GetDirectFunction(const VersionInfo &ver);
ExpEmit Emit(VMFunctionBuilder *build);
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit &reg);
TArray<PType*> &GetReturnTypes() const
@ -1742,7 +1746,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
VMFunction *GetDirectFunction();
VMFunction *GetDirectFunction(const VersionInfo &ver);
bool CheckReturn();
};
@ -1949,7 +1953,7 @@ public:
~FxReturnStatement();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
VMFunction *GetDirectFunction();
VMFunction *GetDirectFunction(const VersionInfo &ver);
bool CheckReturn() { return true; }
};

View file

@ -1,5 +1,5 @@
#include "scopebarrier.h"
#include "dobject.h"
#include "scopebarrier.h"
// Note: the same object can't be both UI and Play. This is checked explicitly in the field construction and will cause esoteric errors here if found.
@ -44,6 +44,19 @@ int FScopeBarrier::FlagsFromSide(int side)
}
}
int FScopeBarrier::ObjectFlagsFromSide(int side)
{
switch (side)
{
case Side_Play:
return OF_Play;
case Side_UI:
return OF_UI;
default:
return 0;
}
}
// used for errors
const char* FScopeBarrier::StringFromSide(int side)
{
@ -72,6 +85,14 @@ int FScopeBarrier::ChangeSideInFlags(int flags, int side)
return flags;
}
// this modifies OF_ flags and sets the side properly.
int FScopeBarrier::ChangeSideInObjectFlags(int flags, int side)
{
flags &= ~(OF_UI | OF_Play);
flags |= ObjectFlagsFromSide(side);
return flags;
}
FScopeBarrier::FScopeBarrier()
{
sidefrom = -1;
@ -150,3 +171,27 @@ void FScopeBarrier::AddFlags(int flags1, int flags2, const char* name)
if (name) callerror.Format("Can't call %s function %s from %s context", StringFromSide(sideto), name, StringFromSide(sidefrom));
}
}
// these are for vmexec.h
void FScopeBarrier::ValidateNew(PClass* cls, PFunction* callingfunc)
{
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
if (outerside == FScopeBarrier::Side_Virtual)
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
int innerside = FScopeBarrier::SideFromObjectFlags(cls->ObjectFlags);
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) // "cannot construct ui class ... from data context"
ThrowAbortException(X_OTHER, "Cannot construct %s class %s from %s context", FScopeBarrier::StringFromSide(innerside), cls->TypeName.GetChars(), FScopeBarrier::StringFromSide(outerside));
}
// this can be imported in vmexec.h
void FScopeBarrier::ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype)
{
// [ZZ] anonymous blocks have 0 variants, so give them Side_Virtual.
int outerside = callingfunc->Variants.Size() ? FScopeBarrier::SideFromFlags(callingfunc->Variants[0].Flags) : FScopeBarrier::Side_Virtual;
if (outerside == FScopeBarrier::Side_Virtual)
outerside = FScopeBarrier::SideFromObjectFlags(callingfunc->OwningClass->ObjectFlags);
int innerside = FScopeBarrier::SideFromFlags(calledfunc->Variants[0].Flags);
if (innerside == FScopeBarrier::Side_Virtual)
innerside = FScopeBarrier::SideFromObjectFlags(selftype->ObjectFlags);
if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData))
ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->SymbolName.GetChars(), FScopeBarrier::StringFromSide(outerside));
}

View file

@ -35,12 +35,15 @@ struct FScopeBarrier
//
static int FlagsFromSide(int side);
static int ObjectFlagsFromSide(int side);
// used for errors
static const char* StringFromSide(int side);
// this modifies VARF_ flags and sets the side properly.
static int ChangeSideInFlags(int flags, int side);
// this modifies OF_ flags and sets the side properly.
static int ChangeSideInObjectFlags(int flags, int side);
FScopeBarrier();
FScopeBarrier(int flags1, int flags2, const char* name);
@ -48,5 +51,9 @@ struct FScopeBarrier
// This is used for comparing a.b.c.d access - if non-allowed field is seen anywhere in the chain, anything after it is non-allowed.
// This struct is used so that the logic is in a single place.
void AddFlags(int flags1, int flags2, const char* name);
// this is called from vmexec.h
static void ValidateNew(PClass* cls, PFunction* callingfunc);
static void ValidateCall(PFunction* calledfunc, PFunction* callingfunc, PClass* selftype);
};

View file

@ -802,9 +802,9 @@ void VMFunctionBuilder::BackpatchListToHere(TArray<size_t> &locs)
//==========================================================================
FFunctionBuildList FunctionBuildList;
VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum)
VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo &ver, PFunction *functype, FxExpression *code, const FString &name, bool fromdecorate, int stateindex, int statecount, int lumpnum)
{
auto func = code->GetDirectFunction();
auto func = code->GetDirectFunction(ver);
if (func != nullptr)
{
delete code;
@ -828,6 +828,7 @@ VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, PFunction *functy
it.StateIndex = stateindex;
it.StateCount = statecount;
it.Lump = lumpnum;
it.Version = ver;
assert(it.Func->Variants.Size() == 1);
it.Func->Variants[0].Implementation = it.Function;
@ -856,7 +857,7 @@ void FFunctionBuildList::Build()
assert(item.Code != NULL);
// We don't know the return type in advance for anonymous functions.
FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump);
FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump, item.Version);
// Allocate registers for the function's arguments and create local variable nodes before starting to resolve it.
VMFunctionBuilder buildit(item.Func->GetImplicitArgs());

View file

@ -146,13 +146,14 @@ class FFunctionBuildList
int StateIndex;
int StateCount;
int Lump;
VersionInfo Version;
bool FromDecorate;
};
TArray<Item> mItems;
public:
VMFunction *AddFunction(PNamespace *curglobals, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum);
VMFunction *AddFunction(PNamespace *curglobals, const VersionInfo &ver, PFunction *func, FxExpression *code, const FString &name, bool fromdecorate, int currentstate, int statecnt, int lumpnum);
void Build();
};

View file

@ -119,6 +119,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
bag.Namespace = ns;
bag.Info = type;
bag.fromDecorate = true;
bag.Version = { 2, 0, 0 };
#ifdef _DEBUG
bag.ClassName = type->TypeName;
#endif

View file

@ -69,6 +69,10 @@ EXTERN_CVAR(Bool, strictdecorate);
PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName)
{
if (parent->mVersion > MakeVersion(2, 0))
{
sc.Message(MSG_ERROR, "Parent class %s of %s not accessible to DECORATE", parent->GetClass()->TypeName.GetChars(), typeName.GetChars());
}
PClassActor *type = static_cast<PClassActor *>(parent->CreateDerivedClass(typeName, parent->Size));
if (type == nullptr)
{
@ -1125,6 +1129,7 @@ static void ParseActor(FScanner &sc, PNamespace *ns)
Baggage bag;
bag.Namespace = ns;
bag.Version = { 2, 0, 0 };
bag.fromDecorate = true;
info = ParseActorHeader(sc, &bag);
sc.MustGetToken('{');

View file

@ -340,7 +340,7 @@ endofstate:
if (ScriptCode != nullptr)
{
auto funcsym = CreateAnonymousFunction(actor, nullptr, state.UseFlags);
state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum);
state.ActionFunc = FunctionBuildList.AddFunction(bag.Namespace, bag.Version, funcsym, ScriptCode, FStringf("%s.StateFunction.%d", actor->TypeName.GetChars(), bag.statedef.GetStateCount()), true, bag.statedef.GetStateCount(), int(statestring.Len()), sc.LumpNum);
}
int count = bag.statedef.AddStates(&state, statestring, scp);
if (count < 0)

View file

@ -26,6 +26,7 @@ class PSymbol : public DObject
DECLARE_ABSTRACT_CLASS(PSymbol, DObject);
public:
FName SymbolName;
VersionInfo mVersion = { 0,0,0 };
protected:
PSymbol(FName name) { SymbolName = name; }
@ -76,6 +77,7 @@ class PField : public PSymbol
HAS_OBJECT_POINTERS
public:
PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0);
VersionInfo GetVersion();
size_t Offset;
PType *Type;

View file

@ -195,6 +195,8 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
if (symbol != nullptr)
{
PClass* cls_ctx = dyn_cast<PClass>(funccls);
PClass* cls_target = funcsym?dyn_cast<PClass>(funcsym->OwningClass):nullptr;
if (funcsym == nullptr)
{
sc.Message(MSG_ERROR, "%s is not a member function of %s", name.GetChars(), selfcls->TypeName.GetChars());
@ -204,6 +206,11 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
// private access is only allowed if the symbol table belongs to the class in which the current function is being defined.
sc.Message(MSG_ERROR, "%s is declared private and not accessible", symbol->SymbolName.GetChars());
}
else if ((funcsym->Variants[0].Flags & VARF_Protected) && (!cls_ctx || !cls_target || !cls_ctx->IsDescendantOf((PClass*)cls_target)))
{
sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars());
return nullptr;
}
else if (funcsym->Variants[0].Flags & VARF_Deprecated)
{
sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars());
@ -221,7 +228,7 @@ PFunction *FindClassMemberFunction(PStruct *selfcls, PStruct *funccls, FName nam
//
//==========================================================================
void CreateDamageFunction(PNamespace *OutNamespace, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum)
void CreateDamageFunction(PNamespace *OutNamespace, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum)
{
if (id == nullptr)
{
@ -231,7 +238,7 @@ void CreateDamageFunction(PNamespace *OutNamespace, PClassActor *info, AActor *d
{
auto dmg = new FxReturnStatement(new FxIntCast(id, true), id->ScriptPosition);
auto funcsym = CreateAnonymousFunction(info, TypeSInt32, 0);
defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum);
defaults->DamageFunc = FunctionBuildList.AddFunction(OutNamespace, ver, funcsym, dmg, FStringf("%s.DamageFunction", info->TypeName.GetChars()), fromDecorate, -1, 0, lumpnum);
}
}

View file

@ -124,6 +124,7 @@ struct Baggage
bool fromDecorate;
int CurrentState;
int Lumpnum;
VersionInfo Version;
FStateDefinitions statedef;
FDropItem *DropItemList;
@ -161,7 +162,7 @@ FName CheckCastKludges(FName in);
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FName> *argnames, PStruct *cls, DWORD funcflags, int useflags);
PFunction *CreateAnonymousFunction(PClass *containingclass, PType *returntype, int flags);
PFunction *FindClassMemberFunction(PStruct *cls, PStruct *funccls, FName name, FScriptPosition &sc, bool *error);
void CreateDamageFunction(PNamespace *ns, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum);
void CreateDamageFunction(PNamespace *ns, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum);
//==========================================================================
//

View file

@ -679,7 +679,7 @@ DEFINE_PROPERTY(damage, X, Actor)
defaults->DamageVal = dmgval;
// Only DECORATE can get here with a valid expression.
CreateDamageFunction(bag.Namespace, bag.Info, defaults, id, true, bag.Lumpnum);
CreateDamageFunction(bag.Namespace, bag.Version, bag.Info, defaults, id, true, bag.Lumpnum);
}
//==========================================================================

View file

@ -7,11 +7,8 @@
#include "cmdlib.h"
#include "doomerrors.h"
#include "memarena.h"
#include "scripting/backend/scopebarrier.h"
// [ZZ] there are serious circular references between this and the rest of ZScript code, so it needs to be done like this
// 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;
@ -705,11 +702,8 @@ do_double: if (inexact)
class VMFunction
{
public:
bool Native;
bool Final = false; // cannot be overridden
bool Unsafe = false; // Contains references to class fields that are unsafe for psp and item state calls.
bool FuncConst = false; // [ZZ] readonly function
int BarrierSide = 0; // [ZZ] FScopeBarrier::Side
bool Unsafe = false;
int VarFlags = 0; // [ZZ] this replaces 5+ bool fields
BYTE ImplicitArgs = 0; // either 0 for static, 1 for method or 3 for action
unsigned VirtualIndex = ~0u;
FName Name;
@ -718,7 +712,7 @@ public:
class PPrototype *Proto;
VMFunction(FName name = NAME_None) : Native(false), ImplicitArgs(0), Name(name), Proto(NULL)
VMFunction(FName name = NAME_None) : ImplicitArgs(0), Name(name), Proto(NULL)
{
AllFunctions.Push(this);
}
@ -942,9 +936,10 @@ class VMNativeFunction : public VMFunction
public:
typedef int (*NativeCallType)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);
VMNativeFunction() : NativeCall(NULL) { Native = true; }
VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; }
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { Native = true; }
// 8 is VARF_Native. I can't write VARF_Native because of circular references between this and dobject/dobjtype.
VMNativeFunction() : NativeCall(NULL) { VarFlags = 8; }
VMNativeFunction(NativeCallType call) : NativeCall(call) { VarFlags = 8; }
VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { VarFlags = 8; }
// Return value is the number of results.
NativeCallType NativeCall;

View file

@ -201,7 +201,7 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
VMScriptFunction *calleefunc = static_cast<VMScriptFunction *>(callee->Func);
const VMRegisters calleereg(callee);
assert(calleefunc != NULL && !calleefunc->Native);
assert(calleefunc != NULL && !(calleefunc->VarFlags & VARF_Native));
assert(numparam == calleefunc->NumArgs || ((int)calleefunc->DefaultArgs.Size() == calleefunc->NumArgs));
assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);

View file

@ -22,7 +22,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
const FVoidObj *konsta;
const VM_ATAG *konstatag;
if (f->Func != NULL && !f->Func->Native)
if (f->Func != NULL && !(f->Func->VarFlags & VARF_Native))
{
sfunc = static_cast<VMScriptFunction *>(f->Func);
konstd = sfunc->KonstD;
@ -673,13 +673,13 @@ begin:
PFunction* callingfunc = (PFunction*)(reg.param + f->NumParam - b)[1].a;
DObject* dobj = (DObject*)(reg.param + f->NumParam - b)[2].a; // this is the self pointer. it should be in, since Side_Virtual functions are always non-static methods.
PClass* selftype = dobj->GetClass();
FScopeBarrier_ValidateCall(calledfunc, callingfunc, selftype);
FScopeBarrier::ValidateCall(calledfunc, callingfunc, selftype);
b -= 2;
}
#endif
FillReturns(reg, f, returns, pc+1, C);
if (call->Native)
if (call->VarFlags & VARF_Native)
{
try
{
@ -736,7 +736,7 @@ begin:
{
VMFunction *call = (VMFunction *)ptr;
if (call->Native)
if (call->VarFlags & VARF_Native)
{
try
{
@ -821,7 +821,7 @@ begin:
if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
// [ZZ] validate readonly and between scope construction
if (callingfunc)
FScopeBarrier_ValidateNew(cls, callingfunc);
FScopeBarrier::ValidateNew(cls, callingfunc);
reg.a[a] = cls->CreateNew();
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
@ -1966,7 +1966,7 @@ static void SetReturn(const VMRegisters &reg, VMFrame *frame, VMReturn *ret, VM_
const void *src;
VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func);
assert(func != NULL && !func->Native);
assert(func != NULL && !(func->VarFlags & VARF_Native));
assert((regtype & ~REGT_KONST) == ret->RegType);
switch (regtype & REGT_TYPE)

View file

@ -48,7 +48,6 @@ TArray<VMFunction *> VMFunction::AllFunctions;
VMScriptFunction::VMScriptFunction(FName name)
{
Native = false;
Name = name;
LineInfo = nullptr;
Code = NULL;
@ -438,7 +437,7 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
bool allocated = false;
try
{
if (func->Native)
if (func->VarFlags & VARF_Native)
{
return static_cast<VMNativeFunction *>(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults);
}

View file

@ -40,6 +40,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line)
struct ClassFlagsBlock {
VM_UWORD Flags;
ZCC_Identifier *Replaces;
VersionInfo Version;
};
struct StateOpts {
@ -188,6 +189,7 @@ class_head(X) ::= EXTEND CLASS(T) IDENTIFIER(A).
head->ParentName = nullptr;
head->Flags = ZCC_Extension;
head->Replaces = nullptr;
head->Version = {0, 0};
head->Type = nullptr;
head->Symbol = nullptr;
X = head;
@ -200,6 +202,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
head->ParentName = B;
head->Flags = C.Flags;
head->Replaces = C.Replaces;
head->Version = C.Version;
head->Type = nullptr;
head->Symbol = nullptr;
X = head;
@ -210,12 +213,13 @@ class_ancestry(X) ::= . { X = NULL; }
class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
%type class_flags{ClassFlagsBlock}
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; X.Version = {0,0}; }
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; X.Replaces = A.Replaces; }
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
class_flags(X) ::= class_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Replaces = A.Replaces; X.Version = C.String->GetChars(); }
/*----- Dottable Identifier -----*/
// This can be either a single identifier or two identifiers connected by a .
@ -322,15 +326,18 @@ struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body
def->Body = B;
def->Type = nullptr;
def->Symbol = nullptr;
def->Version = S.Version;
def->Flags = S.Flags;
X = def;
}
%type struct_flags{ClassFlagsBlock}
struct_flags(X) ::= . { X.Flags = 0; }
struct_flags(X) ::= . { X.Flags = 0; X.Version = {0, 0}; }
struct_flags(X) ::= struct_flags(A) UI. { X.Flags = A.Flags | ZCC_UIFlag; }
struct_flags(X) ::= struct_flags(A) PLAY. { X.Flags = A.Flags | ZCC_Play; }
struct_flags(X) ::= struct_flags(A) CLEARSCOPE. { X.Flags = A.Flags | ZCC_ClearScope; }
struct_flags(X) ::= struct_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; }
struct_flags(X) ::= struct_flags(A) VERSION LPAREN STRCONST(C) RPAREN. { X.Flags = A.Flags | ZCC_Version; X.Version = C.String->GetChars(); }
opt_struct_body(X) ::= . { X = NULL; }
opt_struct_body(X) ::= struct_body(X).
@ -866,6 +873,9 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
decl->Name = C.FuncName;
decl->UseFlags = A == nullptr? nullptr : A->Id;
decl->Flags = (A == nullptr? 0 : A->Flags) | C.FuncFlags;
if (A == nullptr) decl->Version = {0,0,0};
else decl->Version = A->Version;
decl->Body = C.FuncBody;
X = decl;
}
@ -874,7 +884,16 @@ declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
NEW_AST_NODE(VarDeclarator, decl, A == nullptr? B->SourceLoc : A->SourceLoc);
decl->Type = B;
decl->Names = C.VarNames;
decl->Flags = (A == nullptr? 0 : A->Flags);
if (A == nullptr)
{
decl->Flags = 0;
decl->Version = {0,0,0};
}
else
{
decl->Flags = A->Flags;
decl->Version = A->Version;
}
X = decl;
}
else
@ -965,6 +984,7 @@ decl_flags(X) ::= decl_flags(F) decl_flag(A).
X = nil_f;
X->Id = nullptr;
X->Flags = A.Int;
X->Version = { 0, 0 };
}
else
{
@ -981,6 +1001,8 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
X = nil_f;
X->Flags = ZCC_Action;
X->Id = nullptr;
X->Version = { 0, 0 };
}
else
{
@ -990,6 +1012,42 @@ decl_flags(X) ::= decl_flags(F) ACTION(B) states_opts(A).
X->Id = A;
}
decl_flags(X) ::= decl_flags(F) DEPRECATED(B) LPAREN STRCONST(A) RPAREN.
{
if (F == nullptr)
{
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
X = nil_f;
X->Flags = ZCC_Deprecated;
X->Id = nullptr;
X->Version = { 0, 0 };
}
else
{
X = F;
X->Flags |= ZCC_Deprecated;
}
X->Version = A.String->GetChars();
}
decl_flags(X) ::= decl_flags(F) VERSION(B) LPAREN STRCONST(A) RPAREN.
{
if (F == nullptr)
{
NEW_AST_NODE(DeclFlags,nil_f,B.SourceLoc);
X = nil_f;
X->Flags = ZCC_Version;
X->Id = nullptr;
X->Version = { 0, 0 };
}
else
{
X = F;
X->Flags |= ZCC_Version;
}
X->Version = A.String->GetChars();
}
decl_flag(X) ::= NATIVE(T). { X.Int = ZCC_Native; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= STATIC(T). { X.Int = ZCC_Static; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= PRIVATE(T). { X.Int = ZCC_Private; X.SourceLoc = T.SourceLoc; }
@ -999,7 +1057,6 @@ decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= TRANSIENT(T). { X.Int = ZCC_Transient; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= OVERRIDE(T). { X.Int = ZCC_Override; X.SourceLoc = T.SourceLoc; }
decl_flag(X) ::= VARARG(T). { X.Int = ZCC_VarArg; X.SourceLoc = T.SourceLoc; }

View file

@ -275,8 +275,8 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
//
//==========================================================================
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum)
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum)
ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols, PNamespace *_outnamespc, int lumpnum, const VersionInfo &ver)
: Outer(_outer), GlobalTreeNodes(&_symbols), OutNamespace(_outnamespc), AST(ast), Lump(lumpnum), mVersion(ver)
{
FScriptPosition::ResetErrorCounter();
// Group top-level nodes by type
@ -495,16 +495,32 @@ void ZCCCompiler::CreateStructTypes()
{
s->strct->Type = NewStruct(s->NodeName(), outer);
}
if ((s->strct->Flags & (ZCC_UIFlag | ZCC_Play)) == (ZCC_UIFlag | ZCC_Play))
if (s->strct->Flags & ZCC_Version)
{
Error(s->strct, "Struct %s has incompatible flags", s->NodeName().GetChars());
s->strct->Type->mVersion = s->strct->Version;
}
if (s->strct->Flags & ZCC_UIFlag)
s->Type()->ObjectFlags |= OF_UI;
if (s->strct->Flags & ZCC_Play)
s->Type()->ObjectFlags |= OF_Play;
if (mVersion >= MakeVersion(2, 4, 0))
{
if ((s->strct->Flags & (ZCC_UIFlag | ZCC_Play)) == (ZCC_UIFlag | ZCC_Play))
{
Error(s->strct, "Struct %s has incompatible flags", s->NodeName().GetChars());
}
if (outer != OutNamespace) s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::SideFromObjectFlags(outer->ObjectFlags));
else if (s->strct->Flags & ZCC_ClearScope) Warn(s->strct, "Useless 'ClearScope' on struct %s not inside a class", s->NodeName().GetChars());
if (s->strct->Flags & ZCC_UIFlag)
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_UI);
if (s->strct->Flags & ZCC_Play)
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_Play);
if (s->strct->Flags & ZCC_ClearScope)
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_PlainData); // don't inherit the scope from the outer class
}
else
{
// old versions force 'play'.
s->Type()->ObjectFlags = FScopeBarrier::ChangeSideInObjectFlags(s->Type()->ObjectFlags, FScopeBarrier::Side_Play);
}
s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type());
syms->AddSymbol(s->strct->Symbol);
@ -593,6 +609,10 @@ void ZCCCompiler::CreateClassTypes()
// We will never get here if the name is a duplicate, so we can just do the assignment.
try
{
if (parent->mVersion > mVersion)
{
Error(c->cls, "Parent class %s of %s not accessible to ZScript version %d.%d.%d", parent->TypeName.GetChars(), c->NodeName().GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
}
c->cls->Type = parent->CreateDerivedClass(c->NodeName(), TentativeClass);
if (c->Type() == nullptr)
{
@ -610,28 +630,40 @@ void ZCCCompiler::CreateClassTypes()
if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName());
if (c->cls->Flags & ZCC_Abstract)
c->Type()->ObjectFlags |= OF_Abstract;
//
static int incompatible[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope };
int incompatiblecnt = 0;
for (size_t k = 0; k < countof(incompatible); k++)
if (incompatible[k] & c->cls->Flags) incompatiblecnt++;
if (incompatiblecnt > 1)
if (c->cls->Flags & ZCC_Version)
{
Error(c->cls, "Class %s has incompatible flags", c->NodeName().GetChars());
c->Type()->mVersion = c->cls->Version;
}
if (c->cls->Flags & ZCC_UIFlag)
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI;
if (c->cls->Flags & ZCC_Play)
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play;
if (parent->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play
//
if (mVersion >= MakeVersion(2, 4, 0))
{
if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play))
static int incompatible[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope };
int incompatiblecnt = 0;
for (size_t k = 0; k < countof(incompatible); k++)
if (incompatible[k] & c->cls->Flags) incompatiblecnt++;
if (incompatiblecnt > 1)
{
Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars());
Error(c->cls, "Class %s has incompatible flags", c->NodeName().GetChars());
}
c->Type()->ObjectFlags = (c->Type()->ObjectFlags & ~(OF_UI | OF_Play)) | (parent->ObjectFlags & (OF_UI | OF_Play));
if (c->cls->Flags & ZCC_UIFlag)
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_Play) | OF_UI;
if (c->cls->Flags & ZCC_Play)
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play;
if (parent->ObjectFlags & (OF_UI | OF_Play)) // parent is either ui or play
{
if (c->cls->Flags & (ZCC_UIFlag | ZCC_Play))
{
Error(c->cls, "Can't change class scope in class %s", c->NodeName().GetChars());
}
c->Type()->ObjectFlags = (c->Type()->ObjectFlags & ~(OF_UI | OF_Play)) | (parent->ObjectFlags & (OF_UI | OF_Play));
}
}
else
{
c->Type()->ObjectFlags = (c->Type()->ObjectFlags&~OF_UI) | OF_Play;
}
c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.)
@ -1098,16 +1130,23 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly;
if (field->Flags & ZCC_Transient) varflags |= VARF_Transient;
if (type->ObjectFlags & OF_UI)
varflags |= VARF_UI;
if (type->ObjectFlags & OF_Play)
if (mVersion >= MakeVersion(2, 4, 0))
{
if (type->ObjectFlags & OF_UI)
varflags |= VARF_UI;
if (type->ObjectFlags & OF_Play)
varflags |= VARF_Play;
if (field->Flags & ZCC_UIFlag)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
if (field->Flags & ZCC_Play)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
if (field->Flags & ZCC_ClearScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData);
}
else
{
varflags |= VARF_Play;
if (field->Flags & ZCC_UIFlag)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
if (field->Flags & ZCC_Play)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
if (field->Flags & ZCC_ClearScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData);
}
if (field->Flags & ZCC_Native)
{
@ -1174,7 +1213,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
{
// 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);
auto f = type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
if (field->Flags & (ZCC_Version | ZCC_Deprecated)) f->mVersion = field->Version;
}
}
}
@ -1184,7 +1224,8 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
}
else
{
type->AddField(name->Name, thisfieldtype, varflags);
auto f = type->AddField(name->Name, thisfieldtype, varflags);
if (field->Flags & (ZCC_Version | ZCC_Deprecated)) f->mVersion = field->Version;
}
}
name = static_cast<ZCC_VarName*>(name->SiblingNext);
@ -1467,6 +1508,11 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
Error(field, "%s does not represent a class type", FName(ctype->Restriction->Id).GetChars());
return TypeError;
}
if (typesym->Type->mVersion > mVersion)
{
Error(field, "Class %s not accessible to ZScript version %d.%d.%d", FName(ctype->Restriction->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
return TypeError;
}
retval = NewClassPointer(static_cast<PClass *>(typesym->Type));
}
break;
@ -1500,6 +1546,12 @@ PType *ZCCCompiler::ResolveUserType(ZCC_BasicType *type, PSymbolTable *symt)
if (sym != nullptr && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
{
auto ptype = static_cast<PSymbolType *>(sym)->Type;
if (ptype->mVersion > mVersion)
{
Error(type, "Type %s not accessible to ZScript version %d.%d.%d", FName(type->UserType->Id).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
return TypeError;
}
if (ptype->IsKindOf(RUNTIME_CLASS(PEnum)))
{
return TypeSInt32; // hack this to an integer until we can resolve the enum mess.
@ -1846,7 +1898,7 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
if (namenode->Id == NAME_DamageFunction)
{
auto x = ConvertNode(prop->Values);
CreateDamageFunction(OutNamespace, cls, (AActor *)bag.Info->Defaults, x, false, Lump);
CreateDamageFunction(OutNamespace, mVersion, cls, (AActor *)bag.Info->Defaults, x, false, Lump);
((AActor *)bag.Info->Defaults)->DamageVal = -1;
return;
}
@ -2001,6 +2053,7 @@ void ZCCCompiler::InitDefaults()
#ifdef _DEBUG
bag.ClassName = c->Type()->TypeName;
#endif
bag.Version = mVersion;
bag.Namespace = OutNamespace;
bag.Info = ti;
bag.DropItemSet = false;
@ -2124,31 +2177,27 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (f->Flags & ZCC_Override) varflags |= VARF_Override;
if (f->Flags & ZCC_VarArg) varflags |= VARF_VarArg;
if (f->Flags & ZCC_FuncConst) varflags |= VARF_ReadOnly; // FuncConst method is internally marked as VARF_ReadOnly
if (c->Type()->ObjectFlags & OF_UI)
varflags |= VARF_UI;
if (c->Type()->ObjectFlags & OF_Play)
varflags |= VARF_Play;
if (f->Flags & ZCC_FuncConst)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag.
if (f->Flags & ZCC_UIFlag)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
if (f->Flags & ZCC_Play)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
if (f->Flags & ZCC_ClearScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Clear);
if (f->Flags & ZCC_VirtualScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual);
// [ZZ] supporting const self for actors is quite a cumbersome task because there's no concept of a const pointer (?)
// either way, it doesn't make sense, because you can call any method on a readonly class instance.
// The above is nonsense. This needs to work and needs to be implemented properly.
/*
if ((f->Flags & ZCC_FuncConst) && (c->Type()->IsKindOf(RUNTIME_CLASS(PClass))))
if (mVersion >= MakeVersion(2, 4, 0))
{
Error(f, "'Const' on a method can only be used in structs");
if (c->Type()->ObjectFlags & OF_UI)
varflags |= VARF_UI;
if (c->Type()->ObjectFlags & OF_Play)
varflags |= VARF_Play;
//if (f->Flags & ZCC_FuncConst)
// varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_PlainData); // const implies clearscope. this is checked a bit later to also not have ZCC_Play/ZCC_UIFlag.
if (f->Flags & ZCC_UIFlag)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_UI);
if (f->Flags & ZCC_Play)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Play);
if (f->Flags & ZCC_ClearScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Clear);
if (f->Flags & ZCC_VirtualScope)
varflags = FScopeBarrier::ChangeSideInFlags(varflags, FScopeBarrier::Side_Virtual);
}
else
{
varflags |= VARF_Play;
}
*/
if ((f->Flags & ZCC_VarArg) && !(f->Flags & ZCC_Native))
{
@ -2216,13 +2265,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
Error(f, "'VirtualScope' on a static method is not supported");
}
// you can't have a const function belonging to either ui or play.
// const is intended for plain data to signify that you can call a method on readonly variable.
if ((f->Flags & ZCC_FuncConst) && (f->Flags & (ZCC_UIFlag | ZCC_Play | ZCC_VirtualScope)))
{
Error(f, "Invalid combination of qualifiers %s on function %s", FlagsToString(f->Flags&(ZCC_FuncConst | ZCC_UIFlag | ZCC_Play | ZCC_VirtualScope)).GetChars(), FName(f->Name).GetChars());
}
static int excludescope[] = { ZCC_UIFlag, ZCC_Play, ZCC_ClearScope, ZCC_VirtualScope };
excludeflags = 0;
fc = 0;
@ -2393,6 +2435,14 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (imp != nullptr) vindex = imp->VirtualIndex;
else Error(f, "Virtual base function %s not found in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars());
}
if (f->Flags & (ZCC_Version | ZCC_Deprecated))
{
sym->mVersion = f->Version;
if (varflags & VARF_Override)
{
Error(f, "Overridden function %s may not alter version restriction in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars());
}
}
if (!(f->Flags & ZCC_Native))
{
@ -2406,7 +2456,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
auto code = ConvertAST(c->Type(), f->Body);
if (code != nullptr)
{
FunctionBuildList.AddFunction(OutNamespace, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
FunctionBuildList.AddFunction(OutNamespace, mVersion, sym, code, FStringf("%s.%s", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars()), false, -1, 0, Lump);
}
}
}
@ -2418,7 +2468,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
if (sym->Variants[0].Implementation != nullptr)
{
// [ZZ] unspecified virtual function inherits old scope. virtual function scope can't be changed.
sym->Variants[0].Implementation->BarrierSide = FScopeBarrier::SideFromFlags(varflags);
sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags;
}
PClass *clstype = static_cast<PClass *>(c->Type());
@ -2429,11 +2479,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
Error(f, "Virtual function %s.%s not present", c->Type()->TypeName.GetChars(), FName(f->Name).GetChars());
return;
}
if (varflags & VARF_Final)
sym->Variants[0].Implementation->Final = true;
if (varflags & VARF_ReadOnly)
sym->Variants[0].Implementation->FuncConst = true;
if (forclass)
{
@ -2448,7 +2493,12 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
else
{
auto oldfunc = clstype->Virtuals[vindex];
if (oldfunc->Final)
auto parentfunc = dyn_cast<PFunction>(clstype->ParentClass->Symbols.FindSymbol(sym->SymbolName, true));
if (parentfunc && parentfunc->mVersion > mVersion)
{
Error(f, "Attempt to override function %s which is incompatible with version %d.%d.%d", FName(f->Name).GetChars(), mVersion.major, mVersion.minor, mVersion.revision);
}
if (oldfunc->VarFlags & VARF_Final)
{
Error(f, "Attempt to override final function %s", FName(f->Name).GetChars());
}
@ -2458,19 +2508,26 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
Error(f, "Attempt to change scope for virtual function %s", FName(f->Name).GetChars());
}
// you can't change const qualifier for a virtual method
if (oldfunc->FuncConst != sym->Variants[0].Implementation->FuncConst)
if ((sym->Variants[0].Implementation->VarFlags & VARF_ReadOnly) && !(oldfunc->VarFlags & VARF_ReadOnly))
{
Error(f, "Attempt to change const qualifier for virtual function %s", FName(f->Name).GetChars());
Error(f, "Attempt to add const qualifier to virtual function %s", FName(f->Name).GetChars());
}
// you can't change protected qualifier for a virtual method (i.e. putting private), because this cannot be reliably checked without runtime stuff
if (f->Flags & (ZCC_Private | ZCC_Protected))
{
Error(f, "Attempt to change private/protected qualifiers for virtual function %s", FName(f->Name).GetChars());
}
// inherit scope of original function if override not specified
sym->Variants[0].Implementation->BarrierSide = oldfunc->BarrierSide;
sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, oldfunc->BarrierSide);
sym->Variants[0].Flags = FScopeBarrier::ChangeSideInFlags(sym->Variants[0].Flags, FScopeBarrier::SideFromFlags(oldfunc->VarFlags));
// inherit const from original function
if ((sym->Variants[0].Implementation->FuncConst = oldfunc->FuncConst))
if (oldfunc->VarFlags & VARF_ReadOnly)
sym->Variants[0].Flags |= VARF_ReadOnly;
if (oldfunc->VarFlags & VARF_Protected)
sym->Variants[0].Flags |= VARF_Protected;
clstype->Virtuals[vindex] = sym->Variants[0].Implementation;
sym->Variants[0].Implementation->VirtualIndex = vindex;
sym->Variants[0].Implementation->VarFlags = sym->Variants[0].Flags;
}
}
else
@ -2740,7 +2797,7 @@ void ZCCCompiler::CompileStates()
if (code != nullptr)
{
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags);
state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump);
state.ActionFunc = FunctionBuildList.AddFunction(OutNamespace, mVersion, funcsym, code, FStringf("%s.StateFunction.%d", c->Type()->TypeName.GetChars(), statedef.GetStateCount()), false, statedef.GetStateCount(), (int)sl->Frames->Len(), Lump);
}
}

View file

@ -86,7 +86,7 @@ struct ZCC_ConstantWork
class ZCCCompiler
{
public:
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum);
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PNamespace *outnamespace, int lumpnum, const VersionInfo & ver);
~ZCCCompiler();
int Compile();
@ -127,6 +127,7 @@ private:
TArray<ZCC_StructWork *> Structs;
TArray<ZCC_ClassWork *> Classes;
TArray<ZCC_PropertyWork *> Properties;
VersionInfo mVersion;
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);

View file

@ -41,6 +41,7 @@
#include "i_system.h"
#include "m_argv.h"
#include "v_text.h"
#include "version.h"
#include "zcc_parser.h"
#include "zcc_compile.h"
@ -145,6 +146,7 @@ static void InitTokenMap()
TOKENDEF (TK_Final, ZCC_FINAL);
TOKENDEF (TK_Meta, ZCC_META);
TOKENDEF (TK_Deprecated, ZCC_DEPRECATED);
TOKENDEF (TK_Version, ZCC_VERSION);
TOKENDEF (TK_ReadOnly, ZCC_READONLY);
TOKENDEF ('{', ZCC_LBRACE);
TOKENDEF ('}', ZCC_RBRACE);
@ -179,7 +181,6 @@ static void InitTokenMap()
TOKENDEF (']', ZCC_RBRACKET);
TOKENDEF (TK_In, ZCC_IN);
TOKENDEF (TK_Out, ZCC_OUT);
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
TOKENDEF (TK_Super, ZCC_SUPER);
TOKENDEF (TK_Null, ZCC_NULLPTR);
TOKENDEF ('~', ZCC_TILDE);
@ -232,29 +233,36 @@ static void InitTokenMap()
//**--------------------------------------------------------------------------
static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCParseState &state)
static void ParseSingleFile(FScanner *pSC, const char *filename, int lump, void *parser, ZCCParseState &state)
{
int tokentype;
//bool failed;
ZCCToken value;
FScanner sc;
FScanner lsc;
if (filename != nullptr)
if (pSC == nullptr)
{
lump = Wads.CheckNumForFullName(filename, true);
if (lump >= 0)
if (filename != nullptr)
{
sc.OpenLumpNum(lump);
lump = Wads.CheckNumForFullName(filename, true);
if (lump >= 0)
{
lsc.OpenLumpNum(lump);
}
else
{
Printf("Could not find script lump '%s'\n", filename);
return;
}
}
else
{
Printf("Could not find script lump '%s'\n", filename);
return;
}
}
else sc.OpenLumpNum(lump);
else lsc.OpenLumpNum(lump);
pSC = &lsc;
}
FScanner &sc = *pSC;
sc.SetParseVersion(state.ParseVersion);
state.sc = &sc;
while (sc.GetToken())
{
value.SourceLoc = sc.GetMessageLine();
@ -343,9 +351,47 @@ static void DoParse(int lumpnum)
#endif
sc.OpenLumpNum(lumpnum);
sc.SetParseVersion({ 2, 4 }); // To get 'version' we need parse version 2.4 for the initial test
auto saved = sc.SavePos();
ParseSingleFile(nullptr, lumpnum, parser, state);
if (sc.GetToken())
{
if (sc.TokenType == TK_Version)
{
char *endp;
sc.MustGetString();
state.ParseVersion.major = (int16_t)clamp<unsigned long long>(strtoull(sc.String, &endp, 10), 0, USHRT_MAX);
if (*endp != '.')
{
sc.ScriptError("Bad version directive");
}
state.ParseVersion.minor = (int16_t)clamp<unsigned long long>(strtoll(endp + 1, &endp, 10), 0, USHRT_MAX);
if (*endp == '.')
{
state.ParseVersion.revision = (int16_t)clamp<unsigned long long>(strtoll(endp + 1, &endp, 10), 0, USHRT_MAX);
}
else state.ParseVersion.revision = 0;
if (*endp != 0)
{
sc.ScriptError("Bad version directive");
}
if (state.ParseVersion.major == USHRT_MAX || state.ParseVersion.minor == USHRT_MAX || state.ParseVersion.revision == USHRT_MAX)
{
sc.ScriptError("Bad version directive");
}
if (state.ParseVersion > MakeVersion(VER_MAJOR, VER_MINOR, VER_REVISION))
{
sc.ScriptError("Version mismatch. %d.%d.%d expected but only %d.%d.%d supported", state.ParseVersion.major, state.ParseVersion.minor, state.ParseVersion.revision, VER_MAJOR, VER_MINOR, VER_REVISION);
}
}
else
{
state.ParseVersion = MakeVersion(2, 3); // 2.3 is the first version of ZScript.
sc.RestorePos(saved);
}
}
ParseSingleFile(&sc, nullptr, lumpnum, parser, state);
for (unsigned i = 0; i < Includes.Size(); i++)
{
lumpnum = Wads.CheckNumForFullName(Includes[i], true);
@ -362,7 +408,7 @@ static void DoParse(int lumpnum)
Wads.GetWadFullName(Wads.GetLumpFile(baselump)), Includes[i].GetChars());
}
ParseSingleFile(nullptr, lumpnum, parser, state);
ParseSingleFile(nullptr, nullptr, lumpnum, parser, state);
}
}
Includes.Clear();
@ -405,7 +451,7 @@ static void DoParse(int lumpnum)
PSymbolTable symtable;
auto newns = Wads.GetLumpFile(lumpnum) == 0 ? Namespaces.GlobalNamespace : Namespaces.NewNamespace(Wads.GetLumpFile(lumpnum));
ZCCCompiler cc(state, NULL, symtable, newns, lumpnum);
ZCCCompiler cc(state, NULL, symtable, newns, lumpnum, state.ParseVersion);
cc.Compile();
if (FScriptPosition::ErrorCounter > 0)
@ -436,16 +482,6 @@ void ParseScripts()
}
}
/*
CCMD(parse)
{
if (argv.argc() == 2)
{
DoParse(argv[1]);
}
}
*/
static FString ZCCTokenName(int terminal)
{
if (terminal == ZCC_EOF)

View file

@ -41,6 +41,7 @@ enum
ZCC_Play = 1 << 18,
ZCC_ClearScope = 1 << 19,
ZCC_VirtualScope = 1 << 20,
ZCC_Version = 1 << 21,
};
// Function parameter modifiers
@ -194,6 +195,7 @@ struct ZCC_Struct : ZCC_NamedNode
VM_UWORD Flags;
ZCC_TreeNode *Body;
PStruct *Type;
VersionInfo Version;
};
struct ZCC_Property : ZCC_NamedNode
@ -483,6 +485,7 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode
struct ZCC_DeclFlags : ZCC_TreeNode
{
ZCC_Identifier *Id;
VersionInfo Version;
int Flags;
};
@ -497,6 +500,7 @@ struct ZCC_Declarator : ZCC_TreeNode
{
ZCC_Type *Type;
int Flags;
VersionInfo Version;
};
// A variable in a class or struct.
@ -542,6 +546,7 @@ struct ZCC_AST
FSharedStringArena Strings;
FMemArena SyntaxArena;
struct ZCC_TreeNode *TopNode;
VersionInfo ParseVersion;
};
struct ZCCParseState : public ZCC_AST

View file

@ -51,6 +51,7 @@
#include "colormatcher.h"
#include "v_palette.h"
#include "d_player.h"
#include "g_levellocals.h"
CVAR( Float, blood_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Pulled from Skulltag - changed default from 0.5 to 1.0
CVAR( Float, pickup_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Uses same logic as blood_fade_scalar except for pickups
@ -168,13 +169,19 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
{
if (CPlayer->hazardcount > 16*TICRATE || (CPlayer->hazardcount & 8))
{
V_AddBlend (0.f, 1.f, 0.f, 0.125f, blend);
float r = ((level.hazardflash & 0xff0000) >> 16) / 255.f;
float g = ((level.hazardflash & 0xff00) >> 8) / 255.f;
float b = ((level.hazardflash & 0xff)) / 255.f;
V_AddBlend (r, g, b, 0.125f, blend);
}
}
else
{
cnt= MIN(CPlayer->hazardcount/8, 64);
V_AddBlend (0.f, 0.2571f, 0.f, cnt/93.2571428571f, blend);
float r = ((level.hazardcolor & 0xff0000) >> 16) / 255.f;
float g = ((level.hazardcolor & 0xff00) >> 8) / 255.f;
float b = ((level.hazardcolor & 0xff)) / 255.f;
V_AddBlend (r, g, b, cnt/93.2571428571f, blend);
}
}

View file

@ -53,6 +53,10 @@ const char *GetVersionString();
#define RC_FILEVERSION 1,3,9999,0
#define RC_PRODUCTVERSION 1,3,9999,0
#define RC_PRODUCTVERSION2 VERSIONSTR
// These are for content versioning. The current state is '2.4'.
#define VER_MAJOR 2
#define VER_MINOR 4
#define VER_REVISION 0
// Version identifier for network games.
// Bump it every time you do a release unless you're certain you

View file

@ -1,3 +1,4 @@
version "2.4"
#include "zscript/base.txt"
#include "zscript/sounddata.txt"
#include "zscript/mapdata.txt"

View file

@ -237,17 +237,17 @@ class Actor : Thinker native
//int ConversationRoot; // THe root of the current dialogue
// 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;
native readonly deprecated("2.3") double X;
native readonly deprecated("2.3") double Y;
native readonly deprecated("2.3") double Z;
native readonly deprecated("2.3") double VelX;
native readonly deprecated("2.3") double VelY;
native readonly deprecated("2.3") double VelZ;
native readonly deprecated("2.3") double MomX;
native readonly deprecated("2.3") double MomY;
native readonly deprecated("2.3") double MomZ;
native deprecated("2.3") double ScaleX;
native deprecated("2.3") double ScaleY;
//FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.;
@ -717,7 +717,7 @@ class Actor : Thinker native
return true;
}
deprecated void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
deprecated("2.3") void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0)
{
@ -868,18 +868,18 @@ class Actor : Thinker native
}
}
deprecated void A_MeleeAttack()
deprecated("2.3") void A_MeleeAttack()
{
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
}
deprecated void A_MissileAttack()
deprecated("2.3") void A_MissileAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
}
deprecated void A_ComboAttack()
deprecated("2.3") void A_ComboAttack()
{
Class<Actor> MissileType = MissileName;
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
@ -919,13 +919,13 @@ class Actor : Thinker native
native void A_Wander(int flags = 0);
native void A_Look2();
deprecated native void A_BulletAttack();
deprecated("2.3") native void A_BulletAttack();
native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class<Actor> pufftype = "BulletPuff");
native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false);
deprecated void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); }
deprecated("2.3") void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); }
native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was...
deprecated native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
deprecated native void A_StopSoundEx(name slot);
deprecated("2.3") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
deprecated("2.3") native void A_StopSoundEx(name slot);
native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
native action state A_Jump(int chance, statelabel label, ...);
native Actor A_SpawnProjectile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET);
@ -951,7 +951,7 @@ class Actor : Thinker native
native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
native void A_DropInventory(class<Inventory> itemtype, int amount = -1);
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0);
deprecated native void A_ChangeFlag(string flagname, bool value);
deprecated("2.3") native void A_ChangeFlag(string flagname, bool value);
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
native void A_RaiseMaster(int flags = 0);
native void A_RaiseChildren(int flags = 0);
@ -990,10 +990,10 @@ class Actor : Thinker native
native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT);
native void A_ScaleVelocity(double scale, int ptr = AAPTR_DEFAULT);
native void A_ChangeVelocity(double x = 0, double y = 0, double z = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
deprecated native void A_SetUserVar(name varname, int value);
deprecated native void A_SetUserArray(name varname, int index, int value);
deprecated native void A_SetUserVarFloat(name varname, double value);
deprecated native void A_SetUserArrayFloat(name varname, int index, double value);
deprecated("2.3") native void A_SetUserVar(name varname, int value);
deprecated("2.3") native void A_SetUserArray(name varname, int index, int value);
deprecated("2.3") native void A_SetUserVarFloat(name varname, double value);
deprecated("2.3") native void A_SetUserArrayFloat(name varname, int index, double value);
native void A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake");
native void A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0);
action native void A_SetTics(int tics);
@ -1093,7 +1093,7 @@ class Actor : Thinker native
}
// Internal functions
deprecated private native int __decorate_internal_int__(int i);
deprecated private native bool __decorate_internal_bool__(bool b);
deprecated private native double __decorate_internal_float__(double f);
deprecated("2.3") private native int __decorate_internal_int__(int i);
deprecated("2.3") private native bool __decorate_internal_bool__(bool b);
deprecated("2.3") private native double __decorate_internal_float__(double f);
}

View file

@ -170,7 +170,7 @@ extend class Actor
private native bool CheckFlag(string flagname, int check_pointer = AAPTR_DEFAULT);
deprecated action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
deprecated("2.3") action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
{
return CheckFlag(flagname, check_pointer)? ResolveState(label) : null;
}

View file

@ -1,4 +1,4 @@
struct InputEventData native
struct InputEventData native version("2.4")
{
native uint8 type;
native uint8 subtype;
@ -244,7 +244,7 @@ struct Font native
native BrokenLines BreakLines(String text, int maxlen);
}
struct Translation
struct Translation version("2.4")
{
Color colors[256];
@ -290,7 +290,7 @@ struct CVar native
native int ResetToDefault();
}
struct GIFont
struct GIFont version("2.4")
{
Name fontname;
Name color;
@ -337,7 +337,7 @@ class Object native
virtual virtualscope void OnDestroy() {}
}
class BrokenLines : Object native
class BrokenLines : Object native version("2.4")
{
native int Count();
native int StringWidth(int line);
@ -458,23 +458,23 @@ struct LevelLocals native
native int found_items;
native int total_monsters;
native int killed_monsters;
native double gravity;
native double aircontrol;
native double airfriction;
native int airsupply;
native double teamdamage;
native bool monsterstelefrag;
native bool actownspecial;
native bool sndseqtotalctrl;
native play double gravity;
native play double aircontrol;
native play double airfriction;
native play int airsupply;
native readonly double teamdamage;
native readonly bool monsterstelefrag;
native readonly bool actownspecial;
native readonly bool sndseqtotalctrl;
native bool allmap;
native bool missilesactivateimpact;
native bool monsterfallingdamage;
native bool checkswitchrange;
native bool polygrind;
native bool nomonsters;
native readonly bool missilesactivateimpact;
native readonly bool monsterfallingdamage;
native readonly bool checkswitchrange;
native readonly bool polygrind;
native readonly bool nomonsters;
native bool frozen;
native bool infinite_flight;
native bool no_dlg_freeze;
native readonly bool infinite_flight;
native readonly bool no_dlg_freeze;
// level_info_t *info cannot be done yet.
native String GetUDMFString(int type, int index, Name key);
@ -618,7 +618,7 @@ class Floor : Thinker native
floorRaiseInstant,
floorMoveToValue,
floorRaiseToLowestCeiling,
floorRaiseuint8xture,
floorRaiseByTexture,
floorLowerAndChange,
floorRaiseAndChange,
@ -626,7 +626,7 @@ class Floor : Thinker native
floorRaiseToLowest,
floorRaiseToCeiling,
floorLowerToLowestCeiling,
floorLoweruint8xture,
floorLowerByTexture,
floorLowerToCeiling,
donutRaise,
@ -669,8 +669,8 @@ class Ceiling : Thinker native
ceilLowerToNearest,
ceilRaiseToHighestFloor,
ceilRaiseToFloor,
ceilRaiseuint8xture,
ceilLoweruint8xture,
ceilRaiseByTexture,
ceilLowerByTexture,
genCeilingChg0,
genCeilingChgT,

View file

@ -2,12 +2,12 @@
extend class Object
{
deprecated static int GameType() // deprecated for 2.4.x
deprecated("2.4") static int GameType()
{
return gameinfo.gametype;
}
deprecated static void C_MidPrint(string fontname, string textlabel, bool bold = false) // deprecated for 2.4.x
deprecated("2.4") static void C_MidPrint(string fontname, string textlabel, bool bold = false)
{
let f = Font.GetFont(fontname);
if (f == null) return;
@ -18,7 +18,7 @@ extend class Object
extend class Actor
{
deprecated void A_CustomMissile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET)
deprecated("2.3") void A_CustomMissile(class<Actor> missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET)
{
A_SpawnProjectile(missiletype, spawnheight, spawnofs_xy, angle, flags|CMF_BADPITCH, pitch, ptr);
}
@ -26,7 +26,7 @@ extend class Actor
extend class StateProvider
{
deprecated action void A_FireCustomMissile(class<Actor> missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0)
deprecated("2.3") action void A_FireCustomMissile(class<Actor> missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0)
{
A_FireProjectile(missiletype, angle, useammo, spawnofs_xy, spawnheight, flags, -pitch);
}

View file

@ -1,6 +1,6 @@
class BaseEvent native { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything.
class BaseEvent native version("2.4") { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything.
class RenderEvent : BaseEvent native ui
class RenderEvent : BaseEvent native ui version("2.4")
{
native readonly Vector3 ViewPos;
native readonly double ViewAngle;
@ -10,7 +10,7 @@ class RenderEvent : BaseEvent native ui
native readonly Actor Camera;
}
class WorldEvent : BaseEvent native play
class WorldEvent : BaseEvent native play version("2.4")
{
// for loaded/unloaded
native readonly bool IsSaveGame;
@ -28,7 +28,7 @@ class WorldEvent : BaseEvent native play
native readonly double DamageAngle;
}
class PlayerEvent : BaseEvent native play
class PlayerEvent : BaseEvent native play version("2.4")
{
// this is the player number that caused the event.
// note: you can get player struct from this by using players[e.PlayerNumber]
@ -37,7 +37,7 @@ class PlayerEvent : BaseEvent native play
native readonly bool IsReturn;
}
class UiEvent : BaseEvent native ui
class UiEvent : BaseEvent native ui version("2.4")
{
// d_gui.h
enum EGUIEvent
@ -121,7 +121,7 @@ class UiEvent : BaseEvent native ui
native readonly bool IsAlt;
}
class InputEvent : BaseEvent native play
class InputEvent : BaseEvent native play version("2.4")
{
enum EGenericEvent
{
@ -270,7 +270,7 @@ class InputEvent : BaseEvent native play
native readonly int MouseY;
}
class ConsoleEvent : BaseEvent native
class ConsoleEvent : BaseEvent native version("2.4")
{
// for net events, this will be the activator.
// for UI events, this is always -1, and you need to check if level is loaded and use players[consoleplayer].
@ -279,16 +279,16 @@ class ConsoleEvent : BaseEvent native
native readonly int Args[3];
}
class StaticEventHandler : Object native play
class StaticEventHandler : Object native play version("2.4")
{
// static event handlers CAN register other static event handlers.
// unlike EventHandler.Create that will not create them.
protected static native StaticEventHandler Create(class<StaticEventHandler> type);
protected static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
protected static native StaticEventHandler Find(Class<StaticEventHandler> type); // just for convenience. who knows.
clearscope static native StaticEventHandler Create(class<StaticEventHandler> type);
clearscope static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
clearscope static native StaticEventHandler Find(Class<StaticEventHandler> type); // just for convenience. who knows.
protected static native bool Register(StaticEventHandler handler);
protected static native bool Unregister(StaticEventHandler handler);
clearscope static native bool Register(StaticEventHandler handler);
clearscope static native bool Unregister(StaticEventHandler handler);
// these are called when the handler gets registered or unregistered
// you can set Order/IsUiProcessor here.
@ -335,14 +335,14 @@ class StaticEventHandler : Object native play
native bool RequireMouse;
}
class EventHandler : StaticEventHandler native
class EventHandler : StaticEventHandler native version("2.4")
{
static native StaticEventHandler Create(class<StaticEventHandler> type);
static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
static native StaticEventHandler Find(class<StaticEventHandler> type);
clearscope static native StaticEventHandler Create(class<StaticEventHandler> type);
clearscope static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
clearscope static native StaticEventHandler Find(class<StaticEventHandler> type);
static native bool Register(StaticEventHandler handler);
static native bool Unregister(StaticEventHandler handler);
clearscope static native bool Register(StaticEventHandler handler);
clearscope static native bool Unregister(StaticEventHandler handler);
clearscope static native void SendNetworkEvent(String name, int arg1 = 0, int arg2 = 0, int arg3 = 0);
}

View file

@ -751,7 +751,7 @@ class Inventory : Actor native
virtual bool Use (bool pickup) { return false; }
virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; }
virtual ui void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual version("2.4") ui void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual void OwnerDied() {}
virtual Color GetBlend () { return 0; }
@ -818,7 +818,7 @@ class Inventory : Actor native
//
//===========================================================================
virtual ui bool DrawPowerup(int x, int y) { return false; }
virtual ui version("2.4") bool DrawPowerup(int x, int y) { return false; }
//===========================================================================
//

View file

@ -31,10 +31,10 @@ class CustomInventory : StateProvider
//---------------------------------------------------------------------------
// This is only here, because these functions were originally exported on Inventory, despite only working for weapons, so this is here to satisfy some potential old mods having called it through CustomInventory.
deprecated action void A_GunFlash(statelabel flash = null, int flags = 0) {}
deprecated action void A_Lower() {}
deprecated action void A_Raise() {}
deprecated action void A_CheckReload() {}
deprecated("2.3") action void A_GunFlash(statelabel flash = null, int flags = 0) {}
deprecated("2.3") action void A_Lower() {}
deprecated("2.3") action void A_Raise() {}
deprecated("2.3") action void A_CheckReload() {}
native bool CallStateChain (Actor actor, State state);
//===========================================================================

View file

@ -32,7 +32,7 @@
**
*/
struct StrifeDialogueNode native
struct StrifeDialogueNode native version("2.4")
{
native Class<Actor> DropType;
native int ThisNodeNum;
@ -49,7 +49,7 @@ struct StrifeDialogueNode native
}
// FStrifeDialogueReply holds responses the player can give to the NPC
struct StrifeDialogueReply native
struct StrifeDialogueReply native version("2.4")
{
native StrifeDialogueReply Next;
native Class<Actor> GiveType;

View file

@ -1,5 +1,5 @@
struct KeyBindings native
struct KeyBindings native version("2.4")
{
native static String NameKeys(int k1, int k2);
@ -8,7 +8,7 @@ struct KeyBindings native
native void UnbindACommand (String str);
}
struct OptionValues native
struct OptionValues native version("2.4")
{
native static int GetCount(Name group);
native static String GetText(Name group, int index);
@ -16,7 +16,7 @@ struct OptionValues native
native static String GetTextValue(Name group, int index);
}
struct JoystickConfig native
struct JoystickConfig native version("2.4")
{
enum EJoyAxis
{
@ -48,7 +48,7 @@ struct JoystickConfig native
}
class Menu : Object native ui
class Menu : Object native ui version("2.4")
{
enum EMenuKey
{
@ -287,7 +287,7 @@ class Menu : Object native ui
}
class MenuDescriptor : Object native ui
class MenuDescriptor : Object native ui version("2.4")
{
native Name mMenuName;
native String mNetgameMessage;

View file

@ -4,7 +4,7 @@
//
//=============================================================================
class MenuItemBase : Object native ui
class MenuItemBase : Object native ui version("2.4")
{
protected native double mXpos, mYpos;
protected native Name mAction;

View file

@ -32,7 +32,7 @@
**
*/
struct FOptionMenuSettings
struct FOptionMenuSettings version("2.4")
{
int mTitleColor;
int mFontColor;

View file

@ -3,7 +3,7 @@
// INTERMISSION
// Structure passed e.g. to WI_Start(wb)
//
struct WBPlayerStruct native
struct WBPlayerStruct native version("2.4")
{
// Player stats, kills, collected items etc.
native int skills;
@ -14,7 +14,7 @@ struct WBPlayerStruct native
native int fragcount; // [RH] Cumulative frags for this player
}
struct WBStartStruct native
struct WBStartStruct native version("2.4")
{
native int finished_ep;
native int next_ep;