diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 8d66ad8985..2d271e3592 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets /// public class RulesetStore : DatabaseBackedStore { - private readonly List instances = new List(); + private static readonly Dictionary loaded_assemblies = new Dictionary(); public IEnumerable AllRulesets => Query().Where(r => r.Available); @@ -25,18 +25,9 @@ namespace osu.Game.Rulesets { } - private const string ruleset_library_prefix = "osu.Game.Rulesets"; - - protected override void Prepare(bool reset = false) + static RulesetStore() { - instances.Clear(); - - Connection.CreateTable(); - - if (reset) - { - Connection.DeleteAll(); - } + AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; // todo: don't do this on deploy var sln = DebugUtils.GetSolutionPath(); @@ -50,61 +41,75 @@ namespace osu.Game.Rulesets foreach (string file in Directory.GetFiles(Environment.CurrentDirectory, $"{ruleset_library_prefix}.*.dll")) loadRulesetFromFile(file); - - Connection.BeginTransaction(); - - //add all legacy modes in correct order - foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) - { - Connection.InsertOrReplace(createRulesetInfo(r)); - } - - //add any other modes - foreach (var r in instances.Where(r => r.LegacyID < 0)) - { - var us = createRulesetInfo(r); - - var existing = Query().Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault(); - - if (existing == null) - Connection.Insert(us); - } - - //perform a consistency check - foreach (var r in Query()) - { - try - { - r.CreateInstance(); - r.Available = true; - } - catch - { - r.Available = false; - } - - Connection.Update(r); - } - - Connection.Commit(); } - private void loadRulesetFromFile(string file) + private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); + + private const string ruleset_library_prefix = "osu.Game.Rulesets"; + + protected override void Prepare(bool reset = false) + { + + Connection.CreateTable(); + + if (reset) + { + Connection.DeleteAll(); + } + + var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())); + + Connection.RunInTransaction(() => + { + //add all legacy modes in correct order + foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) + { + Connection.InsertOrReplace(createRulesetInfo(r)); + } + + //add any other modes + foreach (var r in instances.Where(r => r.LegacyID < 0)) + { + var us = createRulesetInfo(r); + + var existing = Query().Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault(); + + if (existing == null) + Connection.Insert(us); + } + }); + + Connection.RunInTransaction(() => + { + //perform a consistency check + foreach (var r in Query()) + { + try + { + r.CreateInstance(); + r.Available = true; + } + catch + { + r.Available = false; + } + + Connection.Update(r); + } + }); + } + + private static void loadRulesetFromFile(string file) { var filename = Path.GetFileNameWithoutExtension(file); - if (instances.Any(i => i.GetType().Namespace == filename)) + if (loaded_assemblies.Values.Any(t => t.Namespace == filename)) return; try { - var assembly = Assembly.LoadFile(file); - var rulesets = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Ruleset))); - - if (rulesets.Count() != 1) - return; - - instances.Add((Ruleset)Activator.CreateInstance(rulesets.First(), new RulesetInfo())); + var assembly = Assembly.LoadFrom(file); + loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsSubclassOf(typeof(Ruleset))); } catch (Exception) { } }