UI/SpawnMenu/LimitsPage.razor

A Razor UI page for the spawn menu that displays server limit settings. It builds a list of editable properties from the LimitSystem's static convars and exposes them through a UISheet, only visible to the host.

ReflectionNetworking
@using Sandbox;
@using Sandbox.UI;
@inherits UtilityPage
@namespace Sandbox
@attribute [Icon( "🚧" )]
@attribute [Title( "#server.group.limits" )]
@attribute [Group( "#spawnmenu.utility.group.server" )]
@attribute [Order( 10 )]

<root class="page">
    <UISheet Target="@Settings" PropertyFilter="@UISheet.PropertiesAndButtons" />
</root>

@code
{
    // The limits are replicated server convars - only the host can change them.
    public override bool IsPageVisible() => Networking.IsHost;

    readonly List<SerializedProperty> Settings = BuildSettings();

    // One row per limit convar, written through the console system so the replicated value changes for everyone.
    static List<SerializedProperty> BuildSettings()
    {
        var limits = Game.TypeLibrary.GetType( typeof( LimitsSystem ) );

        return limits.Properties
            .Where( p => p.IsStatic && p.HasAttribute<ConVarAttribute>() )
            .OrderBy( p => p.GetCustomAttribute<OrderAttribute>()?.Value ?? 0 )
            .Select( p =>
            {
                var convar = p.GetCustomAttribute<ConVarAttribute>().Name;
                var phrase = $"#server.{convar["sandbox.".Length..]}";

                var attributes = new List<Attribute> { new PropertyAttribute(), new DescriptionAttribute( $"{phrase}.description" ), new StepAttribute( 1 ) };
                if ( p.GetCustomAttribute<RangeAttribute>() is { } range ) attributes.Add( range );

                // the name is what the row shows
                return Game.TypeLibrary.CreateProperty<int>( phrase, () => (int)p.GetValue( null ), v => ConsoleSystem.SetValue( convar, v ), attributes.ToArray() );
            } )
            .ToList();
    }
}