Ejemplo n.º 1
0
        public void LoadCustomData(ObjectCreator oc)
        {
            foreach (var kv in yaml)
            {
                if (reservedModuleNames.Contains(kv.Key))
                {
                    continue;
                }

                var t = oc.FindType(kv.Key);
                if (t == null || !typeof(IGlobalModData).IsAssignableFrom(t))
                {
                    throw new InvalidDataException("`{0}` is not a valid mod manifest entry.".F(kv.Key));
                }

                IGlobalModData module;
                var            ctor = t.GetConstructor(new[] { typeof(MiniYaml) });
                if (ctor != null)
                {
                    // Class has opted-in to DIY initialization
                    module = (IGlobalModData)ctor.Invoke(new object[] { kv.Value });
                }
                else
                {
                    // Automatically load the child nodes using FieldLoader
                    module = oc.CreateObject <IGlobalModData>(kv.Key);
                    FieldLoader.Load(module, kv.Value);
                }

                modules.Add(module);
            }

            customDataLoaded = true;
        }
Ejemplo n.º 2
0
        static TraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my)
        {
            if (!string.IsNullOrEmpty(my.Value))
            {
                throw new YamlException("Junk value `{0}` on trait node {1}"
                                        .F(my.Value, traitName));
            }

            // HACK: The linter does not want to crash when a trait doesn't exist but only print an error instead
            // ObjectCreator will only return null to signal us to abort here if the linter is running
            var traitInstance = traitName.Split(TraitInstanceSeparator);
            var info          = creator.CreateObject <TraitInfo>(traitInstance[0] + "Info");

            if (info == null)
            {
                return(null);
            }

            try
            {
                if (traitInstance.Length > 1)
                {
                    info.GetType().GetField(nameof(info.InstanceName)).SetValue(info, traitInstance[1]);
                }

                FieldLoader.Load(info, my);
            }
            catch (FieldLoader.MissingFieldsException e)
            {
                var header = "Trait name " + traitName + ": " + (e.Missing.Length > 1 ? "Required properties missing" : "Required property missing");
                throw new FieldLoader.MissingFieldsException(e.Missing, header);
            }

            return(info);
        }
Ejemplo n.º 3
0
        public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false)
        {
            Languages = new string[0];

            // Take a local copy of the manifest
            Manifest       = new Manifest(mod.Id, mod.Package);
            ObjectCreator  = new ObjectCreator(Manifest, mods);
            PackageLoaders = ObjectCreator.GetLoaders <IPackageLoader>(Manifest.PackageFormats, "package");

            ModFiles = new FS(mods, PackageLoaders);
            ModFiles.LoadFromManifest(Manifest);
            Manifest.LoadCustomData(ObjectCreator);

            if (useLoadScreen)
            {
                LoadScreen = ObjectCreator.CreateObject <ILoadScreen>(Manifest.LoadScreen.Value);
                LoadScreen.Init(this, Manifest.LoadScreen.ToDictionary(my => my.Value));
                LoadScreen.Display();
            }

            WidgetLoader = new WidgetLoader(this);
            MapCache     = new MapCache(this);

            SoundLoaders  = ObjectCreator.GetLoaders <ISoundLoader>(Manifest.SoundFormats, "sound");
            SpriteLoaders = ObjectCreator.GetLoaders <ISpriteLoader>(Manifest.SpriteFormats, "sprite");

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

            defaultRules    = Exts.Lazy(() => Ruleset.LoadDefaults(this));
            defaultTileSets = Exts.Lazy(() =>
            {
                var items = new Dictionary <string, TileSet>();

                foreach (var file in Manifest.TileSets)
                {
                    var t = new TileSet(DefaultFileSystem, file);
                    items.Add(t.Id, t);
                }

                return((IReadOnlyDictionary <string, TileSet>)(new ReadOnlyDictionary <string, TileSet>(items)));
            });

            defaultSequences = Exts.Lazy(() =>
            {
                var items = DefaultTileSets.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Value, null));
                return((IReadOnlyDictionary <string, SequenceProvider>)(new ReadOnlyDictionary <string, SequenceProvider>(items)));
            });

            initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Load an uncached IGlobalModData instance directly from the manifest yaml.
        /// This should only be used by external mods that want to query data from this mod.
        /// </summary>
        public T Get <T>(ObjectCreator oc) where T : IGlobalModData
        {
            var t = typeof(T);

            if (!yaml.TryGetValue(t.Name, out var data))
            {
                // Lazily create the default values if not explicitly defined.
                return((T)oc.CreateBasic(t));
            }

            IGlobalModData module;
            var            ctor = t.GetConstructor(new[] { typeof(MiniYaml) });

            if (ctor != null)
            {
                // Class has opted-in to DIY initialization
                module = (IGlobalModData)ctor.Invoke(new object[] { data.Value });
            }
            else
            {
                // Automatically load the child nodes using FieldLoader
                module = oc.CreateObject <IGlobalModData>(t.Name);
                FieldLoader.Load(module, data);
            }

            return((T)module);
        }
