Let custom CVar handlers to be called on cloned cvars

This commit is contained in:
Ricardo Luís Vaz Silva 2023-01-29 18:50:44 -03:00 committed by Rachael Alexanderson
parent 82b7e93d26
commit b50d7f4db5
4 changed files with 184 additions and 31 deletions

View file

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

View file

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

View file

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

View file

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