< Summary

Class:GDX.PlayerLoopSystemExtensions
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/PlayerLoopSystemExtensions.cs
Covered lines:94
Uncovered lines:77
Coverable lines:171
Total lines:369
Line coverage:54.9% (94 of 171)
Covered branches:0
Total branches:0
Covered methods:7
Total methods:10
Method coverage:70% (7 of 10)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
AddSubSystem(...)0%5.273036.84%
AddSubSystemToFirstSubSystemOfType(...)0%4.594066.67%
AddSubSystemToFirstSubSystemOfType(...)0%2.062075%
GenerateSystemTree(...)0%10100100%
RemoveSubSystemsOfType(...)0%9.157064.71%
RemoveSubSystemsOfTypeFromFirstSubSystemOfType(...)0%2.092071.43%
ReplaceFirstSubSystemOfType(...)0%6200%
ReplaceSubSystemsOfType(...)0%20400%
TryGetFirstSubSystemOfType(...)0%770100%
TryGetFirstSystemWithSubSystemOfType(...)0%56700%

File(s)

./Packages/com.dotbunny.gdx/GDX/PlayerLoopSystemExtensions.cs

#LineLine coverage
 1// Copyright (c) 2020-2023 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using GDX.Developer;
 7using UnityEngine.LowLevel;
 8
 9namespace GDX
 10{
 11    /// <summary>
 12    ///     <see cref="UnityEngine.LowLevel.PlayerLoopSystem" /> Based Extension Methods
 13    /// </summary>
 14    public static class PlayerLoopSystemExtensions
 15    {
 16        /// <summary>
 17        ///     Adds a child (sub) system to the provided <paramref name="parentSystem"/>.
 18        /// </summary>
 19        /// <param name="parentSystem">The parent system which a child (sub) system should be added too.</param>
 20        /// <param name="subSystem">The child (sub) system that is to be added to the parent.</param>
 21        public static void AddSubSystem(this ref PlayerLoopSystem parentSystem, ref PlayerLoopSystem subSystem)
 522        {
 523            if (parentSystem.subSystemList != null)
 024            {
 025                ref PlayerLoopSystem[] previousSubSystems = ref parentSystem.subSystemList;
 026                int subSystemCount = previousSubSystems.Length;
 027                parentSystem.subSystemList = new PlayerLoopSystem[subSystemCount + 1];
 028                for (int i = 0; i < subSystemCount; i++)
 029                {
 030                    parentSystem.subSystemList[i] = previousSubSystems[i];
 031                }
 032                parentSystem.subSystemList[subSystemCount + 1] = subSystem;
 033            }
 34            else
 535            {
 536                parentSystem.subSystemList = new PlayerLoopSystem[1];
 537                parentSystem.subSystemList[0] = subSystem;
 538            }
 539        }
 40
 41        /// <summary>
 42        ///     Adds a child (sub) system to the first found instance of a <paramref name="parentSystemType"/> system in
 43        ///     <paramref name="rootSystem"/>.
 44        /// </summary>
 45        /// <param name="rootSystem">The root system which the <paramref name="parentSystemType"/> will be searched recu
 46        /// <param name="parentSystemType">The system <see cref="Type"/> that will be searched for as the parent.</param
 47        /// <param name="subSystemType">The type assigned when creating the <see cref="PlayerLoopSystem"/> to be added.<
 48        /// <param name="subSystemUpdateFunction">The method to invoke when the system is updated.</param>
 49        /// <returns>true/false if the <paramref name="parentSystemType"/> was found, and therefore the add could occur.
 50        /// <example>
 51        /// <code>
 52        ///     PlayerLoopSystem systemRoot = PlayerLoop.GetCurrentPlayerLoop();
 53        ///     systemRoot.AddSubSystemToFirstSubSystemOfType(
 54        ///         typeof(Update.ScriptRunDelayedTasks),
 55        ///         typeof(TaskDirectorSystem), PlayerLoopTick);
 56        ///     PlayerLoop.SetPlayerLoop(systemRoot);
 57        /// </code>
 58        /// </example>
 59        public static bool AddSubSystemToFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 60            Type parentSystemType, Type subSystemType, PlayerLoopSystem.UpdateFunction subSystemUpdateFunction)
 461        {
 462            if (subSystemUpdateFunction == null || subSystemType == null)
 063            {
 064                return false;
 65            }
 66
 467            PlayerLoopSystem newSubSystem = new PlayerLoopSystem()
 68            {
 69                updateDelegate = subSystemUpdateFunction, type = subSystemType
 70            };
 71
 472            ref PlayerLoopSystem foundParent = ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foun
 473            if (!foundTargetSystem)
 074            {
 075                return false;
 76            }
 77
 478            AddSubSystem(ref foundParent, ref newSubSystem);
 479            return true;
 480        }
 81
 82
 83        /// <summary>
 84        ///     Adds a child (sub) system to the first found instance of a <paramref name="parentSystemType"/> system in
 85        ///     <paramref name="rootSystem"/>.
 86        /// </summary>
 87        /// <param name="rootSystem">The root system which the <paramref name="parentSystemType"/> will be searched recu
 88        /// <param name="parentSystemType">The system <see cref="Type"/> that will be searched for as the parent.</param
 89        /// <param name="subSystem">The child (sub) system that is to be added to the parent.</param>
 90        /// <returns>true/false if the <paramref name="parentSystemType"/> was found, and therefore the add could occur.
 91        public static bool AddSubSystemToFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem, Type parentSystemTyp
 192        {
 193            ref PlayerLoopSystem foundParent = ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foun
 194            if (!foundTargetSystem)
 095            {
 096                return false;
 97            }
 98
 199            AddSubSystem(ref foundParent, ref subSystem);
 1100            return true;
 1101        }
 102
 103        /// <summary>
 104        ///     Populates a <see cref="TextGenerator"/> with a tree-like structure that represents the
 105        ///     <see cref="PlayerLoopSystem"/> found under the <paramref name="rootSystem"/>.
 106        /// </summary>
 107        /// <param name="rootSystem">The root system which the tree should be crafted based off of.</param>
 108        /// <param name="generator">Optionally, provide a generator to be populated.</param>
 109        /// <returns>A <see cref="TextGenerator"/> populated with the system output.</returns>
 110        public static TextGenerator GenerateSystemTree(this ref PlayerLoopSystem rootSystem, TextGenerator generator = n
 663111        {
 112            // We abuse this for recursion
 663113            generator ??= new TextGenerator();
 114
 663115            if (rootSystem.type != null)
 658116            {
 658117                generator.AppendLine(rootSystem.type.Name);
 658118            }
 119            else
 5120            {
 5121                generator.AppendLine(generator.GetIndentLevel() == 0 ? "_RootSystem_" : "_NullSystem_");
 5122            }
 123
 663124            if (rootSystem.subSystemList == null || rootSystem.subSystemList.Length <= 0)
 615125            {
 615126                return generator;
 127            }
 128
 48129            int count = rootSystem.subSystemList.Length;
 48130            if (count > 0)
 48131            {
 48132                generator.PushIndent();
 48133            }
 1412134            for (int i = 0; i < count; i++)
 658135            {
 658136                GenerateSystemTree(ref rootSystem.subSystemList[i], generator);
 658137            }
 48138            if (count > 0)
 48139            {
 48140                generator.PopIndent();
 48141            }
 142
 48143            return generator;
 663144        }
 145
 146        /// <summary>
 147        ///     Removes all child (sub) systems of the specified <paramref name="subSystemType"/> from the provided
 148        ///     <paramref name="parentSystem"/>.
 149        /// </summary>
 150        /// <remarks>
 151        ///     This is NOT recursive, and will not effect the child (sub) systems of the child (sub) systems of the
 152        ///     <paramref name="parentSystem"/>
 153        /// </remarks>
 154        /// <param name="parentSystem">The parent system which the child (sub) systems should be removed from.</param>
 155        /// <param name="subSystemType">The system <see cref="Type"/> that will be removed.</param>
 156        /// <returns>true/false, if a remove was done.</returns>
 157        public static bool RemoveSubSystemsOfType(this ref PlayerLoopSystem parentSystem, Type subSystemType)
 5158        {
 5159            if (parentSystem.subSystemList == null)
 0160            {
 0161                return false;
 162            }
 163
 5164            ref PlayerLoopSystem[] previousSubSystems = ref parentSystem.subSystemList;
 5165            int subSystemCount = previousSubSystems.Length;
 166
 167            // We need to actually make sure there is a sub system of type to remove, we will use the search as a place
 168            // to also figure out if there is multiple options.
 5169            int foundCount = 0;
 20170            for (int i = 0; i < subSystemCount; i++)
 5171            {
 5172                if (previousSubSystems[i].type == subSystemType)
 5173                {
 5174                    foundCount++;
 5175                }
 5176            }
 177
 5178            if (foundCount == 0)
 0179            {
 0180                return false;
 181            }
 182
 5183            int newIndex = 0;
 5184            int newCount = subSystemCount - foundCount;
 5185            parentSystem.subSystemList = new PlayerLoopSystem[newCount];
 10186            for (int i = 0; i < newCount; i++)
 0187            {
 0188                if (previousSubSystems[i].type != subSystemType)
 0189                {
 0190                    parentSystem.subSystemList[newIndex] = previousSubSystems[i];
 0191                    newIndex++;
 0192                }
 0193            }
 194
 5195            return true;
 196
 5197        }
 198
 199        /// <summary>
 200        ///     Removes all the child (sub) systems of to the first found instance of a <paramref name="parentSystemType
 201        /// </summary>
 202        /// <param name="rootSystem">The root system which the <paramref name="parentSystemType"/> will be searched recu
 203        /// <param name="parentSystemType">The system <see cref="Type"/> that will be searched for as the parent.</param
 204        /// <param name="subSystemType">The child (sub) system <see cref="Type"/> that will be removed.</param>
 205        /// <returns>true/false, if a remove occured.</returns>
 206        public static bool RemoveSubSystemsOfTypeFromFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 207            Type parentSystemType, Type subSystemType)
 5208        {
 5209            ref PlayerLoopSystem foundParent = ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foun
 5210            if (!foundTargetSystem)
 0211            {
 0212                return false;
 213            }
 214
 5215            return RemoveSubSystemsOfType(ref foundParent, subSystemType);
 5216        }
 217
 218        /// <summary>
 219        ///     Replaces the first child (sub) system of the given <paramref name="rootSystem"/> of
 220        ///     <paramref name="subSystemType"/> with the provided <paramref name="updatedSystem"/>.
 221        /// </summary>
 222        /// <param name="rootSystem">The root system which the <paramref name="subSystemType"/> will be searched recursi
 223        /// <param name="subSystemType">The child (sub) system <see cref="Type"/> that will be replaced.</param>
 224        /// <param name="updatedSystem">The system to replace the found <paramref name="subSystemType"/> with.</param>
 225        /// <returns>true/false if the replace occured.</returns>
 226        public static bool ReplaceFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem, Type subSystemType,
 227            ref PlayerLoopSystem updatedSystem)
 0228        {
 0229            ref PlayerLoopSystem foundParent = ref rootSystem.TryGetFirstSystemWithSubSystemOfType(subSystemType, out bo
 0230            if (!foundTargetSystem)
 0231            {
 0232                return false;
 233            }
 0234            foundParent.subSystemList[foundIndex] = updatedSystem;
 0235            return true;
 0236        }
 237
 238        /// <summary>
 239        ///     Replaces all child (sub) systems of the specified <paramref name="subSystemType"/> from the provided
 240        ///     <paramref name="parentSystem"/>.
 241        /// </summary>
 242        /// <remarks>
 243        ///     This is NOT recursive, and will not effect the child (sub) systems of the child (sub) systems of the
 244        ///     <paramref name="parentSystem"/>
 245        /// </remarks>
 246        /// <param name="parentSystem">The parent system which the child (sub) systems should be replaced.</param>
 247        /// <param name="subSystemType">The system <see cref="Type"/> that will be replaced.</param>
 248        /// <param name="updatedSystem">The system to replace the found <paramref name="subSystemType"/> with.</param>
 249        /// <returns>true/false if any replacement occured.</returns>
 250        public static bool ReplaceSubSystemsOfType(this ref PlayerLoopSystem parentSystem, Type subSystemType,
 251            ref PlayerLoopSystem updatedSystem)
 0252        {
 0253            if (parentSystem.subSystemList == null)
 0254            {
 0255                return false;
 256            }
 257
 0258            int count = parentSystem.subSystemList.Length;
 0259            bool replaced = false;
 0260            for (int i = 0; i < count; i++)
 0261            {
 0262                if (parentSystem.subSystemList[i].type != subSystemType)
 0263                {
 0264                    continue;
 265                }
 266
 0267                parentSystem.subSystemList[i] = updatedSystem;
 0268                replaced = true;
 0269            }
 0270            return replaced;
 0271        }
 272
 273        /// <summary>
 274        ///     Searches the provided <paramref name="rootSystem"/> child (sub) systems for the first instance of a
 275        ///     <paramref name="subSystemType"/> system.
 276        /// </summary>
 277        /// <param name="rootSystem">
 278        ///     The root system which the <paramref name="subSystemType"/> will be searched recursively for.
 279        /// </param>
 280        /// <param name="subSystemType">The child (sub) system <see cref="Type"/> that will be searched for recursively.
 281        /// <param name="foundSubSystem">Was an appropriate system found?</param>
 282        /// <returns>
 283        ///     The found system, or the root system. Check <paramref name="foundSubSystem"/> to determine if the system
 284        ///     was actually found. This pattern is used to preserve the reference.
 285        /// </returns>
 286        public static ref PlayerLoopSystem TryGetFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem, Type subSyst
 70287        {
 70288            if (rootSystem.subSystemList != null)
 70289            {
 70290                int subCount = rootSystem.subSystemList.Length;
 1504291                for (int i = 0; i < subCount; i++)
 702292                {
 293                    // Wishful thinking
 702294                    if (rootSystem.subSystemList[i].type == subSystemType)
 10295                    {
 10296                        foundSubSystem = true;
 10297                        return ref rootSystem.subSystemList[i];
 298                    }
 299
 300                    // Evaluate children
 692301                    if (rootSystem.subSystemList[i].subSystemList != null &&
 302                        rootSystem.subSystemList[i].subSystemList.Length > 0)
 60303                    {
 60304                        ref PlayerLoopSystem child = ref rootSystem.subSystemList[i]
 305                            .TryGetFirstSubSystemOfType(subSystemType, out foundSubSystem);
 60306                        if (foundSubSystem)
 10307                        {
 10308                            return ref child;
 309                        }
 50310                    }
 682311                }
 50312            }
 313
 50314            foundSubSystem = false;
 50315            return ref rootSystem;
 70316        }
 317
 318        /// <summary>
 319        ///     Searches the provided <paramref name="rootSystem"/> child (sub) systems for the first instance of a
 320        ///     <paramref name="subSystemType"/> and returns the parent system, with <paramref name="foundSystemIndex"/>
 321        ///     of the found child (sub) system.
 322        /// </summary>
 323        /// <param name="rootSystem">
 324        ///     The root system which the <paramref name="subSystemType"/> will be searched recursively for.
 325        /// </param>
 326        /// <param name="subSystemType">The child (sub) system <see cref="Type"/> that will be searched for recursively.
 327        /// <param name="foundSubSystem">Was an appropriate child (sub) system found?</param>
 328        /// <param name="foundSystemIndex">The index of the found sub (child) system.</param>
 329        /// <returns>
 330        ///     The found parent system, or the root system. Check <paramref name="foundSubSystem"/> to determine if the
 331        ///     child (sub) system was actually found. This pattern is used to preserve the reference.
 332        /// </returns>
 333        public static ref PlayerLoopSystem TryGetFirstSystemWithSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 334            Type subSystemType, out bool foundSubSystem, out int foundSystemIndex)
 0335        {
 0336            if (rootSystem.subSystemList != null)
 0337            {
 0338                int subCount = rootSystem.subSystemList.Length;
 0339                for (int i = 0; i < subCount; i++)
 0340                {
 341                    // Wishful thinking
 0342                    if (rootSystem.subSystemList[i].type == subSystemType)
 0343                    {
 0344                        foundSubSystem = true;
 0345                        foundSystemIndex = i;
 0346                        return ref rootSystem;
 347                    }
 348
 349                    // Evaluate children
 0350                    if (rootSystem.subSystemList[i].subSystemList != null &&
 351                        rootSystem.subSystemList[i].subSystemList.Length > 0)
 0352                    {
 0353                        ref PlayerLoopSystem child = ref rootSystem.subSystemList[i]
 354                            .TryGetFirstSystemWithSubSystemOfType(subSystemType, out foundSubSystem,
 355                                out foundSystemIndex);
 0356                        if (foundSubSystem)
 0357                        {
 0358                            return ref child;
 359                        }
 0360                    }
 0361                }
 0362            }
 363
 0364            foundSubSystem = false;
 0365            foundSystemIndex = -1;
 0366            return ref rootSystem;
 0367        }
 368    }
 369}