This commit is contained in:
Major Cooke 2023-01-21 11:08:05 -06:00
parent 3039e3e7c8
commit 0a2fc5651c
4 changed files with 382 additions and 3 deletions

View file

@ -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<void (*)(FBaseCVar &)>(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<void (*)(FBaseCVar &)>(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<void (*)(FBaseCVar &)>(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<void (*)(FBaseCVar &)>(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<void (*)(FBaseCVar &)>(CallCVarCallback));
}
void FZSColorCVar::MarkZSCVar()
{
GC::Mark(customCVarHandler);
}

View file

@ -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<DObject*> 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<DObject*> 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<DObject*> 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<DObject*> 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<DObject*> 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;

View file

@ -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<FString>& allwads, TArr
R_ParseTrnslate();
PClassActor::StaticInit ();
FBaseCVar::InitZSCallbacks ();
Job_Init();
// [GRB] Initialize player class list

View file

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