Convars
SwiftlyS2's convar system covers creating convars, finding existing ones, replicating values to clients, and querying client-side values.
Access it through Core.ConVar (APIISwiftlyCore.ConVar, type APIIConVarService).
Supported Generic Types
The generic parameter T used by APIIConVar`1, Create<T>, CreateOrFind<T>, and Find<T> supports:
bool, short, ushort, int, uint, long, ulong, float, double, Color, QAngle, Vector, Vector2D, Vector4D, string
Creating Convars
APIIConVarService.Create(name, helpMessage, defaultValue, flags = ConvarFlags.NONE), plus a where T : unmanaged overload taking minValue, maxValue before flags for
numeric/struct types like Vector.
APIIConVarService.CreateOrFind has the same two
overloads but returns the existing convar instead of throwing if name is
already registered - prefer it unless you specifically want the
duplicate-registration error.
IConVar<bool> enabled = Core.ConVar.Create("sw_plugin_enabled", "Enable or disable the plugin.", true);
IConVar<int> maxBots = Core.ConVar.Create("sw_plugin_max_bots", "Maximum amount of bots allowed.", 6, 0, 20);
IConVar<bool> feature = Core.ConVar.CreateOrFind("sw_plugin_feature", "Enable feature X.", true);Finding Existing Convars
Typed Find
Looking up an existing engine convar like ConVarsv_cheats:
IConVar<bool>? cheats = Core.ConVar.Find<bool>("sv_cheats");
if (cheats == null)
{
Console.WriteLine("sv_cheats was not found.");
}Find as String
Use APIIConVarService.FindAsString for string-level access, or when the convar's type is unknown.
IConVar? hostname = Core.ConVar.FindAsString("hostname");
if (hostname != null)
{
Console.WriteLine($"hostname = {hostname.ValueAsString}");
}Working with APIIConVar`1
Setting Value queues the change and auto-replicates if the convar is replicated; use APIIConVar`1.SetInternal instead for an immediate, non-replicated change (e.g. inside a hook for that same convar, where the queued set won't apply in time). APIIConVar`1.ReplicateToClient/APIIConVar`1.QueryClient push/pull a single client's value, and TryGetMinValue/TryGetMaxValue/TryGetDefaultValue read the bounds safely.
enabled.Value = false;
enabled.SetInternal(true);
enabled.ReplicateToClient(0, true);
enabled.QueryClient(0, valueAsString => Console.WriteLine($"Client replied with: {valueAsString}"));
if (maxBots.TryGetMinValue(out var min)) Console.WriteLine($"Min value: {min}");
if (maxBots.TryGetMaxValue(out var max)) Console.WriteLine($"Max value: {max}");
if (maxBots.TryGetDefaultValue(out var def)) Console.WriteLine($"Default value: {def}");Working with APIIConVar (String API)
Without a generic type, use the non-generic members: ValueAsString, SetInternalAsString, ReplicateToClientAsString, TryGetMinValueAsString, TryGetMaxValueAsString, TryGetDefaultValueAsString - see APIIConVar for the full list.
IConVar? anyConvar = Core.ConVar.FindAsString("sv_cheats");
if (anyConvar != null)
{
anyConvar.SetInternalAsString("1");
anyConvar.ReplicateToClientAsString(0, "1");
}Service-Level Replication
Replicate a value by name to a client, even for convars that don't exist on the server:
Core.ConVar.ReplicateToClient(0, "cl_showfps", "1");
Core.ConVar.ReplicateToAll("cl_teamid_overhead_mode", "2");Tracking ConVar Changes
public override void Load(bool hotReload)
{
Core.Event.OnConVarValueChanged += OnConVarValueChanged;
}
private void OnConVarValueChanged(IOnConVarValueChanged @event) // see <ApiRef name="IOnConVarValueChanged" />
{
if (!@event.ConVarName.StartsWith("sw_"))
return;
Console.WriteLine($"ConVar '{@event.ConVarName}' changed by player #{@event.PlayerId}: '{@event.OldValue}' -> '{@event.NewValue}'");
}Useful for audit logging, debugging, and reacting to config changes without polling Value on a hot path.
Unhook in Unload() (Core.Event.OnConVarValueChanged -= OnConVarValueChanged;) to avoid leaking a delegate across hot reloads.
Reference
APIConvarFlags is a [Flags] enum : ulong mirroring the engine's
FCVAR_* flags (NONE, ARCHIVE, NOTIFY, REPLICATED, CHEAT, HIDDEN,
PROTECTED, and more).