-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDependencyChecker.cs
141 lines (133 loc) · 5.64 KB
/
DependencyChecker.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SALT
{
internal static class DependencyChecker
{
public static bool CheckDependencies(HashSet<ModLoader.ProtoMod> mods)
{
foreach (ModLoader.ProtoMod mod in mods)
{
if (mod.HasDependencies)
{
foreach (Dependency dependency in mod.dependencies.Select(x => Dependency.ParseFromString(x)))
{
Dependency dep = dependency;
if (!mods.Any(x => dep.SatisfiedBy(x)))
{
switch (dep.has_version)
{
case Dependency.HasVersion.MAXIMUM:
throw new Exception(string.Format("Unresolved dependency for '{0}'! Cannot find '{1}' between versions '{2}' and '{3}'", mod.id, dep.mod_id, dep.minimum_version, dep.maximum_version));
case Dependency.HasVersion.MINIMUM:
throw new Exception(string.Format("Unresolved dependency for '{0}'! Cannot find '{1}' above version '{2}'", mod.id, dep.mod_id, dep.minimum_version));
default:
throw new Exception(string.Format("Unresolved dependency for '{0}'! Cannot find '{1}'", mod.id, dep.mod_id));
}
}
}
}
}
return true;
}
public static void CalculateLoadOrder(
HashSet<ModLoader.ProtoMod> mods,
List<string> loadOrder)
{
loadOrder.Clear();
List<ModLoader.ProtoMod> modList = new List<ModLoader.ProtoMod>();
HashSet<string> currentlyLoading = new HashSet<string>();
foreach (ModLoader.ProtoMod mod in mods)
FixAfters(mod);
foreach (ModLoader.ProtoMod mod in mods)
LoadMod(mod);
loadOrder.AddRange(modList.Select(x => x.id));
void FixAfters(ModLoader.ProtoMod mod)
{
foreach (string h in mod.load_before)
{
ModLoader.ProtoMod protoMod = mods.FirstOrDefault(x => x.id == h);
if (protoMod != null)
protoMod.load_after = new HashSet<string>(protoMod.load_after.AddToArray(mod.id)).ToArray();
}
}
void LoadMod(ModLoader.ProtoMod mod)
{
if (modList.Contains(mod))
return;
currentlyLoading.Add(mod.id);
foreach (string v in mod.load_after)
{
ModLoader.ProtoMod mod1 = mods.FirstOrDefault(x => x.id == v);
if (mod1 != null)
{
if (currentlyLoading.Contains(v))
throw new Exception("Circular dependency detected " + mod.id + " " + v);
LoadMod(mod1);
}
}
modList.Add(mod);
currentlyLoading.Remove(mod.id);
}
}
internal class Dependency
{
public string mod_id;
public HasVersion has_version;
public ModInfo.ModVersion minimum_version;
public ModInfo.ModVersion maximum_version;
public static Dependency ParseFromString(string s)
{
string[] strArray = s.Split(' ');
switch (strArray.Length)
{
case 2:
return new Dependency
{
mod_id = strArray[0],
has_version = HasVersion.MINIMUM,
minimum_version = ModInfo.ModVersion.Parse(strArray[1]),
maximum_version = ModInfo.ModVersion.DEFAULT
};
case 3:
return new Dependency
{
mod_id = strArray[0],
has_version = HasVersion.MAXIMUM,
minimum_version = ModInfo.ModVersion.Parse(strArray[1]),
maximum_version = ModInfo.ModVersion.Parse(strArray[2])
};
default:
return new Dependency
{
mod_id = strArray[0],
has_version = HasVersion.NONE,
minimum_version = ModInfo.ModVersion.DEFAULT,
maximum_version = ModInfo.ModVersion.DEFAULT
};
}
}
public bool SatisfiedBy(ModLoader.ProtoMod mod)
{
if (mod.id != this.mod_id) return false;
switch (this.has_version)
{
case HasVersion.MINIMUM:
return ModInfo.ModVersion.Parse(mod.version).CompareTo(this.minimum_version) >= 0;
case HasVersion.MAXIMUM:
return ModInfo.ModVersion.Parse(mod.version).CompareTo(this.minimum_version) >= 0 && ModInfo.ModVersion.Parse(mod.version).CompareTo(this.maximum_version) <= 0;
default:
return true;
}
}
public enum HasVersion
{
NONE,
MINIMUM,
MAXIMUM
}
}
}
}