|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |