Esempio n. 1
0
        /// <summary>Launch SMAPI.</summary>
        internal void LaunchInteractively()
        {
            // initialise logging
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); // for consistent log formatting
            this.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} on {this.GetFriendlyPlatformName()}", LogLevel.Info);
            Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}";

            // inject compatibility shims
#pragma warning disable 618
            Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry);
            Config.Shim(this.DeprecationManager);
            InternalExtensions.Shim(this.ModRegistry);
            Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry);
            Mod.Shim(this.DeprecationManager);
            ContentEvents.Shim(this.ModRegistry, this.Monitor);
            PlayerEvents.Shim(this.DeprecationManager);
            TimeEvents.Shim(this.DeprecationManager);
#pragma warning restore 618

            // redirect direct console output
            {
                Monitor monitor = this.GetSecondaryMonitor("Console.Out");
                monitor.WriteToFile = false; // not useful for troubleshooting mods per discussion
                if (monitor.WriteToConsole)
                {
                    this.ConsoleManager.OnLineIntercepted += line => monitor.Log(line, LogLevel.Trace);
                }
            }

            // add warning headers
            if (this.Settings.DeveloperMode)
            {
                this.Monitor.ShowTraceInConsole = true;
                this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Warn);
            }
            if (!this.Settings.CheckForUpdates)
            {
                this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn);
            }
            if (!this.Monitor.WriteToConsole)
            {
                this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn);
            }

            // print file paths
            this.Monitor.Log($"Mods go here: {Constants.ModPath}");

            // hook into & launch the game
            try
            {
                // verify version
                if (Constants.GameVersion.IsOlderThan(Constants.MinimumGameVersion))
                {
                    this.Monitor.Log($"Oops! You're running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}, but the oldest supported version is {Constants.GetGameDisplayVersion(Constants.MinimumGameVersion)}. Please update your game before using SMAPI. If you have the beta version on Steam, you may need to opt out to get the latest non-beta updates.", LogLevel.Error);
                    this.PressAnyKeyToExit();
                    return;
                }
                if (Constants.MaximumGameVersion != null && Constants.GameVersion.IsNewerThan(Constants.MaximumGameVersion))
                {
                    this.Monitor.Log($"Oops! You're running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)}, but this version of SMAPI is only compatible up to Stardew Valley {Constants.GetGameDisplayVersion(Constants.MaximumGameVersion)}. Please check for a newer version of SMAPI.", LogLevel.Error);
                    this.PressAnyKeyToExit();
                    return;
                }

                // initialise folders
                this.Monitor.Log("Loading SMAPI...");
                this.VerifyPath(Constants.ModPath);
                this.VerifyPath(Constants.LogDir);

                // check for update when game loads
                if (this.Settings.CheckForUpdates)
                {
                    GameEvents.GameLoaded += (sender, e) => this.CheckForUpdateAsync();
                }

                // launch game
                this.StartGame();
            }
            catch (Exception ex)
            {
                this.Monitor.Log($"Critical error: {ex.GetLogSummary()}", LogLevel.Error);
            }
            this.PressAnyKeyToExit();
        }
Esempio n. 2
0
        /// <summary>Initialise SMAPI and mods after the game starts.</summary>
        private void InitialiseAfterGameStart()
        {
            // load settings
            this.Settings = JsonConvert.DeserializeObject <SConfig>(File.ReadAllText(Constants.ApiConfigPath));
            this.GameInstance.VerboseLogging = this.Settings.VerboseLogging;

            // load core components
            this.ModRegistry        = new ModRegistry();
            this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry);
            this.CommandManager     = new CommandManager();

#if SMAPI_1_x
            // inject compatibility shims
#pragma warning disable 618
            Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry);
            Config.Shim(this.DeprecationManager);
            Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry);
            Mod.Shim(this.DeprecationManager);
            GameEvents.Shim(this.DeprecationManager);
            PlayerEvents.Shim(this.DeprecationManager);
            TimeEvents.Shim(this.DeprecationManager);
#pragma warning restore 618
#endif

            // redirect direct console output
            {
                Monitor monitor = this.GetSecondaryMonitor("Console.Out");
                if (monitor.WriteToConsole)
                {
                    this.ConsoleManager.OnMessageIntercepted += message => this.HandleConsoleMessage(monitor, message);
                }
            }

            // add headers
            if (this.Settings.DeveloperMode)
            {
                this.Monitor.ShowTraceInConsole = true;
#if !SMAPI_1_x
                this.Monitor.ShowFullStampInConsole = true;
#endif
                this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info);
            }
            if (!this.Settings.CheckForUpdates)
            {
                this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn);
            }
            if (!this.Monitor.WriteToConsole)
            {
                this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn);
            }
            if (this.Settings.VerboseLogging)
            {
                this.Monitor.Log("Verbose logging enabled.", LogLevel.Trace);
            }

            // validate XNB integrity
            if (!this.ValidateContentIntegrity())
            {
                this.Monitor.Log("SMAPI found problems in your game's content files which are likely to cause errors or crashes. Consider uninstalling XNB mods or reinstalling the game.", LogLevel.Error);
            }

            // load mods
            {
#if SMAPI_1_x
                this.Monitor.Log("Loading mod metadata...");
#else
                this.Monitor.Log("Loading mod metadata...", LogLevel.Trace);
#endif
                ModResolver resolver = new ModResolver();

                // load manifests
                IModMetadata[] mods = resolver.ReadManifests(Constants.ModPath, new JsonHelper(), this.Settings.ModCompatibility, this.Settings.DisabledMods).ToArray();
                resolver.ValidateManifests(mods, Constants.ApiVersion);

                // check for deprecated metadata
#if SMAPI_1_x
                IList <Action> deprecationWarnings = new List <Action>();
                foreach (IModMetadata mod in mods.Where(m => m.Status != ModMetadataStatus.Failed))
                {
                    // missing fields that will be required in SMAPI 2.0
                    {
                        List <string> missingFields = new List <string>(3);

                        if (string.IsNullOrWhiteSpace(mod.Manifest.Name))
                        {
                            missingFields.Add(nameof(IManifest.Name));
                        }
                        if (mod.Manifest.Version == null || mod.Manifest.Version.ToString() == "0.0")
                        {
                            missingFields.Add(nameof(IManifest.Version));
                        }
                        if (string.IsNullOrWhiteSpace(mod.Manifest.UniqueID))
                        {
                            missingFields.Add(nameof(IManifest.UniqueID));
                        }

                        if (missingFields.Any())
                        {
                            deprecationWarnings.Add(() => this.Monitor.Log($"{mod.DisplayName} is missing some manifest fields ({string.Join(", ", missingFields)}) which will be required in an upcoming SMAPI version.", LogLevel.Warn));
                        }
                    }

                    // per-save directories
                    if ((mod.Manifest as Manifest)?.PerSaveConfigs == true)
                    {
                        deprecationWarnings.Add(() => this.DeprecationManager.Warn(mod.DisplayName, $"{nameof(Manifest)}.{nameof(Manifest.PerSaveConfigs)}", "1.0", DeprecationLevel.PendingRemoval));
                        try
                        {
                            string psDir = Path.Combine(mod.DirectoryPath, "psconfigs");
                            Directory.CreateDirectory(psDir);
                            if (!Directory.Exists(psDir))
                            {
                                mod.SetStatus(ModMetadataStatus.Failed, "it requires per-save configuration files ('psconfigs') which couldn't be created for some reason.");
                            }
                        }
                        catch (Exception ex)
                        {
                            mod.SetStatus(ModMetadataStatus.Failed, $"it requires per-save configuration files ('psconfigs') which couldn't be created: {ex.GetLogSummary()}");
                        }
                    }
                }
#endif

                // process dependencies
                mods = resolver.ProcessDependencies(mods).ToArray();

                // load mods
#if SMAPI_1_x
                this.LoadMods(mods, new JsonHelper(), this.ContentManager, deprecationWarnings);
                foreach (Action warning in deprecationWarnings)
                {
                    warning();
                }
#else
                this.LoadMods(mods, new JsonHelper(), this.ContentManager);
#endif
            }
            if (this.Monitor.IsExiting)
            {
                this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn);
                return;
            }

            // update window titles
            int modsLoaded = this.ModRegistry.GetMods().Count();
            this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods";
            Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods";

            // start SMAPI console
            new Thread(this.RunConsoleLoop).Start();
        }
