diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index 08db26505..cd2cc317c 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -302,6 +302,7 @@ bool FBaseCVar::ToBool (UCVarValue value, ECVarType type) case CVAR_Bool: return value.Bool; + case CVAR_Color: case CVAR_Int: return !!value.Int; @@ -331,6 +332,7 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type) switch (type) { case CVAR_Bool: res = (int)value.Bool; break; + case CVAR_Color: case CVAR_Int: res = value.Int; break; #if __GNUC__ <= 2 case CVAR_Float: tmp = value.Float; res = (int)tmp; break; @@ -359,6 +361,7 @@ float FBaseCVar::ToFloat (UCVarValue value, ECVarType type) case CVAR_Bool: return (float)value.Bool; + case CVAR_Color: case CVAR_Int: return (float)value.Int; @@ -388,6 +391,7 @@ const char *FBaseCVar::ToString (UCVarValue value, ECVarType type) case CVAR_String: return value.String; + case CVAR_Color: case CVAR_Int: mysnprintf (cstrbuf, countof(cstrbuf), "%i", value.Int); break; @@ -1830,6 +1834,21 @@ void FZSIntCVar::MarkZSCVar() GC::Mark(customCVarHandler); } +UCVarValue FZSIntCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + int val = ToInt(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomIntCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + UCVarValue v; + v.Int = val; + return v; +} + //=========================================================================== // @@ -1849,11 +1868,11 @@ void FZSFloatCVar::CallCVarCallback(FZSFloatCVar &self) } IFVIRTUALPTRNAME(self.customCVarHandler, "CustomFloatCVar", ModifyValue) { - VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , (double)self.Value }; + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , (double) self.Value }; double v; VMReturn ret(&v); VMCall(func, param, 3, &ret, 1); - self.Value = float(v); + self.Value = (float) v; } } @@ -1875,6 +1894,23 @@ void FZSFloatCVar::MarkZSCVar() GC::Mark(customCVarHandler); } +UCVarValue FZSFloatCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + float val = ToFloat(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomFloatCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , (double) val }; + double v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + val = (float) v; + } + + UCVarValue v; + v.Float = val; + return v; +} + //=========================================================================== // @@ -1918,6 +1954,25 @@ void FZSStringCVar::MarkZSCVar() GC::Mark(customCVarHandler); } +UCVarValue FZSStringCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + FString val = ToString(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomStringCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , &val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + char * str = new char[val.Len() + 1]; + memcpy(str, val.GetChars(), val.Len() * sizeof(char)); + str[val.Len()] = '\0'; + + UCVarValue v; + v.String = str; + return v; +} + //=========================================================================== // @@ -1963,10 +2018,27 @@ void FZSBoolCVar::MarkZSCVar() GC::Mark(customCVarHandler); } +UCVarValue FZSBoolCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + bool val = ToFloat(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomBoolCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + int v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + val = v; + } + + UCVarValue v; + v.Bool = val; + return v; +} + //=========================================================================== // -// FZSIntCVar +// FZSColorCVar // //=========================================================================== @@ -2004,4 +2076,19 @@ void FZSColorCVar::InstantiateZSCVar() void FZSColorCVar::MarkZSCVar() { GC::Mark(customCVarHandler); +} + +UCVarValue FZSColorCVar::GenericZSCVarCallback(UCVarValue value, ECVarType type) { + int val = ToInt(value, type); + + IFVIRTUALPTRNAME(customCVarHandler, "CustomColorCVar", ModifyValue) + { + VMValue param[] = { customCVarHandler.Get() , cvarName.GetIndex() , val }; + VMReturn ret(&val); + VMCall(func, param, 3, &ret, 1); + } + + UCVarValue v; + v.Int = val; + return v; } \ No newline at end of file diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h index d4cd7241a..4d2737ab3 100644 --- a/src/common/console/c_cvars.h +++ b/src/common/console/c_cvars.h @@ -50,30 +50,31 @@ CVARS (console variables) enum { - CVAR_ARCHIVE = 1, // set to cause it to be saved to config. - CVAR_USERINFO = 1 << 1, // added to userinfo when changed. - CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed. - CVAR_NOSET = 1 << 3, // don't allow change from console at all, - // but can be set from the command line. - CVAR_LATCH = 1 << 4, // save changes until server restart. - CVAR_UNSETTABLE = 1 << 5, // can unset this var from console. - CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo. - CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation? - CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed. - CVAR_NOINITCALL = 1 << 9, // don't call callback at game start. - CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section. - CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented). - CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame - // and config. - CVAR_MOD = 1 << 13, // cvar was defined by a mod. - CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS - // (dummy mod cvar). - CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled. - CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context. - CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to - // mirror an external variable. - CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network. - CVAR_ZS_CUSTOM = 1 << 19, // Custom CVar backed by a ZScript class + CVAR_ARCHIVE = 1, // set to cause it to be saved to config. + CVAR_USERINFO = 1 << 1, // added to userinfo when changed. + CVAR_SERVERINFO = 1 << 2, // added to serverinfo when changed. + CVAR_NOSET = 1 << 3, // don't allow change from console at all, + // but can be set from the command line. + CVAR_LATCH = 1 << 4, // save changes until server restart. + CVAR_UNSETTABLE = 1 << 5, // can unset this var from console. + CVAR_DEMOSAVE = 1 << 6, // save the value of this cvar in a demo. + CVAR_ISDEFAULT = 1 << 7, // is cvar unchanged since creation? + CVAR_AUTO = 1 << 8, // allocated; needs to be freed when destroyed. + CVAR_NOINITCALL = 1 << 9, // don't call callback at game start. + CVAR_GLOBALCONFIG = 1 << 10, // cvar is saved to global config section. + CVAR_VIDEOCONFIG = 1 << 11, // cvar is saved to video config section (not implemented). + CVAR_NOSAVE = 1 << 12, // when used with CVAR_SERVERINFO, do not save var to savegame + // and config. + CVAR_MOD = 1 << 13, // cvar was defined by a mod. + CVAR_IGNORE = 1 << 14, // do not send cvar across the network/inaccesible from ACS + // (dummy mod cvar). + CVAR_CHEAT = 1 << 15, // can be set only when sv_cheats is enabled. + CVAR_UNSAFECONTEXT = 1 << 16, // cvar value came from unsafe context. + CVAR_VIRTUAL = 1 << 17, // do not invoke the callback recursively so it can be used to + // mirror an external variable. + CVAR_CONFIG_ONLY = 1 << 18, // do not save var to savegame and do not send it across network. + CVAR_ZS_CUSTOM = 1 << 19, // Custom CVar backed by a ZScript class + CVAR_ZS_CUSTOM_CLONE = 1 << 20, // Clone of a Custom ZScript CVar }; enum ECVarType @@ -184,6 +185,12 @@ public: virtual UCVarValue GetFavoriteRepDefault (ECVarType *type) const = 0; virtual void SetGenericRepDefault (UCVarValue value, ECVarType type) = 0; + virtual UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) + { // not valid for cvars that aren't custom zscript cvars, doesn't modify the actual cvar directly, just transforms the value + // FZSStringCVar allocates a buffer for the returned string that must be freed by the caller + return 0; + } + FBaseCVar &operator= (const FBaseCVar &var) { UCVarValue val; ECVarType type; val = var.GetFavoriteRep (&type); SetGenericRep (val, type); return *this; } @@ -502,6 +509,7 @@ public: FZSIntCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); void InstantiateZSCVar() override; void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; }; class FZSFloatCVar : public FFloatCVar @@ -515,6 +523,7 @@ public: FZSFloatCVar(const char *name, float def, uint32_t flags, FName className, const char* descr = nullptr); void InstantiateZSCVar() override; void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; }; class FZSStringCVar : public FStringCVar @@ -528,6 +537,7 @@ public: FZSStringCVar(const char *name, const char * def, uint32_t flags, FName className, const char* descr = nullptr); void InstantiateZSCVar() override; void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; }; class FZSBoolCVar : public FBoolCVar @@ -541,6 +551,7 @@ public: FZSBoolCVar(const char *name, bool def, uint32_t flags, FName className, const char* descr = nullptr); void InstantiateZSCVar() override; void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; }; class FZSColorCVar : public FColorCVar @@ -554,6 +565,7 @@ public: FZSColorCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); void InstantiateZSCVar() override; void MarkZSCVar() override; + UCVarValue GenericZSCVarCallback(UCVarValue value, ECVarType type) override; }; class FBoolCVarRef diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp index a29a6b711..cae27a4da 100644 --- a/src/common/scripting/interface/vmnatives.cpp +++ b/src/common/scripting/interface/vmnatives.cpp @@ -852,7 +852,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetInt) PARAM_INT(val); UCVarValue v; v.Int = val; - self->SetGenericRep(v, CVAR_Int); + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_Int); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_Int); + } + return 0; } @@ -870,7 +885,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetFloat) PARAM_FLOAT(val); UCVarValue v; v.Float = (float)val; - self->SetGenericRep(v, CVAR_Float); + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_Float); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_Float); + } + return 0; } @@ -889,7 +919,22 @@ DEFINE_ACTION_FUNCTION(_CVar, SetString) PARAM_STRING(val); UCVarValue v; v.String = val.GetChars(); - self->SetGenericRep(v, CVAR_String); + + if(self->GetFlags() & CVAR_ZS_CUSTOM_CLONE) + { + auto realCVar = (FBaseCVar*)(self->GetExtraDataPointer()); + assert(realCVar->GetFlags() & CVAR_ZS_CUSTOM); + + v = realCVar->GenericZSCVarCallback(v, CVAR_String); + self->SetGenericRep(v, realCVar->GetRealType()); + + if(realCVar->GetRealType() == CVAR_String) delete[] v.String; + } + else + { + self->SetGenericRep(v, CVAR_String); + } + return 0; } diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index e2876da9a..084ea4541 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -458,8 +458,17 @@ void userinfo_t::Reset() case NAME_PlayerClass: type = CVAR_Int; break; default: type = cvar->GetRealType(); break; } - newcvar = C_CreateCVar(NULL, type, cvar->GetFlags() & CVAR_MOD); + + int flags = cvar->GetFlags(); + + newcvar = C_CreateCVar(NULL, type, (flags & CVAR_MOD) | ((flags & CVAR_ZS_CUSTOM) << 1) ); newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String); + + if(flags & CVAR_ZS_CUSTOM) + { + newcvar->SetExtraDataPointer(cvar); // store backing cvar + } + Insert(cvarname, newcvar); } }