Ejemplo n.º 5
0
 public ModData( params string[] mods )
 {
     Manifest = new Manifest( mods );
     ObjectCreator = new ObjectCreator( Manifest );
     LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
     LoadScreen.Init();
     LoadScreen.Display();
     WidgetLoader = new WidgetLoader( this );
 }
Ejemplo n.º 6
0
        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.LoadDefaultRules());

            initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        }
Ejemplo n.º 7
0
 public ModData( params string[] mods )
 {
     Manifest = new Manifest( mods );
     ObjectCreator = new ObjectCreator( Manifest );
     LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value);
     LoadScreen.Init(Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
     LoadScreen.Display();
     WidgetLoader = new WidgetLoader( this );
 }
Ejemplo n.º 8
0
 public ModData(params string[] mods)
 {
     Manifest      = new Manifest(mods);
     ObjectCreator = new ObjectCreator(Manifest);
     LoadScreen    = ObjectCreator.CreateObject <ILoadScreen>(Manifest.LoadScreen.Value);
     LoadScreen.Init(Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value));
     LoadScreen.Display();
     WidgetLoader = new WidgetLoader(this);
 }
Ejemplo n.º 9
0
        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;
        }
Ejemplo n.º 10
0
        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);

            // HACK: Mount only local folders so we have a half-working environment for the asset installer
            FileSystem.UnmountAll();
            foreach (var dir in Manifest.Folders)
                FileSystem.Mount(dir);
        }
Ejemplo n.º 11
0
        public ModData( params string[] mods )
        {
            Manifest = new Manifest( mods );
            ObjectCreator = new ObjectCreator( Manifest );
            LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
            LoadScreen.Init();
            LoadScreen.Display();

            FileSystem.LoadFromManifest( Manifest );
            ChromeProvider.Initialize( Manifest.Chrome );
            SheetBuilder = new SheetBuilder( TextureChannel.Red );
            CursorSheetBuilder = new CursorSheetBuilder( this );
            AvailableMaps = FindMaps( mods );
            WidgetLoader = new WidgetLoader( this );
        }
Ejemplo n.º 12
0
        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);

            // HACK: Mount only local folders so we have a half-working environment for the asset installer
            FileSystem.UnmountAll();
            foreach (var dir in Manifest.Folders)
            {
                FileSystem.Mount(dir);
            }
        }
Ejemplo n.º 13
0
        public ModData( params string[] mods )
        {
            Manifest = new Manifest( mods );
            ObjectCreator = new ObjectCreator( Manifest );
            LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen);
            LoadScreen.Init();
            LoadScreen.Display();

            // all this manipulation of static crap here is nasty and breaks
            // horribly when you use ModData in unexpected ways.

            FileSystem.LoadFromManifest( Manifest );
            ChromeProvider.Initialize( Manifest.Chrome );
            SheetBuilder = new SheetBuilder( TextureChannel.Red );
            CursorSheetBuilder = new CursorSheetBuilder( this );
            AvailableMaps = FindMaps( mods );
            WidgetLoader = new WidgetLoader( this );
        }
Ejemplo n.º 14
0
        public ModData(string mod, bool useLoadScreen = false)
        {
            Languages = new string[0];
            Manifest  = new Manifest(mod);

            // Allow mods to load types from the core Game assembly, and any additional assemblies they specify.
            var assemblies =
                new[] { typeof(Game).Assembly }.Concat(
                Manifest.Assemblies.Select(path => Assembly.LoadFrom(Platform.ResolvePath(path))));

            ObjectCreator = new ObjectCreator(assemblies);
            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);

            SoundLoaders  = GetLoaders <ISoundLoader>(Manifest.SoundFormats, "sound");
            SpriteLoaders = GetLoaders <ISpriteLoader>(Manifest.SpriteFormats, "sprite");

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

            defaultRules = Exts.Lazy(() => RulesetCache.Load());

            initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        }
Ejemplo n.º 15
0
        static ITraitInfo LoadTraitInfo(ObjectCreator creator, string traitName, MiniYaml my)
        {
            if (!string.IsNullOrEmpty(my.Value))
            {
                throw new YamlException("Junk value `{0}` on trait node {1}"
                                        .F(my.Value, traitName));
            }
            var info = creator.CreateObject <ITraitInfo>(traitName + "Info");

            try
            {
                FieldLoader.Load(info, my);
            }
            catch (FieldLoader.MissingFieldsException e)
            {
                var header = "Trait name " + traitName + ": " + (e.Missing.Length > 1 ? "Required properties missing" : "Required property missing");
                throw new FieldLoader.MissingFieldsException(e.Missing, header);
            }

            return(info);
        }