Esempio n. 3
0
        /*********
        ** Private methods
        *********/
        /// <summary>Initialise SMAPI and mods after the game starts.</summary>
        private void InitialiseAfterGameStart()
        {
            // load settings
            this.Settings = JsonConvert.DeserializeObject <SConfig>(File.ReadAllText(Constants.ApiConfigPath));
            this.GameInstance.VerboseLogging = this.Settings.VerboseLogging;

            // load core components
            this.ModRegistry        = new ModRegistry(this.Settings.ModCompatibility);
            this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry);
            this.CommandManager     = new CommandManager();

            // inject compatibility shims
#pragma warning disable 618
            Command.Shim(this.CommandManager, this.DeprecationManager, this.ModRegistry);
            Config.Shim(this.DeprecationManager);
            InternalExtensions.Shim(this.ModRegistry);
            Log.Shim(this.DeprecationManager, this.GetSecondaryMonitor("legacy mod"), this.ModRegistry);
            Mod.Shim(this.DeprecationManager);
            ContentEvents.Shim(this.ModRegistry, this.Monitor);
            GameEvents.Shim(this.DeprecationManager);
            PlayerEvents.Shim(this.DeprecationManager);
            TimeEvents.Shim(this.DeprecationManager);
#pragma warning restore 618

            // redirect direct console output
            {
                Monitor monitor = this.GetSecondaryMonitor("Console.Out");
                if (monitor.WriteToConsole)
                {
                    this.ConsoleManager.OnMessageIntercepted += message => this.HandleConsoleMessage(monitor, message);
                }
            }

            // add headers
            if (this.Settings.DeveloperMode)
            {
                this.Monitor.ShowTraceInConsole = true;
                this.Monitor.Log($"You configured SMAPI to run in developer mode. The console may be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info);
            }
            if (!this.Settings.CheckForUpdates)
            {
                this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn);
            }
            if (!this.Monitor.WriteToConsole)
            {
                this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn);
            }
            if (this.Settings.VerboseLogging)
            {
                this.Monitor.Log("Verbose logging enabled.", LogLevel.Trace);
            }

            // validate XNB integrity
            if (!this.ValidateContentIntegrity())
            {
                this.Monitor.Log("SMAPI found problems in the game's XNB files which may cause errors or crashes while you're playing. Consider uninstalling XNB mods or reinstalling the game.", LogLevel.Warn);
            }

            // load mods
            int modsLoaded;
            {
                // load mods
                JsonHelper     jsonHelper          = new JsonHelper();
                IList <Action> deprecationWarnings = new List <Action>();
                ModMetadata[]  mods = this.FindMods(Constants.ModPath, new JsonHelper(), deprecationWarnings);
                modsLoaded = this.LoadMods(mods, jsonHelper, (SContentManager)Game1.content, deprecationWarnings);

                // log deprecation warnings together
                foreach (Action warning in deprecationWarnings)
                {
                    warning();
                }
            }
            if (this.Monitor.IsExiting)
            {
                this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn);
                return;
            }

            // update window titles
            this.GameInstance.Window.Title = $"Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods";
            Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GetGameDisplayVersion(Constants.GameVersion)} with {modsLoaded} mods";

            // start SMAPI console
            new Thread(this.RunConsoleLoop).Start();
        }