< Summary

Information
Class: Trailblazer.TrailblazerWorldContextSettings
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Runtime/TrailblazerWorldContextSettings.cs
Line coverage
100%
Covered lines: 180
Uncovered lines: 0
Coverable lines: 180
Total lines: 272
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%44100%
CreateDefault()100%11100%
ThrowIfNonPositive(...)100%11100%
ThrowIfNonPositive(...)100%11100%
ThrowIfNegative(...)100%11100%
ThrowIfNegative(...)100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Runtime/TrailblazerWorldContextSettings.cs

#LineLine coverage
 1//=======================================================================
 2// TrailblazerWorldContextSettings.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using Trailblazer.Pathing;
 10
 11namespace Trailblazer;
 12
 13/// <summary>
 14/// Freezes the finite graph, lifecycle, and query-workspace ceilings for one world context.
 15/// </summary>
 16public sealed class TrailblazerWorldContextSettings
 17{
 18    internal const int MinimumIngressBytes = 256;
 119    internal static readonly long MinimumActiveSnapshotBytes = checked(
 120        NavigationWorldGraph.Empty.RetainedBytes * 3L);
 121    internal static readonly int MinimumPersistentGraphPages = checked(
 122        NavigationWorldGraph.Empty.PersistentPageCount * 3);
 23
 24    /// <summary>Gets the recommended finite settings used when a host does not provide custom limits.</summary>
 25    public static TrailblazerWorldContextSettings Default { get; } = CreateDefault();
 26
 27    /// <summary>Creates an immutable explicit set of context-owned runtime ceilings.</summary>
 35328    public TrailblazerWorldContextSettings(
 35329        NavigationOperationLimits operationLimits,
 35330        MaintenanceWorkBudget maintenanceBudget,
 35331        GuideSampleWorkBudget guideSampleBudget,
 35332        Fixed64 movementGroupPadding,
 35333        int maxIngressEntries,
 35334        long maxIngressBytes,
 35335        int maxActiveSnapshots,
 35336        long maxActiveSnapshotBytes,
 35337        int maxRetiredSnapshots,
 35338        long maxRetiredSnapshotBytes,
 35339        int maxPersistentGraphPages,
 35340        int maxDynamicCellSlotsPerMap,
 35341        int maxDynamicCellSlots,
 35342        int navigationAreaCount,
 35343        int maxAreaPolicies,
 35344        int maxAreaRulesPerPolicy,
 35345        int maxAreaRules,
 35346        int maxConcurrentSnapshotLeases,
 35347        NavigationQueryLimits queryLimits)
 48    {
 35349        SwiftThrowHelper.ThrowIfArgument(
 35350            operationLimits.MaxPendingOperations <= 0,
 35351            nameof(operationLimits),
 35352            "Operation limits must be explicitly initialized.");
 35253        SwiftThrowHelper.ThrowIfArgument(
 35254            maintenanceBudget.MaxConsumedEnvelopes <= 0,
 35255            nameof(maintenanceBudget),
 35256            "Maintenance work budget must be explicitly initialized.");
 35157        ThrowIfNonPositive(maxIngressEntries, nameof(maxIngressEntries));
 35058        ThrowIfNonPositive(maxIngressBytes, nameof(maxIngressBytes));
 34959        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 34960            maxIngressBytes < MinimumIngressBytes,
 34961            null,
 34962            nameof(maxIngressBytes));
 34863        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 34864            maxActiveSnapshots < 3,
 34865            maxActiveSnapshots,
 34866            nameof(maxActiveSnapshots),
 34867            "Snapshot capacity must reserve the current, fail-closed, and candidate roots.");
 34768        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 34769            maxActiveSnapshotBytes < MinimumActiveSnapshotBytes,
 34770            null,
 34771            nameof(maxActiveSnapshotBytes),
 34772            "Snapshot bytes must reserve the current, fail-closed, and candidate empty roots.");
 34573        ThrowIfNegative(maxRetiredSnapshots, nameof(maxRetiredSnapshots));
 34474        ThrowIfNegative(maxRetiredSnapshotBytes, nameof(maxRetiredSnapshotBytes));
 34375        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 34376            maxPersistentGraphPages < MinimumPersistentGraphPages,
 34377            maxPersistentGraphPages,
 34378            nameof(maxPersistentGraphPages),
 34379            "Persistent pages must reserve the current, fail-closed, and candidate empty roots.");
 34180        ThrowIfNegative(maxDynamicCellSlotsPerMap, nameof(maxDynamicCellSlotsPerMap));
 34081        ThrowIfNegative(maxDynamicCellSlots, nameof(maxDynamicCellSlots));
 33982        SwiftThrowHelper.ThrowIfArgument(
 33983            maxDynamicCellSlots < maxDynamicCellSlotsPerMap,
 33984            nameof(maxDynamicCellSlots),
 33985            "Context dynamic-cell capacity cannot be smaller than the per-map capacity.");
 33886        SwiftThrowHelper.ThrowIfArgument(
 33887            maxDynamicCellSlotsPerMap < operationLimits.MaxOverlayCellsPerMap,
 33888            nameof(maxDynamicCellSlotsPerMap),
 33889            "Per-map dynamic-cell capacity must cover every cell overlay admitted by the operation limits.");
 33790        SwiftThrowHelper.ThrowIfArgument(
 33791            maxDynamicCellSlots < operationLimits.MaxOverlayCells,
 33792            nameof(maxDynamicCellSlots),
 33793            "Context dynamic-cell capacity must cover every cell overlay admitted by the operation limits.");
 33694        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 33695            navigationAreaCount <= 0 || navigationAreaCount > ushort.MaxValue + 1,
 33696            navigationAreaCount,
 33697            nameof(navigationAreaCount));
 33598        ThrowIfNonPositive(maxAreaPolicies, nameof(maxAreaPolicies));
 33499        ThrowIfNonPositive(maxAreaRulesPerPolicy, nameof(maxAreaRulesPerPolicy));
 333100        ThrowIfNonPositive(maxAreaRules, nameof(maxAreaRules));
 332101        SwiftThrowHelper.ThrowIfArgument(
 332102            maxAreaRules < maxAreaRulesPerPolicy
 332103            || maxAreaRulesPerPolicy < navigationAreaCount,
 332104            nameof(maxAreaRules),
 332105            "Area-rule capacity must cover the configured context area layout.");
 331106        int maximumRetainedAreaPolicies = System.Math.Min(
 331107            maxAreaPolicies,
 331108            maxAreaRules / navigationAreaCount);
 331109        long minimumAreaPolicyWork = System.Math.Max(
 331110            navigationAreaCount,
 331111            2L * maximumRetainedAreaPolicies) + 1L;
 331112        SwiftThrowHelper.ThrowIfArgument(
 331113            maintenanceBudget.MaxDependencyEntries < minimumAreaPolicyWork,
 331114            nameof(maintenanceBudget),
 331115            "Dependency work must fit one exact area-policy publication.");
 329116        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 329117            movementGroupPadding < Fixed64.Zero,
 329118            null,
 329119            nameof(movementGroupPadding));
 328120        ThrowIfNonPositive(maxConcurrentSnapshotLeases, nameof(maxConcurrentSnapshotLeases));
 328121        SwiftThrowHelper.ThrowIfArgument(
 328122            queryLimits.MaxConcurrentNavigationQueries <= 0,
 328123            nameof(queryLimits),
 328124            "Query limits must be explicitly initialized.");
 327125        SwiftThrowHelper.ThrowIfArgument(
 327126            queryLimits.MaxConcurrentNavigationQueries > maxConcurrentSnapshotLeases,
 327127            nameof(queryLimits),
 327128            "Concurrent queries cannot exceed the context snapshot-lease ceiling.");
 129
 326130        OperationLimits = operationLimits;
 326131        MaintenanceBudget = maintenanceBudget;
 326132        GuideSampleBudget = guideSampleBudget;
 326133        MovementGroupPadding = movementGroupPadding;
 326134        MaxIngressEntries = maxIngressEntries;
 326135        MaxIngressBytes = maxIngressBytes;
 326136        MaxActiveSnapshots = maxActiveSnapshots;
 326137        MaxActiveSnapshotBytes = maxActiveSnapshotBytes;
 326138        MaxRetiredSnapshots = maxRetiredSnapshots;
 326139        MaxRetiredSnapshotBytes = maxRetiredSnapshotBytes;
 326140        MaxPersistentGraphPages = maxPersistentGraphPages;
 326141        MaxDynamicCellSlotsPerMap = maxDynamicCellSlotsPerMap;
 326142        MaxDynamicCellSlots = maxDynamicCellSlots;
 326143        NavigationAreaCount = navigationAreaCount;
 326144        MaxAreaPolicies = maxAreaPolicies;
 326145        MaxAreaRulesPerPolicy = maxAreaRulesPerPolicy;
 326146        MaxAreaRules = maxAreaRules;
 326147        MaxConcurrentSnapshotLeases = maxConcurrentSnapshotLeases;
 326148        QueryLimits = queryLimits;
 326149    }
 150
 151    /// <summary>Gets the map-operation, preparation, and semantic-overlay ceilings.</summary>
 152    public NavigationOperationLimits OperationLimits { get; }
 153
 154    /// <summary>Gets the deterministic work budget consumed at each maintenance boundary.</summary>
 155    public MaintenanceWorkBudget MaintenanceBudget { get; }
 156
 157    /// <summary>Gets the deterministic work budget consumed by one graph flow guide sample.</summary>
 158    public GuideSampleWorkBudget GuideSampleBudget { get; }
 159
 160    /// <summary>Gets the world-space padding added to the mean radius of one movement group.</summary>
 161    public Fixed64 MovementGroupPadding { get; }
 162
 163    /// <summary>Gets the maximum coalesced GridForge ingress entries.</summary>
 164    public int MaxIngressEntries { get; }
 165
 166    /// <summary>Gets the maximum retained GridForge ingress bytes.</summary>
 167    public long MaxIngressBytes { get; }
 168
 169    /// <summary>Gets the maximum current, fail-closed, and unpublished active snapshots.</summary>
 170    public int MaxActiveSnapshots { get; }
 171
 172    /// <summary>Gets the maximum bytes retained by active snapshots.</summary>
 173    public long MaxActiveSnapshotBytes { get; }
 174
 175    /// <summary>Gets the maximum leased snapshot generations retained after publication.</summary>
 176    public int MaxRetiredSnapshots { get; }
 177
 178    /// <summary>Gets the maximum bytes retained by leased retired snapshots.</summary>
 179    public long MaxRetiredSnapshotBytes { get; }
 180
 181    /// <summary>Gets the maximum persistent registry, semantic, physical, and index pages.</summary>
 182    public int MaxPersistentGraphPages { get; }
 183
 184    /// <summary>Gets the maximum non-reused dynamic cell slots retained by one map.</summary>
 185    public int MaxDynamicCellSlotsPerMap { get; }
 186
 187    /// <summary>Gets the maximum non-reused dynamic cell slots retained by the context.</summary>
 188    public int MaxDynamicCellSlots { get; }
 189
 190    /// <summary>Gets the exact contiguous context area layout spanning IDs zero through count minus one.</summary>
 191    public int NavigationAreaCount { get; }
 192
 193    /// <summary>Gets the maximum immutable navigation-area policies retained by the context.</summary>
 194    public int MaxAreaPolicies { get; }
 195
 196    /// <summary>Gets the maximum direct-indexed rules retained by one area policy.</summary>
 197    public int MaxAreaRulesPerPolicy { get; }
 198
 199    /// <summary>Gets the maximum direct-indexed area rules retained across the context.</summary>
 200    public int MaxAreaRules { get; }
 201
 202    /// <summary>Gets the maximum concurrently checked-out immutable graph snapshots.</summary>
 203    public int MaxConcurrentSnapshotLeases { get; }
 204
 205    /// <summary>Gets the context-owned navigation query admission and retention ceilings.</summary>
 206    public NavigationQueryLimits QueryLimits { get; }
 207
 1208    private static TrailblazerWorldContextSettings CreateDefault() => new(
 1209        new NavigationOperationLimits(
 1210            maxPendingOperations: 32,
 1211            maxPendingDescriptorBytes: 1_048_576,
 1212            maxPreparedMapBytes: 16_777_216,
 1213            maxBatchItems: 32,
 1214            maxBatchDescriptorBytes: 1_048_576,
 1215            maxBatchSortScratchBytes: 1_048_576,
 1216            maxCorridorCells: 64,
 1217            maxMaps: 16,
 1218            maxRetainedMapIdentities: 32,
 1219            maxOverlayCellsPerMap: 4_096,
 1220            maxOverlayConnectionsPerMap: 1_024,
 1221            maxOverlayTransitionsPerMap: 1_024,
 1222            maxOverlayCells: 16_384,
 1223            maxOverlayConnections: 4_096,
 1224            maxOverlayTransitions: 4_096,
 1225            maxTransitionRulesPerMap: 1_024,
 1226            maxTransitionRules: 4_096),
 1227        new MaintenanceWorkBudget(
 1228            maxConsumedEnvelopes: 4_096,
 1229            maxBaselineAddresses: 65_536,
 1230            maxOverlaySlots: 16_384,
 1231            maxComponentNodes: 65_536,
 1232            maxSeamCandidateProbes: 65_536,
 1233            maxExplicitEdges: 65_536,
 1234            maxDependencyEntries: 65_536,
 1235            maxSurfaceComponentEdges: 65_536),
 1236        new GuideSampleWorkBudget(
 1237            maxCurrentNodeLookupProbes: 128,
 1238            maxCursorLegScans: 128,
 1239            maxCursorRebases: 8,
 1240            maxPortalChecks: 32,
 1241            maxPrismChecks: 32,
 1242            maxTraceIntervals: 32,
 1243            maxLocalRecoveryAttempts: 1),
 1244        movementGroupPadding: Fixed64.Half,
 1245        maxIngressEntries: 16_384,
 1246        maxIngressBytes: 4_194_304,
 1247        maxActiveSnapshots: 3,
 1248        maxActiveSnapshotBytes: 66_379_544,
 1249        maxRetiredSnapshots: 8,
 1250        maxRetiredSnapshotBytes: 67_108_864,
 1251        maxPersistentGraphPages: 660_550,
 1252        maxDynamicCellSlotsPerMap: 4_096,
 1253        maxDynamicCellSlots: 16_384,
 1254        navigationAreaCount: 1,
 1255        maxAreaPolicies: 64,
 1256        maxAreaRulesPerPolicy: 4_096,
 1257        maxAreaRules: 65_536,
 1258        maxConcurrentSnapshotLeases: 8,
 1259        queryLimits: NavigationQueryLimits.Default);
 260
 261    private static void ThrowIfNonPositive(int value, string parameterName) =>
 1681262        SwiftThrowHelper.ThrowIfArgumentOutOfRange(value <= 0, value, parameterName);
 263
 264    private static void ThrowIfNonPositive(long value, string parameterName) =>
 350265        SwiftThrowHelper.ThrowIfArgumentOutOfRange(value <= 0, null, parameterName);
 266
 267    private static void ThrowIfNegative(int value, string parameterName) =>
 1026268        SwiftThrowHelper.ThrowIfArgumentOutOfRange(value < 0, value, parameterName);
 269
 270    private static void ThrowIfNegative(long value, string parameterName) =>
 344271        SwiftThrowHelper.ThrowIfArgumentOutOfRange(value < 0, null, parameterName);
 272}