浏览代码

Manager Dependency List

/refactor-manager-dependencies
Thomas ICHÉ 2 年前
当前提交
5511615a
共有 5 个文件被更改,包括 207 次插入15 次删除
  1. 1
      Runtime/Managers/Implementations/GameManager.cs
  2. 177
      Runtime/Managers/Manager.cs
  3. 5
      Runtime/Managers/ManagerDefaultPrefabAttribute.cs
  4. 28
      Runtime/Managers/ManagerDependsOnAttribute.cs
  5. 11
      Runtime/Managers/ManagerDependsOnAttribute.cs.meta

1
Runtime/Managers/Implementations/GameManager.cs


namespace GameplayIngredients
{
[AddComponentMenu(ComponentMenu.managersPath + "Game Manager")]
[ManagerDependsOn(typeof(GameSaveManager), typeof(FullScreenFadeManager), typeof(LevelStreamingManager))]
[ManagerDefaultPrefab("GameManager")]
public class GameManager : Manager
{

177
Runtime/Managers/Manager.cs


if(GameplayIngredientsSettings.currentSettings.verboseCalls)
Debug.Log("Initializing all Managers...");
foreach(var type in kAllManagerTypes)
DependencyGraph dg = new DependencyGraph();
foreach (var type in kAllManagerTypes)
{
// Check for any Do Not Create Attribute
var doNotCreateAttr = type.GetCustomAttribute<DoNotCreateManagerAttribute>();

// Check for entries in exclusion List
if (exclusionList != null && exclusionList.ToList().Contains(type.Name))
dg.Add(type);
var dependencies = type.GetCustomAttribute<ManagerDependsOnAttribute>();
if(dependencies != null)
{
foreach(var depType in dependencies.dependantTypes)
{
dg.AddDependency(type, depType);
}
}
}
if (exclusionList != null)
{
foreach (var type in exclusionList)
Debug.LogWarning($"Manager : {type.Name} is in GameplayIngredientSettings.excludedeManagers List: ignoring Creation");
continue;
if(dg.TryRemove(type, exclusionList))
{
if (GameplayIngredientsSettings.currentSettings.verboseCalls)
Debug.LogWarning($"Manager : Excluded {type} from manager creation");
}
else
{
if (GameplayIngredientsSettings.currentSettings.verboseCalls)
Debug.LogWarning($"Manager : Could not exclude {type} from manager creation because it has dependencies");
}
}
var prefabAttr = type.GetCustomAttribute<ManagerDefaultPrefabAttribute>();
List<Type> toBeCreated = dg.GetOrderedList();
// Finally, create all managers
foreach (var type in toBeCreated)
{
var prefabAttr = type.GetCustomAttribute<ManagerDefaultPrefabAttribute>();
if(prefabAttr != null)
if (prefabAttr != null)
if(prefab == null) // Try loading the "Default_" prefixed version of the prefab
if (prefab == null) // Try loading the "Default_" prefixed version of the prefab
prefab = Resources.Load<GameObject>("Default_"+prefabAttr.prefab);
prefab = Resources.Load<GameObject>("Default_" + prefabAttr.prefab);
if(prefab != null)
if (prefab != null)
{
gameObject = GameObject.Instantiate(prefab);
}

gameObject.name = type.Name;
GameObject.DontDestroyOnLoad(gameObject);
var comp = (Manager)gameObject.GetComponent(type);
s_Managers.Add(type,comp);
s_Managers.Add(type, comp);
}
}
class DependencyGraph
{
List<DependencyNode> nodes;
public DependencyGraph()
{
nodes = new List<DependencyNode>();
}
public void Add(Type o)
{
if (!nodes.Any(n => n.target == o))
{
var node = new DependencyNode(o);
nodes.Add(node);
}
}
DependencyNode Get(Type o)
{
return nodes.Where(n => n.target == o).FirstOrDefault();
}
public void AddDependency(Type o, Type dependency)
{
Add(o);
Add(dependency);
var node = Get(o);
if(!IsDependentOn(dependency, o)) // Prevent Circular Dependency
{
node.dependencies.Add(Get(dependency));
}
else
{
if (GameplayIngredientsSettings.currentSettings.verboseCalls)
Debug.LogWarning($"Managers : Found circular dependency {o} -> {dependency}, ignoring");
}
}
// Try remove a type by its name, if it's not a dependency of another node
public bool TryRemove(string type, string[] exclusionList)
{
var n = nodes.Where(n => n.target.Name == type).FirstOrDefault();
foreach(var node in nodes)
{
// If type is not excluded and our type is a dependency, then we can't remove the node
if (!exclusionList.Contains(node.target.Name) && IsDependentOn(node.target, n.target))
return false;
}
nodes.Remove(n);
return true;
}
// Walk the tree to find dependencies
public bool IsDependentOn(Type type, Type dependency)
{
foreach(var dep in Get(type).dependencies)
{
if (dep.target == type)
return true;
else
return (IsDependentOn(dep.target, dependency));
}
return false;
}
// Return all dependencies of a given type
public List<Type> GetDependencies(Type type)
{
List<Type> t = new List<Type>();
t.Add(type);
foreach(var dep in Get(type).dependencies)
{
if (!t.Contains(dep.target))
t.Concat(GetDependencies(dep.target));
}
return t;
}
// Builds a list of loading order
public List<Type> GetOrderedList()
{
Dictionary<Type, int> d = new Dictionary<Type, int>();
foreach(var node in nodes)
{
if (!d.ContainsKey(node.target))
d.Add(node.target, 0);
else
d[node.target] += 1;
foreach(var dep in node.dependencies)
{
if (!d.ContainsKey(dep.target))
d.Add(dep.target, 0);
else
d[dep.target] += 1;
}
}
return d.OrderBy(x => x.Value).Reverse().ToDictionary(x => x.Key, x => x.Value).Keys.ToList();
}
class DependencyNode
{
public List<DependencyNode> dependencies;
public readonly Type target;
public DependencyNode(Type target)
{
dependencies = new List<DependencyNode>();
this.target = target;
}
public override string ToString()
{
return target.Name;
}
}
}
}

5
Runtime/Managers/ManagerDefaultPrefabAttribute.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System;
namespace GameplayIngredients
{

28
Runtime/Managers/ManagerDependsOnAttribute.cs


using System.Collections.Generic;
using System;
namespace GameplayIngredients
{
[AttributeUsage(AttributeTargets.Class)]
public class ManagerDependsOnAttribute : Attribute
{
public Type[] dependantTypes { get; private set; }
public ManagerDependsOnAttribute(params Type[] dependencies)
{
var dt = new List<Type>();
foreach(var type in dependencies)
{
// Only add if this is a manager
if(type != null && typeof(Manager).IsAssignableFrom(type))
{
dt.Add(type);
}
}
dependantTypes = dt.ToArray();
}
}
}

11
Runtime/Managers/ManagerDependsOnAttribute.cs.meta


fileFormatVersion: 2
guid: c26ce7858a5c56c4da09ed5c0f230f1e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存