< Summary

Class:GDX.PlayerLoopSystemExtensions
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/PlayerLoopSystemExtensions.cs
Covered lines:106
Uncovered lines:67
Coverable lines:173
Total lines:395
Line coverage:61.2% (106 of 173)
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%330100%
AddSubSystemToFirstSubSystemOfType(...)0%4.594066.67%
AddSubSystemToFirstSubSystemOfType(...)0%2.062075%
GenerateSystemTree(...)0%10100100%
RemoveSubSystemsOfType(...)0%8.987065.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-2024 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)
 622        {
 623            if (parentSystem.subSystemList != null)
 124            {
 125                ref PlayerLoopSystem[] previousSubSystems = ref parentSystem.subSystemList;
 126                int subSystemCount = previousSubSystems.Length;
 127                PlayerLoopSystem[] newSubSystems = new PlayerLoopSystem[subSystemCount + 1];
 1828                for (int i = 0; i < subSystemCount; i++)
 829                {
 830                    newSubSystems[i] = previousSubSystems[i];
 831                }
 32
 133                newSubSystems[subSystemCount] = subSystem;
 134                parentSystem.subSystemList = newSubSystems;
 135            }
 36            else
 537            {
 538                parentSystem.subSystemList = new PlayerLoopSystem[1];
 539                parentSystem.subSystemList[0] = subSystem;
 540            }
 641        }
 42
 43        /// <summary>
 44        ///     Adds a child (sub) system to the first found instance of a <paramref name="parentSystemType" /> system i
 45        ///     <paramref name="rootSystem" />.
 46        /// </summary>
 47        /// <param name="rootSystem">
 48        ///     The root system which the <paramref name="parentSystemType" /> will be searched recursively
 49        ///     for.
 50        /// </param>
 51        /// <param name="parentSystemType">The system <see cref="Type" /> that will be searched for as the parent.</para
 52        /// <param name="subSystemType">The type assigned when creating the <see cref="PlayerLoopSystem" /> to be added.
 53        /// <param name="subSystemUpdateFunction">The method to invoke when the system is updated.</param>
 54        /// <returns>true/false if the <paramref name="parentSystemType" /> was found, and therefore the add could occur
 55        /// <example>
 56        ///     <code>
 57        ///     PlayerLoopSystem systemRoot = PlayerLoop.GetCurrentPlayerLoop();
 58        ///     systemRoot.AddSubSystemToFirstSubSystemOfType(
 59        ///         typeof(Update.ScriptRunDelayedTasks),
 60        ///         typeof(TaskDirectorSystem), PlayerLoopTick);
 61        ///     PlayerLoop.SetPlayerLoop(systemRoot);
 62        /// </code>
 63        /// </example>
 64        public static bool AddSubSystemToFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 65            Type parentSystemType, Type subSystemType, PlayerLoopSystem.UpdateFunction subSystemUpdateFunction)
 566        {
 567            if (subSystemUpdateFunction == null || subSystemType == null)
 068            {
 069                return false;
 70            }
 71
 572            PlayerLoopSystem newSubSystem = new PlayerLoopSystem
 73            {
 74                updateDelegate = subSystemUpdateFunction, type = subSystemType
 75            };
 76
 577            ref PlayerLoopSystem foundParent =
 78                ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foundTargetSystem);
 579            if (!foundTargetSystem)
 080            {
 081                return false;
 82            }
 83
 584            AddSubSystem(ref foundParent, ref newSubSystem);
 585            return true;
 586        }
 87
 88
 89        /// <summary>
 90        ///     Adds a child (sub) system to the first found instance of a <paramref name="parentSystemType" /> system i
 91        ///     <paramref name="rootSystem" />.
 92        /// </summary>
 93        /// <param name="rootSystem">
 94        ///     The root system which the <paramref name="parentSystemType" /> will be searched recursively
 95        ///     for.
 96        /// </param>
 97        /// <param name="parentSystemType">The system <see cref="Type" /> that will be searched for as the parent.</para
 98        /// <param name="subSystem">The child (sub) system that is to be added to the parent.</param>
 99        /// <returns>true/false if the <paramref name="parentSystemType" /> was found, and therefore the add could occur
 100        public static bool AddSubSystemToFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 101            Type parentSystemType, ref PlayerLoopSystem subSystem)
 1102        {
 1103            ref PlayerLoopSystem foundParent =
 104                ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foundTargetSystem);
 1105            if (!foundTargetSystem)
 0106            {
 0107                return false;
 108            }
 109
 1110            AddSubSystem(ref foundParent, ref subSystem);
 1111            return true;
 1112        }
 113
 114        /// <summary>
 115        ///     Populates a <see cref="TextGenerator" /> with a tree-like structure that represents the
 116        ///     <see cref="PlayerLoopSystem" /> found under the <paramref name="rootSystem" />.
 117        /// </summary>
 118        /// <param name="rootSystem">The root system which the tree should be crafted based off of.</param>
 119        /// <param name="generator">Optionally, provide a generator to be populated.</param>
 120        /// <returns>A <see cref="TextGenerator" /> populated with the system output.</returns>
 121        public static TextGenerator GenerateSystemTree(this ref PlayerLoopSystem rootSystem,
 122            TextGenerator generator = null)
 671123        {
 124            // We abuse this for recursion
 671125            generator ??= new TextGenerator();
 126
 671127            if (rootSystem.type != null)
 666128            {
 666129                generator.AppendLine(rootSystem.type.Name);
 666130            }
 131            else
 5132            {
 5133                generator.AppendLine(generator.GetIndentLevel() == 0 ? "_RootSystem_" : "_NullSystem_");
 5134            }
 135
 671136            if (rootSystem.subSystemList == null || rootSystem.subSystemList.Length <= 0)
 623137            {
 623138                return generator;
 139            }
 140
 48141            int count = rootSystem.subSystemList.Length;
 48142            if (count > 0)
 48143            {
 48144                generator.PushIndent();
 48145            }
 146
 1428147            for (int i = 0; i < count; i++)
 666148            {
 666149                GenerateSystemTree(ref rootSystem.subSystemList[i], generator);
 666150            }
 151
 48152            if (count > 0)
 48153            {
 48154                generator.PopIndent();
 48155            }
 156
 48157            return generator;
 671158        }
 159
 160        /// <summary>
 161        ///     Removes all child (sub) systems of the specified <paramref name="subSystemType" /> from the provided
 162        ///     <paramref name="parentSystem" />.
 163        /// </summary>
 164        /// <remarks>
 165        ///     This is NOT recursive, and will not effect the child (sub) systems of the child (sub) systems of the
 166        ///     <paramref name="parentSystem" />
 167        /// </remarks>
 168        /// <param name="parentSystem">The parent system which the child (sub) systems should be removed from.</param>
 169        /// <param name="subSystemType">The system <see cref="Type" /> that will be removed.</param>
 170        /// <returns>true/false, if a remove was done.</returns>
 171        public static bool RemoveSubSystemsOfType(this ref PlayerLoopSystem parentSystem, Type subSystemType)
 5172        {
 5173            if (parentSystem.subSystemList == null)
 0174            {
 0175                return false;
 176            }
 177
 5178            ref PlayerLoopSystem[] previousSubSystems = ref parentSystem.subSystemList;
 5179            int subSystemCount = previousSubSystems.Length;
 180
 181            // We need to actually make sure there is a sub system of type to remove, we will use the search as a place
 182            // to also figure out if there is multiple options.
 5183            int foundCount = 0;
 20184            for (int i = 0; i < subSystemCount; i++)
 5185            {
 5186                if (previousSubSystems[i].type == subSystemType)
 5187                {
 5188                    foundCount++;
 5189                }
 5190            }
 191
 5192            if (foundCount == 0)
 0193            {
 0194                return false;
 195            }
 196
 5197            int newIndex = 0;
 5198            int newCount = subSystemCount - foundCount;
 5199            PlayerLoopSystem[] newSubSystemList = new PlayerLoopSystem[newCount];
 200
 10201            for (int i = 0; i < newCount; i++)
 0202            {
 0203                if (previousSubSystems[i].type != subSystemType)
 0204                {
 0205                    newSubSystemList[newIndex] = previousSubSystems[i];
 0206                    newIndex++;
 0207                }
 0208            }
 209
 5210            parentSystem.subSystemList = newSubSystemList;
 211
 5212            return true;
 5213        }
 214
 215        /// <summary>
 216        ///     Removes all the child (sub) systems of to the first found instance of a <paramref name="parentSystemType
 217        ///     in <paramref name="rootSystem" />
 218        /// </summary>
 219        /// <param name="rootSystem">
 220        ///     The root system which the <paramref name="parentSystemType" /> will be searched recursively
 221        ///     for.
 222        /// </param>
 223        /// <param name="parentSystemType">The system <see cref="Type" /> that will be searched for as the parent.</para
 224        /// <param name="subSystemType">The child (sub) system <see cref="Type" /> that will be removed.</param>
 225        /// <returns>true/false, if a remove occured.</returns>
 226        public static bool RemoveSubSystemsOfTypeFromFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 227            Type parentSystemType, Type subSystemType)
 5228        {
 5229            ref PlayerLoopSystem foundParent =
 230                ref rootSystem.TryGetFirstSubSystemOfType(parentSystemType, out bool foundTargetSystem);
 5231            if (!foundTargetSystem)
 0232            {
 0233                return false;
 234            }
 235
 5236            return RemoveSubSystemsOfType(ref foundParent, subSystemType);
 5237        }
 238
 239        /// <summary>
 240        ///     Replaces the first child (sub) system of the given <paramref name="rootSystem" /> of
 241        ///     <paramref name="subSystemType" /> with the provided <paramref name="updatedSystem" />.
 242        /// </summary>
 243        /// <param name="rootSystem">The root system which the <paramref name="subSystemType" /> will be searched recurs
 244        /// <param name="subSystemType">The child (sub) system <see cref="Type" /> that will be replaced.</param>
 245        /// <param name="updatedSystem">The system to replace the found <paramref name="subSystemType" /> with.</param>
 246        /// <returns>true/false if the replace occured.</returns>
 247        public static bool ReplaceFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem, Type subSystemType,
 248            ref PlayerLoopSystem updatedSystem)
 0249        {
 0250            ref PlayerLoopSystem foundParent =
 251                ref rootSystem.TryGetFirstSystemWithSubSystemOfType(subSystemType, out bool foundTargetSystem,
 252                    out int foundIndex);
 0253            if (!foundTargetSystem)
 0254            {
 0255                return false;
 256            }
 257
 0258            foundParent.subSystemList[foundIndex] = updatedSystem;
 0259            return true;
 0260        }
 261
 262        /// <summary>
 263        ///     Replaces all child (sub) systems of the specified <paramref name="subSystemType" /> from the provided
 264        ///     <paramref name="parentSystem" />.
 265        /// </summary>
 266        /// <remarks>
 267        ///     This is NOT recursive, and will not effect the child (sub) systems of the child (sub) systems of the
 268        ///     <paramref name="parentSystem" />
 269        /// </remarks>
 270        /// <param name="parentSystem">The parent system which the child (sub) systems should be replaced.</param>
 271        /// <param name="subSystemType">The system <see cref="Type" /> that will be replaced.</param>
 272        /// <param name="updatedSystem">The system to replace the found <paramref name="subSystemType" /> with.</param>
 273        /// <returns>true/false if any replacement occured.</returns>
 274        public static bool ReplaceSubSystemsOfType(this ref PlayerLoopSystem parentSystem, Type subSystemType,
 275            ref PlayerLoopSystem updatedSystem)
 0276        {
 0277            if (parentSystem.subSystemList == null)
 0278            {
 0279                return false;
 280            }
 281
 0282            int count = parentSystem.subSystemList.Length;
 0283            bool replaced = false;
 0284            for (int i = 0; i < count; i++)
 0285            {
 0286                if (parentSystem.subSystemList[i].type != subSystemType)
 0287                {
 0288                    continue;
 289                }
 290
 0291                parentSystem.subSystemList[i] = updatedSystem;
 0292                replaced = true;
 0293            }
 294
 0295            return replaced;
 0296        }
 297
 298        /// <summary>
 299        ///     Searches the provided <paramref name="rootSystem" /> child (sub) systems for the first instance of a
 300        ///     <paramref name="subSystemType" /> system.
 301        /// </summary>
 302        /// <param name="rootSystem">
 303        ///     The root system which the <paramref name="subSystemType" /> will be searched recursively for.
 304        /// </param>
 305        /// <param name="subSystemType">The child (sub) system <see cref="Type" /> that will be searched for recursively
 306        /// <param name="foundSubSystem">Was an appropriate system found?</param>
 307        /// <returns>
 308        ///     The found system, or the root system. Check <paramref name="foundSubSystem" /> to determine if the syste
 309        ///     was actually found. This pattern is used to preserve the reference.
 310        /// </returns>
 311        public static ref PlayerLoopSystem TryGetFirstSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 312            Type subSystemType, out bool foundSubSystem)
 72313        {
 72314            if (rootSystem.subSystemList != null)
 72315            {
 72316                int subCount = rootSystem.subSystemList.Length;
 1544317                for (int i = 0; i < subCount; i++)
 721318                {
 319                    // Wishful thinking
 721320                    if (rootSystem.subSystemList[i].type == subSystemType)
 11321                    {
 11322                        foundSubSystem = true;
 11323                        return ref rootSystem.subSystemList[i];
 324                    }
 325
 326                    // Evaluate children
 710327                    if (rootSystem.subSystemList[i].subSystemList != null &&
 328                        rootSystem.subSystemList[i].subSystemList.Length > 0)
 61329                    {
 61330                        ref PlayerLoopSystem child = ref rootSystem.subSystemList[i]
 331                            .TryGetFirstSubSystemOfType(subSystemType, out foundSubSystem);
 61332                        if (foundSubSystem)
 10333                        {
 10334                            return ref child;
 335                        }
 51336                    }
 700337                }
 51338            }
 339
 51340            foundSubSystem = false;
 51341            return ref rootSystem;
 72342        }
 343
 344        /// <summary>
 345        ///     Searches the provided <paramref name="rootSystem" /> child (sub) systems for the first instance of a
 346        ///     <paramref name="subSystemType" /> and returns the parent system, with <paramref name="foundSystemIndex" 
 347        ///     of the found child (sub) system.
 348        /// </summary>
 349        /// <param name="rootSystem">
 350        ///     The root system which the <paramref name="subSystemType" /> will be searched recursively for.
 351        /// </param>
 352        /// <param name="subSystemType">The child (sub) system <see cref="Type" /> that will be searched for recursively
 353        /// <param name="foundSubSystem">Was an appropriate child (sub) system found?</param>
 354        /// <param name="foundSystemIndex">The index of the found sub (child) system.</param>
 355        /// <returns>
 356        ///     The found parent system, or the root system. Check <paramref name="foundSubSystem" /> to determine if th
 357        ///     child (sub) system was actually found. This pattern is used to preserve the reference.
 358        /// </returns>
 359        public static ref PlayerLoopSystem TryGetFirstSystemWithSubSystemOfType(this ref PlayerLoopSystem rootSystem,
 360            Type subSystemType, out bool foundSubSystem, out int foundSystemIndex)
 0361        {
 0362            if (rootSystem.subSystemList != null)
 0363            {
 0364                int subCount = rootSystem.subSystemList.Length;
 0365                for (int i = 0; i < subCount; i++)
 0366                {
 367                    // Wishful thinking
 0368                    if (rootSystem.subSystemList[i].type == subSystemType)
 0369                    {
 0370                        foundSubSystem = true;
 0371                        foundSystemIndex = i;
 0372                        return ref rootSystem;
 373                    }
 374
 375                    // Evaluate children
 0376                    if (rootSystem.subSystemList[i].subSystemList != null &&
 377                        rootSystem.subSystemList[i].subSystemList.Length > 0)
 0378                    {
 0379                        ref PlayerLoopSystem child = ref rootSystem.subSystemList[i]
 380                            .TryGetFirstSystemWithSubSystemOfType(subSystemType, out foundSubSystem,
 381                                out foundSystemIndex);
 0382                        if (foundSubSystem)
 0383                        {
 0384                            return ref child;
 385                        }
 0386                    }
 0387                }
 0388            }
 389
 0390            foundSubSystem = false;
 0391            foundSystemIndex = -1;
 0392            return ref rootSystem;
 0393        }
 394    }
 395}