Ejemplo n.º 16
0
        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.ToDictionary(my => my.Value));
            LoadScreen.Display();
            WidgetLoader = new WidgetLoader(this);
            RulesetCache = new RulesetCache(this);
            RulesetCache.LoadingProgress += HandleLoadingProgress;
            MapCache = new MapCache(this);

            var loaders = 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));
                }

                loaders.Add((ISpriteLoader)ObjectCreator.CreateBasic(loader));
            }

            SpriteLoaders = loaders.ToArray();

            // 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;
        }
Ejemplo n.º 17
0
        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;
        }
Ejemplo n.º 18
0
        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.ToDictionary(my => my.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;
        }
Ejemplo n.º 19
0
        public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false)
        {
            Languages = Array.Empty <string>();

            // Take a local copy of the manifest
            Manifest       = new Manifest(mod.Id, mod.Package);
            ObjectCreator  = new ObjectCreator(Manifest, mods);
            PackageLoaders = ObjectCreator.GetLoaders <IPackageLoader>(Manifest.PackageFormats, "package");

            ModFiles = new FS(mod.Id, mods, PackageLoaders);
            ModFiles.LoadFromManifest(Manifest);
            Manifest.LoadCustomData(ObjectCreator);

            if (useLoadScreen)
            {
                LoadScreen = ObjectCreator.CreateObject <ILoadScreen>(Manifest.LoadScreen.Value);
                LoadScreen.Init(this, Manifest.LoadScreen.ToDictionary(my => my.Value));
                LoadScreen.Display();
            }

            WidgetLoader = new WidgetLoader(this);
            MapCache     = new MapCache(this);

            SoundLoaders  = ObjectCreator.GetLoaders <ISoundLoader>(Manifest.SoundFormats, "sound");
            SpriteLoaders = ObjectCreator.GetLoaders <ISpriteLoader>(Manifest.SpriteFormats, "sprite");
            VideoLoaders  = ObjectCreator.GetLoaders <IVideoLoader>(Manifest.VideoFormats, "video");

            var terrainFormat = Manifest.Get <TerrainFormat>();
            var terrainLoader = ObjectCreator.FindType(terrainFormat.Type + "Loader");
            var terrainCtor   = terrainLoader?.GetConstructor(new[] { typeof(ModData) });

            if (terrainLoader == null || !terrainLoader.GetInterfaces().Contains(typeof(ITerrainLoader)) || terrainCtor == null)
            {
                throw new InvalidOperationException($"Unable to find a terrain loader for type '{terrainFormat.Type}'.");
            }

            TerrainLoader = (ITerrainLoader)terrainCtor.Invoke(new[] { this });

            var sequenceFormat = Manifest.Get <SpriteSequenceFormat>();
            var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader");
            var sequenceCtor   = sequenceLoader?.GetConstructor(new[] { typeof(ModData) });

            if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null)
            {
                throw new InvalidOperationException($"Unable to find a sequence loader for type '{sequenceFormat.Type}'.");
            }

            SpriteSequenceLoader = (ISpriteSequenceLoader)sequenceCtor.Invoke(new[] { this });

            var modelFormat = Manifest.Get <ModelSequenceFormat>();
            var modelLoader = ObjectCreator.FindType(modelFormat.Type + "Loader");
            var modelCtor   = modelLoader?.GetConstructor(new[] { typeof(ModData) });

            if (modelLoader == null || !modelLoader.GetInterfaces().Contains(typeof(IModelSequenceLoader)) || modelCtor == null)
            {
                throw new InvalidOperationException($"Unable to find a model loader for type '{modelFormat.Type}'.");
            }

            ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this });
            ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s);

            Hotkeys = new HotkeyManager(ModFiles, Game.Settings.Keys, Manifest);

            Translation = new Translation(Game.Settings.Player.Language, Manifest.Translations, DefaultFileSystem);

            defaultRules       = Exts.Lazy(() => Ruleset.LoadDefaults(this));
            defaultTerrainInfo = Exts.Lazy(() =>
            {
                var items = new Dictionary <string, ITerrainInfo>();

                foreach (var file in Manifest.TileSets)
                {
                    var t = TerrainLoader.ParseTerrain(DefaultFileSystem, file);
                    items.Add(t.Id, t);
                }

                return((IReadOnlyDictionary <string, ITerrainInfo>)(new ReadOnlyDictionary <string, ITerrainInfo>(items)));
            });

            defaultSequences = Exts.Lazy(() =>
            {
                var items = DefaultTerrainInfo.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Key, null));
                return((IReadOnlyDictionary <string, SequenceProvider>)(new ReadOnlyDictionary <string, SequenceProvider>(items)));
            });

            initialThreadId = Environment.CurrentManagedThreadId;
        }