Skip to content

Instantly share code, notes, and snippets.

@mchamplain
Created October 5, 2023 02:59
Show Gist options
  • Save mchamplain/ce6437da3b83cd877d604115b51db3ea to your computer and use it in GitHub Desktop.
Save mchamplain/ce6437da3b83cd877d604115b51db3ea to your computer and use it in GitHub Desktop.
Helper to find Entitas systems that we didn't add to the systems (Entitas v1.x)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Entitas;
using UnityEngine;
namespace Common.Utilities
{
public static class SystemsVerificationTool
{
public static void EnsureAllSystemsAreAdded(Feature mainSystems, string namespaceFilter)
{
var allSystemsInNamespace = GetAllSystemsInNamespace(namespaceFilter);
var addedSystems = GetAddedSystemsFromFeature(mainSystems);
foreach (var systemType in allSystemsInNamespace)
{
if (!addedSystems.Contains(systemType))
{
Debug.LogWarning($"System {systemType.Name} is not added to the main systems list.");
}
}
}
private static HashSet<Type> GetAllSystemsInNamespace(string namespaceFilter)
{
return new HashSet<Type>(Assembly.GetExecutingAssembly().GetTypes()
.Where(type => type.Namespace != null && type.Namespace.StartsWith(namespaceFilter) &&
!typeof(Feature).IsAssignableFrom(type) && // Exclude Feature types
(typeof(IExecuteSystem).IsAssignableFrom(type) ||
typeof(ICleanupSystem).IsAssignableFrom(type) ||
typeof(IInitializeSystem).IsAssignableFrom(type) ||
typeof(ITearDownSystem).IsAssignableFrom(type) ||
type.IsSubclassOf(typeof(ReactiveSystem<>))
)));
}
private static HashSet<Type> GetAddedSystemsFromFeature(Feature feature)
{
var addedSystems = new HashSet<Type>();
// Extract all systems added to the Feature
List<object> featureSystems = new List<object>();
featureSystems.AddRange(feature.GetSystems<IInitializeSystem>());
featureSystems.AddRange(feature.GetSystems<IExecuteSystem>());
featureSystems.AddRange(feature.GetSystems<ICleanupSystem>());
featureSystems.AddRange(feature.GetSystems<ITearDownSystem>());
foreach (var system in featureSystems)
{
if (system is Feature subFeature)
{
addedSystems.UnionWith(GetAddedSystemsFromFeature(subFeature)); // Recursion for nested Features
}
else
{
addedSystems.Add(system.GetType());
}
}
return addedSystems;
}
public static List<T> GetSystems<T>(this Feature feature)
{
// Get non-public fields using reflection based on type T
string fieldName = "";
if (typeof(T) == typeof(IInitializeSystem))
{
fieldName = "_initializeSystems";
}
else if (typeof(T) == typeof(IExecuteSystem))
{
fieldName = "_executeSystems";
}
else if (typeof(T) == typeof(ICleanupSystem))
{
fieldName = "_cleanupSystems";
}
else if (typeof(T) == typeof(ITearDownSystem))
{
fieldName = "_tearDownSystems";
}
FieldInfo field = typeof(Feature).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
return field.GetValue(feature) as List<T>;
}
return new List<T>();
}
}
}
/**
Usage:
systems = new Feature("Game Systems");
systems
.Add(new TimerFeature(contexts))
.Add(new GameStateFeature(contexts))
.Add(new TutorialFeature(contexts))
//...
;
#if UNITY_EDITOR
// let's check if we forgot to include a system -_-
SystemsVerificationTool.EnsureAllSystemsAreAdded(systems, "MyGame.Scripts");
#endif
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment