public ObjectCreator(Manifest manifest, FileSystem.FileSystem modFiles) { typeCache = new Cache<string, Type>(FindType); ctorCache = new Cache<Type, ConstructorInfo>(GetCtor); // Allow mods to load types from the core Game assembly, and any additional assemblies they specify. var assemblyList = new List<Assembly>() { typeof(Game).Assembly }; foreach (var path in manifest.Assemblies) { var data = modFiles.Open(path).ReadAllBytes(); // .NET doesn't provide any way of querying the metadata of an assembly without either: // (a) loading duplicate data into the application domain, breaking the world. // (b) crashing if the assembly has already been loaded. // We can't check the internal name of the assembly, so we'll work off the data instead var hash = CryptoUtil.SHA1Hash(data); Assembly assembly; if (!ResolvedAssemblies.TryGetValue(hash, out assembly)) { assembly = Assembly.Load(data); ResolvedAssemblies.Add(hash, assembly); } assemblyList.Add(assembly); } AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly; assemblies = assemblyList.SelectMany(asm => asm.GetNamespaces().Select(ns => Pair.New(asm, ns))).ToArray(); AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly; }
public ModData(string mod, bool useLoadScreen = false) { Languages = new string[0]; Manifest = new Manifest(mod); ObjectCreator = new ObjectCreator(Manifest); Manifest.LoadCustomData(ObjectCreator); if (useLoadScreen) { LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value); LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value)); LoadScreen.Display(); } WidgetLoader = new WidgetLoader(this); RulesetCache = new RulesetCache(this); RulesetCache.LoadingProgress += HandleLoadingProgress; MapCache = new MapCache(this); var spriteLoaders = new List<ISpriteLoader>(); foreach (var format in Manifest.SpriteFormats) { var loader = ObjectCreator.FindType(format + "Loader"); if (loader == null || !loader.GetInterfaces().Contains(typeof(ISpriteLoader))) throw new InvalidOperationException("Unable to find a sprite loader for type '{0}'.".F(format)); spriteLoaders.Add((ISpriteLoader)ObjectCreator.CreateBasic(loader)); } SpriteLoaders = spriteLoaders.ToArray(); var sequenceFormat = Manifest.Get<SpriteSequenceFormat>(); var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader"); var ctor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null; if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || ctor == null) throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type)); SpriteSequenceLoader = (ISpriteSequenceLoader)ctor.Invoke(new[] { this }); SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s); // HACK: Mount only local folders so we have a half-working environment for the asset installer GlobalFileSystem.UnmountAll(); foreach (var dir in Manifest.Folders) GlobalFileSystem.Mount(dir); defaultRules = Exts.Lazy(() => RulesetCache.Load()); initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; }
public ObjectCreator(Manifest manifest) { // All the core namespaces var asms = typeof(Game).Assembly.GetNamespaces() // Game .Select(c => Pair.New(typeof(Game).Assembly, c)) .ToList(); // Namespaces from each mod assembly foreach (var a in manifest.Assemblies) { var asm = Assembly.LoadFile(Path.GetFullPath(a)); asms.AddRange(asm.GetNamespaces().Select(ns => Pair.New(asm, ns))); } assemblies = asms.ToArray(); }
public ModData(string mod) { Languages = new string[0]; Manifest = new Manifest(mod); ObjectCreator = new ObjectCreator(Manifest); LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value); LoadScreen.Init(Manifest, Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value)); LoadScreen.Display(); WidgetLoader = new WidgetLoader(this); RulesetCache = new RulesetCache(this); RulesetCache.LoadingProgress += HandleLoadingProgress; MapCache = new MapCache(this); // HACK: Mount only local folders so we have a half-working environment for the asset installer GlobalFileSystem.UnmountAll(); foreach (var dir in Manifest.Folders) GlobalFileSystem.Mount(dir); defaultRules = Exts.Lazy(() => RulesetCache.LoadDefaultRules()); initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; }
public HotkeyManager(IReadOnlyFileSystem fileSystem, Dictionary <string, Hotkey> settings, Manifest manifest) { this.settings = settings; var keyDefinitions = MiniYaml.Load(fileSystem, manifest.Hotkeys, null); foreach (var kd in keyDefinitions) { var definition = new HotkeyDefinition(kd.Key, kd.Value); definitions[kd.Key] = definition; keys[kd.Key] = definition.Default; } foreach (var kv in settings) { if (definitions.ContainsKey(kv.Key)) { keys[kv.Key] = kv.Value; } } foreach (var hd in definitions) { hd.Value.HasDuplicates = GetFirstDuplicate(hd.Value.Name, this[hd.Value.Name].GetValue(), hd.Value) != null; } }
public static string MakeKey(Manifest mod) { return MakeKey(mod.Id, mod.Metadata.Version); }
internal void Register(Manifest mod, string launchPath, IEnumerable<string> launchArgs, ModRegistration registration) { if (mod.Metadata.Hidden) return; var key = ExternalMod.MakeKey(mod); var yaml = new MiniYamlNode("Registration", new MiniYaml("", new List<MiniYamlNode>() { new MiniYamlNode("Id", mod.Id), new MiniYamlNode("Version", mod.Metadata.Version), new MiniYamlNode("Title", mod.Metadata.Title), new MiniYamlNode("LaunchPath", launchPath), new MiniYamlNode("LaunchArgs", new[] { "Game.Mod=" + mod.Id }.Concat(launchArgs).JoinWith(", ")) })); using (var stream = mod.Package.GetStream("icon.png")) if (stream != null) yaml.Value.Nodes.Add(new MiniYamlNode("Icon", Convert.ToBase64String(stream.ReadAllBytes()))); using (var stream = mod.Package.GetStream("icon-2x.png")) if (stream != null) yaml.Value.Nodes.Add(new MiniYamlNode("Icon2x", Convert.ToBase64String(stream.ReadAllBytes()))); using (var stream = mod.Package.GetStream("icon-3x.png")) if (stream != null) yaml.Value.Nodes.Add(new MiniYamlNode("Icon3x", Convert.ToBase64String(stream.ReadAllBytes()))); var sources = new List<string>(); if (registration.HasFlag(ModRegistration.System)) sources.Add(Platform.GetSupportDir(SupportDirType.System)); if (registration.HasFlag(ModRegistration.User)) { sources.Add(Platform.GetSupportDir(SupportDirType.User)); // If using the modern support dir we must also write the registration // to the legacy support dir for older engine versions, but ONLY if it exists var legacyPath = Platform.GetSupportDir(SupportDirType.LegacyUser); if (Directory.Exists(legacyPath)) sources.Add(legacyPath); } // Make sure the mod is available for this session, even if saving it fails LoadMod(yaml.Value, forceRegistration: true); var lines = new List<MiniYamlNode> { yaml }.ToLines().ToArray(); foreach (var source in sources.Distinct()) { var metadataPath = Path.Combine(source, "ModMetadata"); try { Directory.CreateDirectory(metadataPath); File.WriteAllLines(Path.Combine(metadataPath, key + ".yaml"), lines); } catch (Exception e) { Log.Write("debug", "Failed to register current mod metadata"); Log.Write("debug", e.ToString()); } } }