Convars
SwiftlyS2 provides a complete convar system that allows you to create convars, find existing game convars, replicate values to clients, and query client-side values.
Accessing Convar Service
The convar service is available through Core.ConVar.
public override void Load(bool hotReload)
{
var convarService = Core.ConVar;
}Supported Generic Types
The generic parameter T used by IConVar<T>, Create<T>, CreateOrFind<T>, and Find<T> supports these types:
boolshortushortintuintlongulongfloatdoubleColorQAngleVectorVector2DVector4Dstring
Creating Convars
Convars can be created with a default value, or with min/max limits for unmanaged numeric-like types.
Basic Create
IConVar<bool> enabled = Core.ConVar.Create(
"sw_plugin_enabled",
"Enable or disable the plugin.",
true,
ConvarFlags.NONE
);The Create function signature is:
IConVar<T> Create<T>(string name, string helpMessage, T defaultValue, ConvarFlags flags = ConvarFlags.NONE)Create with Min/Max
IConVar<int> maxBots = Core.ConVar.Create(
"sw_plugin_max_bots",
"Maximum amount of bots allowed.",
6,
0,
20,
ConvarFlags.NONE
);The min/max overload signature is:
IConVar<T> Create<T>(string name, string helpMessage, T defaultValue, T? minValue, T? maxValue, ConvarFlags flags = ConvarFlags.NONE)
where T : unmanagedCreate Or Find
If you want to avoid duplicate registration errors, use CreateOrFind.
IConVar<bool> feature = Core.ConVar.CreateOrFind(
"sw_plugin_feature",
"Enable feature X.",
true,
ConvarFlags.NONE
);It also supports the min/max overload:
IConVar<T> CreateOrFind<T>(string name, string helpMessage, T defaultValue, T? minValue, T? maxValue, ConvarFlags flags = ConvarFlags.NONE)
where T : unmanagedFinding Existing Convars
Typed Find
Use Find<T> when you know the convar type.
IConVar<bool>? cheats = Core.ConVar.Find<bool>("sv_cheats");
if (cheats == null)
{
Console.WriteLine("sv_cheats was not found.");
}Find as String
Use FindAsString when you only need string-level access.
IConVar? hostname = Core.ConVar.FindAsString("hostname");
if (hostname != null)
{
Console.WriteLine($"hostname = {hostname.ValueAsString}");
}Working with IConVar<T>
Setting and Getting Values
enabled.Value = false;
Console.WriteLine(enabled.Value);Setting Value Internally
Setting Value goes through the normal set queue. In special cases where you need an immediate internal change, use SetInternal.
enabled.SetInternal(true);Replicate to a Specific Client
enabled.ReplicateToClient(0, true);Query Value from a Client
enabled.QueryClient(0, valueAsString =>
{
Console.WriteLine($"Client replied with: {valueAsString}");
});Reading Min/Max/Default Safely
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 defaultValue))
{
Console.WriteLine($"Default value: {defaultValue}");
}Working with IConVar (String API)
When you do not have or do not want a generic type, use IConVar members like ValueAsString and SetInternalAsString.
IConVar? anyConvar = Core.ConVar.FindAsString("sv_cheats");
if (anyConvar != null)
{
anyConvar.SetInternalAsString("1");
anyConvar.ReplicateToClientAsString(0, "1");
}Service-Level Replication
You can replicate values even for convars that do not exist on the server by using service-level replication.
Core.ConVar.ReplicateToClient(0, "cl_showfps", "1");
Core.ConVar.ReplicateToAll("cl_teamid_overhead_mode", "2");Tracking ConVar Changes
You can track convar changes by listening to Core.Event.OnConVarValueChanged.
public override void Load(bool hotReload)
{
Core.Event.OnConVarValueChanged += OnConVarValueChanged;
}
public override void Unload(bool hotReload)
{
Core.Event.OnConVarValueChanged -= OnConVarValueChanged;
}
private void OnConVarValueChanged(IOnConVarValueChanged @event)
{
if (!@event.ConVarName.StartsWith("sw_"))
{
return;
}
Console.WriteLine(
$"ConVar '{@event.ConVarName}' changed by player #{@event.PlayerId}: '{@event.OldValue}' -> '{@event.NewValue}'"
);
}This is useful for audit logging, debugging, and reacting to runtime configuration changes.
This method is very useful when you want to use convar values in hot paths.
Complete Example
[PluginMetadata(Id = "MyPlugin", Version = "1.0.0", Name = "My Own Plugin", Author = "myself", Description = "i created this plugin")]
public partial class MyPlugin : BasePlugin
{
private IConVar<bool>? _enabled;
private IConVar<int>? _maxBots;
public override void Load(bool hotReload)
{
_enabled = Core.ConVar.CreateOrFind(
"sw_plugin_enabled",
"Enable or disable this plugin.",
true,
ConvarFlags.NONE
);
_maxBots = Core.ConVar.CreateOrFind(
"sw_plugin_max_bots",
"Maximum amount of bots.",
6,
0,
20,
ConvarFlags.NONE
);
_enabled.Value = true;
_maxBots.SetInternal(10);
_enabled.QueryClient(0, value =>
{
Console.WriteLine($"Client #0 sees sw_plugin_enabled={value}");
});
}
}Reference
See ConvarFlags.
See IConVar.
See IConVar<T>.
See IConVarService.