diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 7edf126ab..3f7d900cd 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -60,6 +60,7 @@ struct FLatchedValue FBaseCVar *Variable; UCVarValue Value; ECVarType Type; + bool UnsafeContext; }; static TArray LatchedValues; @@ -71,11 +72,6 @@ FBaseCVar *CVars = NULL; int cvar_defflags; -FBaseCVar::FBaseCVar (const FBaseCVar &var) -{ - I_FatalError ("Use of cvar copy constructor"); -} - FBaseCVar::FBaseCVar (const char *var_name, uint32_t flags, void (*callback)(FBaseCVar &)) { FBaseCVar *var; @@ -148,7 +144,12 @@ void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend) if (m_UseCallback) Callback (); - Flags &= ~CVAR_ISDEFAULT; + if ((Flags & CVAR_ARCHIVE) && !(Flags & CVAR_UNSAFECONTEXT)) + { + SafeValue = GetGenericRep(CVAR_String).String; + } + + Flags &= ~(CVAR_ISDEFAULT | CVAR_UNSAFECONTEXT); } void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) @@ -167,13 +168,17 @@ void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) latch.Value = value; else latch.Value.String = copystring(value.String); + latch.UnsafeContext = !!(Flags & CVAR_UNSAFECONTEXT); LatchedValues.Push (latch); + + Flags &= ~CVAR_UNSAFECONTEXT; } else if ((Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) { if (netgame && !players[consoleplayer].settings_controller) { Printf ("Only setting controllers can change %s\n", Name); + Flags &= ~CVAR_UNSAFECONTEXT; return; } D_SendServerInfoChange (this, value, type); @@ -1134,6 +1139,14 @@ DEFINE_ACTION_FUNCTION(_CVar, ResetToDefault) return 0; } +void FBaseCVar::MarkUnsafe() +{ + if (!(Flags & CVAR_MOD) && UnsafeExecutionContext) + { + Flags |= CVAR_UNSAFECONTEXT; + } +} + // // Flag cvar implementation // @@ -1644,6 +1657,8 @@ void UnlatchCVars (void) { uint32_t oldflags = var.Variable->Flags; var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO); + if (var.UnsafeContext) + var.Variable->Flags |= CVAR_UNSAFECONTEXT; var.Variable->SetGenericRep (var.Value, var.Type); if (var.Type == CVAR_String) delete[] var.Value.String; @@ -1697,9 +1712,7 @@ void C_ArchiveCVars (FConfigFile *f, uint32_t filter) (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) == filter) { - UCVarValue val; - val = cvar->GetGenericRep (CVAR_String); - f->SetValueForKey (cvar->GetName (), val.String); + f->SetValueForKey(cvar->GetName(), cvar->SafeValue); } cvar = cvar->m_Next; } @@ -1707,16 +1720,6 @@ void C_ArchiveCVars (FConfigFile *f, uint32_t filter) EXTERN_CVAR(Bool, sv_cheats); -static bool IsUnsafe(const FBaseCVar *const var) -{ - const bool unsafe = UnsafeExecutionContext && !(var->GetFlags() & CVAR_MOD); - if (unsafe) - { - Printf(TEXTCOLOR_RED "Cannot set console variable" TEXTCOLOR_GOLD " %s " TEXTCOLOR_RED "from unsafe command\n", var->GetName()); - } - return unsafe; -} - void FBaseCVar::CmdSet (const char *newval) { if ((GetFlags() & CVAR_CHEAT) && !sv_cheats) @@ -1724,10 +1727,8 @@ void FBaseCVar::CmdSet (const char *newval) Printf("sv_cheats must be true to set this console variable.\n"); return; } - else if (IsUnsafe(this)) - { - return; - } + + MarkUnsafe(); UCVarValue val; @@ -1814,10 +1815,7 @@ CCMD (toggle) { if ( (var = FindCVar (argv[1], &prev)) ) { - if (IsUnsafe(var)) - { - return; - } + var->MarkUnsafe(); val = var->GetGenericRep (CVAR_Bool); val.Bool = !val.Bool; diff --git a/src/c_cvars.h b/src/c_cvars.h index 02e9d67a2..11166098b 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -64,6 +64,7 @@ enum CVAR_MOD = 8192, // cvar was defined by a mod CVAR_IGNORE = 16384,// do not send cvar across the network/inaccesible from ACS (dummy mod cvar) CVAR_CHEAT = 32768,// can be set only when sv_cheats is enabled + CVAR_UNSAFECONTEXT = 65536,// cvar value came from unsafe context }; union UCVarValue @@ -110,6 +111,7 @@ public: void SetGenericRep (UCVarValue value, ECVarType type); void ResetToDefault (); void SetArchiveBit () { Flags |= CVAR_ARCHIVE; } + void MarkUnsafe(); virtual ECVarType GetRealType () const = 0; @@ -132,7 +134,6 @@ public: static void ListVars (const char *filter, bool plain); protected: - FBaseCVar () {} virtual void DoSet (UCVarValue value, ECVarType type) = 0; static bool ToBool (UCVarValue value, ECVarType type); @@ -147,10 +148,11 @@ protected: static UCVarValue FromGUID (const GUID &value, ECVarType type); char *Name; + FString SafeValue; uint32_t Flags; private: - FBaseCVar (const FBaseCVar &var); + FBaseCVar (const FBaseCVar &var) = delete; FBaseCVar (const char *name, uint32_t flags); void (*m_Callback)(FBaseCVar &);