From 0a2fc5651c4fe90207db2b265c56ff4c5788f161 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 21 Jan 2023 11:08:05 -0600 Subject: [PATCH] Merged https://github.com/ZDoom/gzdoom/pull/1878 (ZScript Custom Cvars) --- src/common/console/c_cvars.cpp | 272 ++++++++++++++++++++++++++- src/common/console/c_cvars.h | 74 ++++++++ src/d_main.cpp | 14 +- wadsrc/static/zscript/engine/base.zs | 25 +++ 4 files changed, 382 insertions(+), 3 deletions(-) diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index d89bb3da3..08db26505 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -45,6 +45,14 @@ #include "palutil.h" #include "i_interface.h" +#include "dobject.h" +#include "dobjtype.h" +#include "dobjgc.h" + +#include "vm.h" + +#include "doomstat.h" + struct FLatchedValue { @@ -215,13 +223,11 @@ FBaseCVar::~FBaseCVar () void FBaseCVar::SetCallback(void (*callback)(FBaseCVar&)) { m_Callback = callback; - m_UseCallback = true; } void FBaseCVar::ClearCallback() { m_Callback = nullptr; - m_UseCallback = false; } void FBaseCVar::SetExtraDataPointer(void *pointer) @@ -603,6 +609,34 @@ void FBaseCVar::EnableCallbacks () } } +void FBaseCVar::InitZSCallbacks () +{ + CVarMap::Iterator it(cvarMap); + CVarMap::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if (cvar->Flags & CVAR_ZS_CUSTOM) + { + cvar->InstantiateZSCVar(); + } + } + GC::AddMarkerFunc(FBaseCVar::MarkZSCallbacks); +} + +void FBaseCVar::MarkZSCallbacks () { + CVarMap::Iterator it(cvarMap); + CVarMap::Pair *pair; + while (it.NextPair(pair)) + { + auto cvar = pair->Value; + if (cvar->Flags & CVAR_ZS_CUSTOM) + { + cvar->MarkZSCVar(); + } + } +} + void FBaseCVar::DisableCallbacks () { m_UseCallback = false; @@ -1432,6 +1466,21 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags } } +FBaseCVar * C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className) +{ + assert(FindCVar(var_name, NULL) == NULL); + flags |= CVAR_AUTO | CVAR_ZS_CUSTOM; + switch (var_type) + { + case CVAR_Bool: return new FZSBoolCVar(var_name, 0, flags, className); + case CVAR_Int: return new FZSIntCVar(var_name, 0, flags, className); + case CVAR_Float: return new FZSFloatCVar(var_name, 0, flags, className); + case CVAR_String: return new FZSStringCVar(var_name, NULL, flags, className); + case CVAR_Color: return new FZSColorCVar(var_name, 0, flags, className); + default: return NULL; + } +} + void UnlatchCVars (void) { for (const FLatchedValue& var : LatchedValues) @@ -1737,3 +1786,222 @@ CCMD(listcvarswithoutdescription) { C_ListCVarsWithoutDescription(); } + + +//=========================================================================== +// +// FZSIntCVar +// +//=========================================================================== + + +FZSIntCVar::FZSIntCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr) + : FIntCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSIntCVar::CallCVarCallback(FZSIntCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomIntCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomIntCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + VMReturn ret(&self.Value); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSIntCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomIntCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s",cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomIntCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSIntCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + + +//=========================================================================== +// +// FZSFloatCVar +// +//=========================================================================== + + +FZSFloatCVar::FZSFloatCVar(const char *name, float def, uint32_t flags, FName _className, const char* descr) + : FFloatCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSFloatCVar::CallCVarCallback(FZSFloatCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomFloatCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomFloatCVar", ModifyValue) + { + 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); + } +} + +void FZSFloatCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomFloatCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomFloatCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSFloatCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + + +//=========================================================================== +// +// FZSStringCVar +// +//=========================================================================== + + +FZSStringCVar::FZSStringCVar(const char *name, const char * def, uint32_t flags, FName _className, const char* descr) + : FStringCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSStringCVar::CallCVarCallback(FZSStringCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomStringCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomStringCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , &self.mValue }; + VMReturn ret(&self.mValue); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSStringCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomStringCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomStringCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSStringCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + + +//=========================================================================== +// +// FZSBoolCVar +// +//=========================================================================== + + +FZSBoolCVar::FZSBoolCVar(const char *name, bool def, uint32_t flags, FName _className, const char* descr) + : FBoolCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSBoolCVar::CallCVarCallback(FZSBoolCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomBoolCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomBoolCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + int v; + VMReturn ret(&v); + VMCall(func, param, 3, &ret, 1); + self.Value = v; + } +} + +void FZSBoolCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomBoolCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomBoolCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSBoolCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} + + +//=========================================================================== +// +// FZSIntCVar +// +//=========================================================================== + + +FZSColorCVar::FZSColorCVar(const char *name, int def, uint32_t flags, FName _className, const char* descr) + : FColorCVar(name,def,flags,nullptr,descr) , cvarName(name) , className(_className) +{ customCVarHandler = nullptr; } + +void FZSColorCVar::CallCVarCallback(FZSColorCVar &self) +{ + if (!self.customCVarHandler) { + I_Error("Handler for CustomColorCVar '%s' of class '%s' was Destroyed", self.cvarName.GetChars(), self.className.GetChars()); + } + IFVIRTUALPTRNAME(self.customCVarHandler, "CustomColorCVar", ModifyValue) + { + VMValue param[] = { self.customCVarHandler.Get() , self.cvarName.GetIndex() , self.Value }; + VMReturn ret(&self.Value); + VMCall(func, param, 3, &ret, 1); + } +} + +void FZSColorCVar::InstantiateZSCVar() +{ + static PClass * baseClass = PClass::FindClass("CustomColorCVar"); + assert(baseClass); + PClass * classPtr = PClass::FindClass(className); + if (!classPtr || !classPtr->IsDescendantOf(baseClass)) + { + I_Error("Instantiating CVar '%s': Class '%s' %s", cvarName.GetChars(), className.GetChars(), (classPtr ? "is not a descendant of CustomColorCVar" : "does not exist")); + } + customCVarHandler = classPtr->CreateNew(); + SetCallback(reinterpret_cast(CallCVarCallback)); +} + +void FZSColorCVar::MarkZSCVar() +{ + GC::Mark(customCVarHandler); +} \ No newline at end of file diff --git a/src/common/console/c_cvars.h b/src/common/console/c_cvars.h index d60771d2d..d4cd7241a 100644 --- a/src/common/console/c_cvars.h +++ b/src/common/console/c_cvars.h @@ -37,6 +37,7 @@ #include "tarray.h" #include "autosegs.h" #include "name.h" +#include "dobjgc.h" class FSerializer; // this needs to go away. /* @@ -72,6 +73,7 @@ enum 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 }; enum ECVarType @@ -188,6 +190,8 @@ public: static void EnableNoSet (); // enable the honoring of CVAR_NOSET static void EnableCallbacks (); static void DisableCallbacks (); + static void InitZSCallbacks (); + static void MarkZSCallbacks (); static void ResetColors (); // recalc color cvars' indices after screen change static void ListVars (const char *filter, bool plain); @@ -209,6 +213,10 @@ public: protected: virtual void DoSet (UCVarValue value, ECVarType type) = 0; + virtual void InstantiateZSCVar() + {} + virtual void MarkZSCVar() + {} static bool ToBool (UCVarValue value, ECVarType type); static int ToInt (UCVarValue value, ECVarType type); @@ -278,6 +286,7 @@ FBaseCVar *GetCVar(int playernum, const char *cvarname); // Create a new cvar with the specified name and type FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, uint32_t flags); +FBaseCVar *C_CreateZSCustomCVar(const char *var_name, ECVarType var_type, uint32_t flags, FName className); // Called from G_InitNew() void UnlatchCVars (void); @@ -482,6 +491,71 @@ protected: int BitNum; }; +class FZSIntCVar : public FIntCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSIntCVar &); +public: + FZSIntCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; +}; + +class FZSFloatCVar : public FFloatCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSFloatCVar &); +public: + FZSFloatCVar(const char *name, float def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; +}; + +class FZSStringCVar : public FStringCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSStringCVar &); +public: + FZSStringCVar(const char *name, const char * def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; +}; + +class FZSBoolCVar : public FBoolCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSBoolCVar &); +public: + FZSBoolCVar(const char *name, bool def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; +}; + +class FZSColorCVar : public FColorCVar +{ + TObjPtr customCVarHandler; + FName cvarName; + FName className; + + static void CallCVarCallback(FZSColorCVar &); +public: + FZSColorCVar(const char *name, int def, uint32_t flags, FName className, const char* descr = nullptr); + void InstantiateZSCVar() override; + void MarkZSCVar() override; +}; + class FBoolCVarRef { FBoolCVar* ref; diff --git a/src/d_main.cpp b/src/d_main.cpp index 89919af0f..5104b1aa0 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1593,6 +1593,8 @@ void ParseCVarInfo() ECVarType cvartype = CVAR_Dummy; int cvarflags = CVAR_MOD|CVAR_ARCHIVE; FBaseCVar *cvar; + bool customCVar = false; + FName customCVarClassName; // Check for flag tokens. while (sc.TokenType == TK_Identifier) @@ -1621,6 +1623,14 @@ void ParseCVarInfo() { cvarflags |= CVAR_CONFIG_ONLY; } + else if (stricmp(sc.String, "handlerClass") == 0) + { + sc.MustGetStringName("("); + sc.MustGetString(); + customCVar = true; + customCVarClassName = sc.String; + sc.MustGetStringName(")"); + } else { sc.ScriptError("Unknown cvar attribute '%s'", sc.String); @@ -1703,7 +1713,7 @@ void ParseCVarInfo() } } // Now create the cvar. - cvar = C_CreateCVar(cvarname, cvartype, cvarflags); + cvar = customCVar ? C_CreateZSCustomCVar(cvarname, cvartype, cvarflags, customCVarClassName) : C_CreateCVar(cvarname, cvartype, cvarflags); if (cvardefault != NULL) { UCVarValue val; @@ -3261,6 +3271,8 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr R_ParseTrnslate(); PClassActor::StaticInit (); + FBaseCVar::InitZSCallbacks (); + Job_Init(); // [GRB] Initialize player class list diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index ea6440bbc..61376f228 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -688,6 +688,31 @@ struct CVar native native int ResetToDefault(); } +class CustomIntCVar abstract +{ + abstract int ModifyValue(Name CVarName, int val); +} + +class CustomFloatCVar abstract +{ + abstract double ModifyValue(Name CVarName, double val); +} + +class CustomStringCVar abstract +{ + abstract String ModifyValue(Name CVarName, String val); +} + +class CustomBoolCVar abstract +{ + abstract bool ModifyValue(Name CVarName, bool val); +} + +class CustomColorCVar abstract +{ + abstract Color ModifyValue(Name CVarName, Color val); +} + struct GIFont version("2.4") { Name fontname;