From e2711a74e784a0980f7ca2085fe2af1406df1f34 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 21:48:57 -0500 Subject: [PATCH 1/7] Add float user vars for DECORATE - PClass::Extend now takes alignment into consideration. --- src/dobjtype.cpp | 15 ++++++++------- src/dobjtype.h | 3 ++- src/thingdef/thingdef_parse.cpp | 10 +++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 609ec17211..121c0fb27d 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2403,22 +2403,23 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) //========================================================================== // -// PClass:: Extend +// PClass :: Extend // -// Add bytes to the end of this class. Returns the previous -// size of the class. +// Add bytes to the end of this class and possibly more to meet +// alignment restrictions. Returns the start of the extended block. // //========================================================================== -unsigned int PClass::Extend(unsigned int extension) +unsigned int PClass::Extend(unsigned int extension, unsigned int alignment) { assert(this->bRuntimeClass); unsigned int oldsize = Size; - Size += extension; + unsigned int padto = (oldsize + alignment - 1) & ~(alignment - 1); + Size = padto + extension; Defaults = (BYTE *)M_Realloc(Defaults, Size); - memset(Defaults + oldsize, 0, extension); - return oldsize; + memset(Defaults + oldsize, 0, Size - oldsize); + return padto; } //========================================================================== diff --git a/src/dobjtype.h b/src/dobjtype.h index b482efe457..05097795bb 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -660,7 +660,8 @@ public: void InsertIntoHash(); DObject *CreateNew() const; PClass *CreateDerivedClass(FName name, unsigned int size); - unsigned int Extend(unsigned int extension); + unsigned int Extend(unsigned int extension, unsigned int alignment); + unsigned int Extend(const PType *type) { return Extend(type->Size, type->Align); } void InitializeActorInfo(); void BuildFlatPointers(); const PClass *NativeClass() const; diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 97e22dc8c0..cc2c71e34b 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -531,14 +531,14 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl sc.ScriptError("Native classes may not have user variables"); } - // Read the type and make sure it's int. + // Read the type and make sure it's acceptable. sc.MustGetAnyToken(); - if (sc.TokenType != TK_Int) + if (sc.TokenType != TK_Int && sc.TokenType != TK_Float) { - sc.ScriptMessage("User variables must be of type int"); + sc.ScriptMessage("User variables must be of type 'int' or 'float'"); FScriptPosition::ErrorCounter++; } - type = TypeSInt32; + type = sc.TokenType == TK_Int ? (PType *)TypeSInt32 : (PType *)TypeFloat64; sc.MustGetToken(TK_Identifier); // For now, restrict user variables to those that begin with "user_" to guarantee @@ -585,7 +585,7 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl sc.MustGetToken(';'); PField *sym = new PField(symname, type, 0); - sym->Offset = cls->Extend(sizeof(int) * maxelems); + sym->Offset = cls->Extend(type); if (symt->AddSymbol(sym) == NULL) { delete sym; From feb5ab31cc920cdc1053d35cef907c83ec5e8592 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:05:25 -0500 Subject: [PATCH 2/7] Add double variants of SetValue() for numeric PTypes --- src/dobjtype.cpp | 29 ++++++++++++++++++++++++++++- src/dobjtype.h | 5 +++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 121c0fb27d..0a964917c1 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -392,7 +392,12 @@ bool PType::VisitedNodeSet::Check(const PType *node) void PType::SetValue(void *addr, int val) { - assert(0 && "Cannot set value for this type"); + assert(0 && "Cannot set int value for this type"); +} + +void PType::SetValue(void *addr, double val) +{ + assert(0 && "Cannot set float value for this type"); } //========================================================================== @@ -682,6 +687,11 @@ void PInt::SetValue(void *addr, int val) } } +void PInt::SetValue(void *addr, double val) +{ + SetValue(addr, (int)val); +} + //========================================================================== // // PInt :: GetValueInt @@ -927,6 +937,11 @@ void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count) //========================================================================== void PFloat::SetValue(void *addr, int val) +{ + return SetValue(addr, (double)val); +} + +void PFloat::SetValue(void *addr, double val) { assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); if (Size == 4) @@ -1112,6 +1127,12 @@ void PFixed::SetValue(void *addr, int val) *(fixed_t *)addr = val << FRACBITS; } +void PFixed::SetValue(void *addr, double val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(fixed_t *)addr = FLOAT2FIXED(val); +} + //========================================================================== // // PFixed :: GetValueInt @@ -1173,6 +1194,12 @@ void PAngle::SetValue(void *addr, int val) *(angle_t *)addr = Scale(val, ANGLE_90, 90); } +void PAngle::SetValue(void *addr, double val) +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + *(angle_t *)addr = (angle_t)(val * ANGLE_90 / 90); +} + //========================================================================== // // PAngle :: GetValueInt diff --git a/src/dobjtype.h b/src/dobjtype.h index 05097795bb..a5e2ab2a24 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -188,6 +188,7 @@ public: // Sets the value of a variable of this type at (addr) virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); // Gets the value of a variable of this type at (addr) virtual int GetValueInt(void *addr) const; @@ -320,6 +321,7 @@ public: PInt(unsigned int size, bool unsign); virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; @@ -344,6 +346,7 @@ public: PFloat(unsigned int size); virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; @@ -410,6 +413,7 @@ public: PFixed(); virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; @@ -422,6 +426,7 @@ public: PAngle(); virtual void SetValue(void *addr, int val); + virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; From 299019ea158d794e599e5bdf739d98285e64d9f6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:24:59 -0500 Subject: [PATCH 3/7] Add GetValueFloat() for numeric PTypes --- src/dobjtype.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++-- src/dobjtype.h | 5 +++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 0a964917c1..552b8ee685 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -412,6 +412,12 @@ int PType::GetValueInt(void *addr) const return 0; } +double PType::GetValueFloat(void *addr) const +{ + assert(0 && "Cannot get value for this type"); + return 0; +} + //========================================================================== // // PType :: GetStoreOp @@ -724,6 +730,17 @@ int PInt::GetValueInt(void *addr) const } } +//========================================================================== +// +// PInt :: GetValueFloat +// +//========================================================================== + +double PInt::GetValueFloat(void *addr) const +{ + return GetValueInt(addr); +} + //========================================================================== // // PInt :: GetStoreOp @@ -962,16 +979,27 @@ void PFloat::SetValue(void *addr, double val) //========================================================================== int PFloat::GetValueInt(void *addr) const +{ + return xs_ToInt(GetValueFloat(addr)); +} + +//========================================================================== +// +// PFloat :: GetValueFloat +// +//========================================================================== + +double PFloat::GetValueFloat(void *addr) const { assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); if (Size == 4) { - return xs_ToInt(*(float *)addr); + return *(float *)addr; } else { assert(Size == 8); - return xs_ToInt(*(double *)addr); + return *(double *)addr; } } @@ -1145,6 +1173,18 @@ int PFixed::GetValueInt(void *addr) const return *(fixed_t *)addr >> FRACBITS; } +//========================================================================== +// +// PFixed :: GetValueFloat +// +//========================================================================== + +double PFixed::GetValueFloat(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return FIXED2DBL(*(fixed_t *)addr); +} + //========================================================================== // // PFixed :: GetStoreOp @@ -1212,6 +1252,18 @@ int PAngle::GetValueInt(void *addr) const return *(angle_t *)addr / ANGLE_1; } +//========================================================================== +// +// PAngle :: GetValueFloat +// +//========================================================================== + +double PAngle::GetValueFloat(void *addr) const +{ + assert(((intptr_t)addr & (Align - 1)) == 0 && "unaligned address"); + return (double)(*(angle_t *)addr) / ANGLE_1; +} + //========================================================================== // // PAngle :: GetStoreOp diff --git a/src/dobjtype.h b/src/dobjtype.h index a5e2ab2a24..e9ff982454 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -192,6 +192,7 @@ public: // Gets the value of a variable of this type at (addr) virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; // Gets the opcode to store from a register to memory virtual int GetStoreOp() const; @@ -323,6 +324,7 @@ public: virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; virtual int GetRegType() const; @@ -348,6 +350,7 @@ public: virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; virtual int GetRegType() const; @@ -415,6 +418,7 @@ public: virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; }; @@ -428,6 +432,7 @@ public: virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, double val); virtual int GetValueInt(void *addr) const; + virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; }; From b6e3358b1cf62e39bd4f6c7d54ffacf546bd3cec Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:14:31 -0500 Subject: [PATCH 4/7] Add A_SetUserVarFloat and A_SetUserArrayFloat --- src/thingdef/thingdef_codeptr.cpp | 86 ++++++++++++++++++++++++------- wadsrc/static/actors/actor.txt | 2 + 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 6efbeb1671..9fa547f461 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -4681,22 +4681,46 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpecial) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) +static PField *GetVar(AActor *self, FName varname) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME (varname); - PARAM_INT (value); - PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); if (var == NULL || (var->Flags & VARF_Native) || !var->Type->IsKindOf(RUNTIME_CLASS(PBasicType))) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return 0; + return nullptr; } + return var; +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) +{ + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_INT (value); + // Set the value of the specified user variable. - var->Type->SetValue(reinterpret_cast(self) + var->Offset, value); + PField *var = GetVar(self, varname); + if (var != nullptr) + { + var->Type->SetValue(reinterpret_cast(self) + var->Offset, value); + } + return 0; +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVarFloat) +{ + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_FLOAT (value); + + // Set the value of the specified user variable. + PField *var = GetVar(self, varname); + if (var != nullptr) + { + var->Type->SetValue(reinterpret_cast(self) + var->Offset, value); + } return 0; } @@ -4706,13 +4730,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) // //=========================================================================== -DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) +static PField *GetArrayVar(AActor *self, FName varname, int pos) { - PARAM_ACTION_PROLOGUE; - PARAM_NAME (varname); - PARAM_INT (pos); - PARAM_INT (value); - PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); if (var == NULL || (var->Flags & VARF_Native) || @@ -4721,17 +4740,48 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) { Printf("%s is not a user array in class %s\n", varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return 0; + return nullptr; } - PArray *arraytype = static_cast(var->Type); - if ((unsigned)pos >= arraytype->ElementCount) + if ((unsigned)pos >= static_cast(var->Type)->ElementCount) { Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), self->GetClass()->TypeName.GetChars()); - return 0; + return nullptr; } + return var; +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) +{ + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_INT (pos); + PARAM_INT (value); + // Set the value of the specified user array at index pos. - arraytype->ElementType->SetValue(reinterpret_cast(self) + var->Offset + arraytype->ElementSize * pos, value); + PField *var = GetArrayVar(self, varname, pos); + if (var != nullptr) + { + PArray *arraytype = static_cast(var->Type); + arraytype->ElementType->SetValue(reinterpret_cast(self) + var->Offset + arraytype->ElementSize * pos, value); + } + return 0; +} + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArrayFloat) +{ + PARAM_ACTION_PROLOGUE; + PARAM_NAME (varname); + PARAM_INT (pos); + PARAM_FLOAT (value); + + // Set the value of the specified user array at index pos. + PField *var = GetArrayVar(self, varname, pos); + if (var != nullptr) + { + PArray *arraytype = static_cast(var->Type); + arraytype->ElementType->SetValue(reinterpret_cast(self) + var->Offset + arraytype->ElementSize * pos, value); + } return 0; } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index e3bb06fe74..7548cd6c91 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -275,6 +275,8 @@ ACTOR Actor native //: Thinker action native A_SetArg(int pos, int value); action native A_SetUserVar(name varname, int value); action native A_SetUserArray(name varname, int index, int value); + action native A_SetUserVarFloat(name varname, float value); + action native A_SetUserArrayFloat(name varname, int index, float value); action native A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); action native A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, float mulWaveX = 1, float mulWaveY = 1, float mulWaveZ = 1, int falloff = 0, int highpoint = 0); From 35121544b4eb5d8dbdad1aedd9889b12db539cc7 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:33:10 -0500 Subject: [PATCH 5/7] Add float support to ACS's Get/SetUserVariable functions - "Support" means that setting one will convert from fixed point to floating point, and reading one will do the reverse. --- src/p_acs.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index fe10921d03..42048c159e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4567,7 +4567,14 @@ static void SetUserVariable(AActor *self, FName varname, int index, int value) if (GetVarAddrType(self, varname, index, addr, type)) { - type->SetValue(addr, value); + if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + type->SetValue(addr, value); + } + else + { + type->SetValue(addr, FIXED2DBL(value)); + } } } @@ -4578,7 +4585,14 @@ static int GetUserVariable(AActor *self, FName varname, int index) if (GetVarAddrType(self, varname, index, addr, type)) { - return type->GetValueInt(addr); + if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + return type->GetValueInt(addr); + } + else + { + return FLOAT2FIXED(type->GetValueFloat(addr)); + } } return 0; } From b37ef48e99a5729a21356e30ab36f1f671eebd5a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:36:26 -0500 Subject: [PATCH 6/7] Allow ACS's GetUserVariable to access non-user variables - Since DECORATE already allows reading all declared variables in a class, where's the utility in keeping this restriction in ACS? - Variables must still be numeric types. - SetUserVariable is still restricted to user variables only. --- src/p_acs.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 42048c159e..9dbbd5eea4 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4529,12 +4529,12 @@ int DLevelScript::LineFromID(int id) } } -bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type) +bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type, bool allownative) { PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); PArray *arraytype; - if (var == NULL || (var->Flags & VARF_Native)) + if (var == NULL || (!allownative && (var->Flags & VARF_Native))) { return false; } @@ -4557,6 +4557,12 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType * return false; } addr = baddr; + // We don't want Int subclasses like Name or Color to be accessible, + // but we do want to support Float subclasses like Fixed. + if (!type->IsA(RUNTIME_CLASS(PInt)) || !type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + return false; + } return true; } @@ -4565,7 +4571,7 @@ static void SetUserVariable(AActor *self, FName varname, int index, int value) void *addr; PType *type; - if (GetVarAddrType(self, varname, index, addr, type)) + if (GetVarAddrType(self, varname, index, addr, type, false)) { if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) { @@ -4583,7 +4589,7 @@ static int GetUserVariable(AActor *self, FName varname, int index) void *addr; PType *type; - if (GetVarAddrType(self, varname, index, addr, type)) + if (GetVarAddrType(self, varname, index, addr, type, true)) { if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) { From 1648a71e45c00296094f0505c79f8d8b2f7f8fa6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Mar 2016 22:49:12 -0500 Subject: [PATCH 7/7] Add support for Name and String types to ACS's GetUserVariable - Reading one of these types will copy its value into the global ACS string table and return the index. --- src/p_acs.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9dbbd5eea4..1436836020 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4529,12 +4529,12 @@ int DLevelScript::LineFromID(int id) } } -bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type, bool allownative) +bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType *&type, bool readonly) { PField *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); PArray *arraytype; - if (var == NULL || (!allownative && (var->Flags & VARF_Native))) + if (var == NULL || (!readonly && (var->Flags & VARF_Native))) { return false; } @@ -4561,6 +4561,11 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType * // but we do want to support Float subclasses like Fixed. if (!type->IsA(RUNTIME_CLASS(PInt)) || !type->IsKindOf(RUNTIME_CLASS(PFloat))) { + // For reading, we also support Name and String types. + if (readonly && (type->IsA(RUNTIME_CLASS(PName)) || type->IsA(RUNTIME_CLASS(PString)))) + { + return true; + } return false; } return true; @@ -4591,13 +4596,21 @@ static int GetUserVariable(AActor *self, FName varname, int index) if (GetVarAddrType(self, varname, index, addr, type, true)) { - if (!type->IsKindOf(RUNTIME_CLASS(PFloat))) + if (type->IsKindOf(RUNTIME_CLASS(PFloat))) { - return type->GetValueInt(addr); + return FLOAT2FIXED(type->GetValueFloat(addr)); + } + else if (type->IsA(RUNTIME_CLASS(PName))) + { + return GlobalACSStrings.AddString(FName(ENamedName(type->GetValueInt(addr))).GetChars()); + } + else if (type->IsA(RUNTIME_CLASS(PString))) + { + return GlobalACSStrings.AddString(*(FString *)addr); } else { - return FLOAT2FIXED(type->GetValueFloat(addr)); + return type->GetValueInt(addr); } } return 0;