From cd93d59eaf5aa05e0fa55eadd958339b9042155d Mon Sep 17 00:00:00 2001 From: Tyler Staples Date: Mon, 12 Dec 2016 15:58:44 -0800 Subject: Added a struct to wrap cache entries for the sake of tracking invalid lookups. This fixes the issue where a null reference exception would be thrown when trying to look up non-existant or non-private members. Added a null check to GetPrivateValue and it's overloads to fix the issue where it would throw a null reference exception when required was false and the field was null. --- .../Framework/Reflection/ReflectionHelper.cs | 49 ++++++++++++++++++---- 1 file changed, 42 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs b/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs index 38b4e357..1d5cf157 100644 --- a/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs +++ b/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs @@ -12,6 +12,16 @@ namespace StardewModdingAPI.Framework.Reflection /********* ** Properties *********/ + /// MemberInfo wrapper for tracking validity. + internal struct CacheEntry + { + /// Is this member valid. Used to avoid unecessary lookups. + public bool IsValid; + + /// The reflection data for this member. This will be null if IsValid is false. + public MemberInfo MemberInfo; + } + /// The cached fields and methods found via reflection. private readonly MemoryCache Cache = new MemoryCache(typeof(ReflectionHelper).FullName); @@ -67,10 +77,17 @@ namespace StardewModdingAPI.Framework.Reflection /// The object which has the field. /// The field name. /// Whether to throw an exception if the private field is not found. - /// This is a shortcut for followed by . + /// The value of the field or the default value of the type if the field is not found. + /// + /// This is a shortcut for followed by . + /// When is false, this will return the default value if reflection fails. If you need to check whether the field exists, use instead. + /// public TValue GetPrivateValue(object obj, string name, bool required = true) { - return this.GetPrivateField(obj, name, required).GetValue(); + IPrivateField field = this.GetPrivateField(obj, name, required); + return (field != null) + ? field.GetValue() + : default(TValue); } /// Get the value of a private static field. @@ -78,10 +95,17 @@ namespace StardewModdingAPI.Framework.Reflection /// The type which has the field. /// The field name. /// Whether to throw an exception if the private field is not found. - /// This is a shortcut for followed by . + /// The value of the field or the default value of the type if the field is not found. + /// + /// This is a shortcut for followed by . + /// When is false, this will return the default value if reflection fails. If you need to check whether the field exists, use instead. + /// public TValue GetPrivateValue(Type type, string name, bool required = true) { - return this.GetPrivateField(type, name, required).GetValue(); + IPrivateField field = this.GetPrivateField(type, name, required); + return (field != null) + ? field.GetValue() + : default(TValue); } /**** @@ -228,11 +252,22 @@ namespace StardewModdingAPI.Framework.Reflection { // get from cache if (this.Cache.Contains(key)) - return (TMemberInfo)this.Cache[key]; + { + CacheEntry entry = (CacheEntry)this.Cache[key]; + return entry.IsValid + ? (TMemberInfo)entry.MemberInfo + : default(TMemberInfo); + } - // fetch & cache new value + // fetch & cache new value, marking if it's valid for future lookups. TMemberInfo result = fetch(); - this.Cache.Add(key, result, new CacheItemPolicy { SlidingExpiration = this.SlidingCacheExpiry }); + CacheEntry cacheEntry = new CacheEntry() + { + IsValid = (result != null), + MemberInfo = result + }; + + this.Cache.Add(key, cacheEntry, new CacheItemPolicy { SlidingExpiration = this.SlidingCacheExpiry }); return result; } } -- cgit From d9e87399bf65d0053ad57d316d0df9e1a631a42b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Dec 2016 12:27:44 -0500 Subject: format code (#193) --- .../Framework/Reflection/CacheEntry.cs | 30 ++++++++++++++++++++ .../Framework/Reflection/ReflectionHelper.cs | 33 ++++++---------------- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 3 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 src/StardewModdingAPI/Framework/Reflection/CacheEntry.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/Reflection/CacheEntry.cs b/src/StardewModdingAPI/Framework/Reflection/CacheEntry.cs new file mode 100644 index 00000000..30faca37 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Reflection/CacheEntry.cs @@ -0,0 +1,30 @@ +using System.Reflection; + +namespace StardewModdingAPI.Framework.Reflection +{ + /// A cached member reflection result. + internal struct CacheEntry + { + /********* + ** Accessors + *********/ + /// Whether the lookup found a valid match. + public bool IsValid; + + /// The reflection data for this member (or null if invalid). + public MemberInfo MemberInfo; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Whether the lookup found a valid match. + /// The reflection data for this member (or null if invalid). + public CacheEntry(bool isValid, MemberInfo memberInfo) + { + this.IsValid = isValid; + this.MemberInfo = memberInfo; + } + } +} diff --git a/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs b/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs index 1d5cf157..edf59b81 100644 --- a/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs +++ b/src/StardewModdingAPI/Framework/Reflection/ReflectionHelper.cs @@ -12,16 +12,6 @@ namespace StardewModdingAPI.Framework.Reflection /********* ** Properties *********/ - /// MemberInfo wrapper for tracking validity. - internal struct CacheEntry - { - /// Is this member valid. Used to avoid unecessary lookups. - public bool IsValid; - - /// The reflection data for this member. This will be null if IsValid is false. - public MemberInfo MemberInfo; - } - /// The cached fields and methods found via reflection. private readonly MemoryCache Cache = new MemoryCache(typeof(ReflectionHelper).FullName); @@ -77,7 +67,7 @@ namespace StardewModdingAPI.Framework.Reflection /// The object which has the field. /// The field name. /// Whether to throw an exception if the private field is not found. - /// The value of the field or the default value of the type if the field is not found. + /// Returns the field value, or the default value for if the field wasn't found and is false. /// /// This is a shortcut for followed by . /// When is false, this will return the default value if reflection fails. If you need to check whether the field exists, use instead. @@ -85,7 +75,7 @@ namespace StardewModdingAPI.Framework.Reflection public TValue GetPrivateValue(object obj, string name, bool required = true) { IPrivateField field = this.GetPrivateField(obj, name, required); - return (field != null) + return field != null ? field.GetValue() : default(TValue); } @@ -95,7 +85,7 @@ namespace StardewModdingAPI.Framework.Reflection /// The type which has the field. /// The field name. /// Whether to throw an exception if the private field is not found. - /// The value of the field or the default value of the type if the field is not found. + /// Returns the field value, or the default value for if the field wasn't found and is false. /// /// This is a shortcut for followed by . /// When is false, this will return the default value if reflection fails. If you need to check whether the field exists, use instead. @@ -103,7 +93,7 @@ namespace StardewModdingAPI.Framework.Reflection public TValue GetPrivateValue(Type type, string name, bool required = true) { IPrivateField field = this.GetPrivateField(type, name, required); - return (field != null) + return field != null ? field.GetValue() : default(TValue); } @@ -254,21 +244,16 @@ namespace StardewModdingAPI.Framework.Reflection if (this.Cache.Contains(key)) { CacheEntry entry = (CacheEntry)this.Cache[key]; - return entry.IsValid - ? (TMemberInfo)entry.MemberInfo + return entry.IsValid + ? (TMemberInfo)entry.MemberInfo : default(TMemberInfo); } - // fetch & cache new value, marking if it's valid for future lookups. + // fetch & cache new value TMemberInfo result = fetch(); - CacheEntry cacheEntry = new CacheEntry() - { - IsValid = (result != null), - MemberInfo = result - }; - + CacheEntry cacheEntry = new CacheEntry(result != null, result); this.Cache.Add(key, cacheEntry, new CacheItemPolicy { SlidingExpiration = this.SlidingCacheExpiry }); return result; } } -} \ No newline at end of file +} diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 1a31b751..65083e67 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -162,6 +162,7 @@ + -- cgit From 487ae1dce92a410984a7c13bf0f30bdd0d878aea Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Dec 2016 13:52:09 -0500 Subject: add version.IsOlderThan(other) method for convenience --- src/StardewModdingAPI/Version.cs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/StardewModdingAPI/Version.cs b/src/StardewModdingAPI/Version.cs index bdecc8e0..7c6d319c 100644 --- a/src/StardewModdingAPI/Version.cs +++ b/src/StardewModdingAPI/Version.cs @@ -98,6 +98,13 @@ namespace StardewModdingAPI return string.Compare(this.ToString(), other.ToString(), StringComparison.InvariantCultureIgnoreCase); } + /// Get whether this version is older than the specified version. + /// The version to compare with this instance. + public bool IsOlderThan(Version other) + { + return this.CompareTo(other) < 0; + } + /// Get whether this version is newer than the specified version. /// The version to compare with this instance. public bool IsNewerThan(Version other) -- cgit From 23988a3c33a7a1616c2d36a2c4b7e3a2d06f4216 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Dec 2016 15:37:23 -0500 Subject: migrate manifest & version to interfaces with backwards compatibility (#197) --- src/StardewModdingAPI/Constants.cs | 8 +- .../Framework/AssemblyRewriting/CacheEntry.cs | 2 +- .../Framework/ModAssemblyLoader.cs | 4 +- src/StardewModdingAPI/IManifest.cs | 27 +++++ src/StardewModdingAPI/ISemanticVersion.cs | 35 ++++++ src/StardewModdingAPI/Manifest.cs | 60 ++++++---- src/StardewModdingAPI/Mod.cs | 15 ++- src/StardewModdingAPI/Program.cs | 22 ++-- src/StardewModdingAPI/SemanticVersion.cs | 130 +++++++++++++++++++++ src/StardewModdingAPI/StardewModdingAPI.csproj | 3 + src/StardewModdingAPI/Version.cs | 118 +++++++------------ 11 files changed, 311 insertions(+), 113 deletions(-) create mode 100644 src/StardewModdingAPI/IManifest.cs create mode 100644 src/StardewModdingAPI/ISemanticVersion.cs create mode 100644 src/StardewModdingAPI/SemanticVersion.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index f5b9e70a..57a89e76 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -26,7 +26,11 @@ namespace StardewModdingAPI ** Accessors *********/ /// SMAPI's current semantic version. - public static readonly Version Version = new Version(1, 4, 0, null); + [Obsolete("Use " + nameof(Constants) + "." + nameof(ApiVersion))] + public static readonly Version Version = (Version)Constants.ApiVersion; + + /// SMAPI's current semantic version. + public static ISemanticVersion ApiVersion => new Version(1, 4, 0, null, suppressDeprecationWarning: true); /// The minimum supported version of Stardew Valley. public const string MinimumGameVersion = "1.1"; @@ -56,7 +60,7 @@ namespace StardewModdingAPI public static string ExecutionPath => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); /// The title of the SMAPI console window. - public static string ConsoleTitle => $"Stardew Modding API Console - Version {Constants.Version} - Mods Loaded: {Program.ModsLoaded}"; + public static string ConsoleTitle => $"Stardew Modding API Console - Version {Constants.ApiVersion} - Mods Loaded: {Program.ModsLoaded}"; /// The directory path in which error logs should be stored. public static string LogDir => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StardewValley", "ErrorLogs"); diff --git a/src/StardewModdingAPI/Framework/AssemblyRewriting/CacheEntry.cs b/src/StardewModdingAPI/Framework/AssemblyRewriting/CacheEntry.cs index 3dfbc78c..a747eaa8 100644 --- a/src/StardewModdingAPI/Framework/AssemblyRewriting/CacheEntry.cs +++ b/src/StardewModdingAPI/Framework/AssemblyRewriting/CacheEntry.cs @@ -36,7 +36,7 @@ namespace StardewModdingAPI.Framework.AssemblyRewriting /// The paths for the cached assembly. /// The MD5 hash of the original assembly. /// The current SMAPI version. - public bool IsUpToDate(CachePaths paths, string hash, Version currentVersion) + public bool IsUpToDate(CachePaths paths, string hash, ISemanticVersion currentVersion) { return hash == this.Hash && this.ApiVersion == currentVersion.ToString() diff --git a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs index 1ceb8ad2..a2c4ac23 100644 --- a/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/ModAssemblyLoader.cs @@ -58,7 +58,7 @@ namespace StardewModdingAPI.Framework CachePaths cachePaths = this.GetCachePaths(assemblyPath); { CacheEntry cacheEntry = File.Exists(cachePaths.Metadata) ? JsonConvert.DeserializeObject(File.ReadAllText(cachePaths.Metadata)) : null; - if (cacheEntry != null && cacheEntry.IsUpToDate(cachePaths, hash, Constants.Version)) + if (cacheEntry != null && cacheEntry.IsUpToDate(cachePaths, hash, Constants.ApiVersion)) return new RewriteResult(assemblyPath, cachePaths, assemblyBytes, cacheEntry.Hash, cacheEntry.UseCachedAssembly, isNewerThanCache: false); // no rewrite needed } this.Monitor.Log($"Preprocessing {Path.GetFileName(assemblyPath)} for compatibility...", LogLevel.Trace); @@ -99,7 +99,7 @@ namespace StardewModdingAPI.Framework // cache all results foreach (RewriteResult result in results) { - CacheEntry cacheEntry = new CacheEntry(result.Hash, Constants.Version.ToString(), forceCacheAssemblies || result.UseCachedAssembly); + CacheEntry cacheEntry = new CacheEntry(result.Hash, Constants.ApiVersion.ToString(), forceCacheAssemblies || result.UseCachedAssembly); File.WriteAllText(result.CachePaths.Metadata, JsonConvert.SerializeObject(cacheEntry)); if (forceCacheAssemblies || result.UseCachedAssembly) File.WriteAllBytes(result.CachePaths.Assembly, result.AssemblyBytes); diff --git a/src/StardewModdingAPI/IManifest.cs b/src/StardewModdingAPI/IManifest.cs new file mode 100644 index 00000000..3e4b7513 --- /dev/null +++ b/src/StardewModdingAPI/IManifest.cs @@ -0,0 +1,27 @@ +namespace StardewModdingAPI +{ + /// A manifest which describes a mod for SMAPI. + public interface IManifest + { + /// The mod name. + string Name { get; set; } + + /// A brief description of the mod. + string Description { get; set; } + + /// The mod author's name. + string Author { get; } + + /// The mod version. + ISemanticVersion Version { get; set; } + + /// The minimum SMAPI version required by this mod, if any. + string MinimumApiVersion { get; set; } + + /// The unique mod ID. + string UniqueID { get; set; } + + /// The name of the DLL in the directory that has the method. + string EntryDll { get; set; } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/ISemanticVersion.cs b/src/StardewModdingAPI/ISemanticVersion.cs new file mode 100644 index 00000000..f50752fe --- /dev/null +++ b/src/StardewModdingAPI/ISemanticVersion.cs @@ -0,0 +1,35 @@ +using System; + +namespace StardewModdingAPI +{ + /// A semantic version with an optional release tag. + public interface ISemanticVersion : IComparable + { + /********* + ** Accessors + *********/ + /// The major version incremented for major API changes. + int MajorVersion { get; } + + /// The minor version incremented for backwards-compatible changes. + int MinorVersion { get; } + + /// The patch version for backwards-compatible bug fixes. + int PatchVersion { get; } + + /// An optional build tag. + string Build { get; } + + + /********* + ** Accessors + *********/ + /// Get whether this version is older than the specified version. + /// The version to compare with this instance. + bool IsOlderThan(ISemanticVersion other); + + /// Get whether this version is newer than the specified version. + /// The version to compare with this instance. + bool IsNewerThan(ISemanticVersion other); + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Manifest.cs b/src/StardewModdingAPI/Manifest.cs index bfc66c43..981ff023 100644 --- a/src/StardewModdingAPI/Manifest.cs +++ b/src/StardewModdingAPI/Manifest.cs @@ -3,21 +3,52 @@ using Newtonsoft.Json; namespace StardewModdingAPI { + /// Wraps so it can implement without breaking backwards compatibility. + [Obsolete("Use " + nameof(IManifest) + " or " + nameof(Mod) + "." + nameof(Mod.ModManifest) + " instead")] + internal class ManifestImpl : Manifest, IManifest + { + /// The mod version. + public new ISemanticVersion Version + { + get { return base.Version; } + set { base.Version = (Version)value; } + } + } + /// A manifest which describes a mod for SMAPI. public class Manifest { /********* ** Accessors *********/ - /// Whether the manifest defined the deprecated field. - [JsonIgnore] - internal bool UsedAuthourField { get; private set; } - /// The mod name. - public virtual string Name { get; set; } = ""; + public string Name { get; set; } + + /// A brief description of the mod. + public string Description { get; set; } /// The mod author's name. - public virtual string Author { get; set; } = ""; + public string Author { get; set; } + + /// The mod version. + public Version Version { get; set; } = new Version(0, 0, 0, "", suppressDeprecationWarning: true); + + /// The minimum SMAPI version required by this mod, if any. + public string MinimumApiVersion { get; set; } + + /// The name of the DLL in the directory that has the method. + public string EntryDll { get; set; } + + /// The unique mod ID. + public string UniqueID { get; set; } = Guid.NewGuid().ToString(); + + + /**** + ** Obsolete + ****/ + /// Whether the manifest defined the deprecated field. + [JsonIgnore] + internal bool UsedAuthourField { get; private set; } /// Obsolete. [Obsolete("Use " + nameof(Manifest) + "." + nameof(Manifest.Author) + ".")] @@ -31,23 +62,8 @@ namespace StardewModdingAPI } } - /// The mod version. - public virtual Version Version { get; set; } = new Version(0, 0, 0, ""); - - /// A brief description of the mod. - public virtual string Description { get; set; } = ""; - - /// The unique mod ID. - public virtual string UniqueID { get; set; } = Guid.NewGuid().ToString(); - /// Whether the mod uses per-save config files. [Obsolete("Use " + nameof(Mod) + "." + nameof(Mod.Helper) + "." + nameof(IModHelper.ReadConfig) + " instead")] - public virtual bool PerSaveConfigs { get; set; } - - /// The minimum SMAPI version required by this mod, if any. - public string MinimumApiVersion { get; set; } - - /// The name of the DLL in the directory that has the method. - public virtual string EntryDll { get; set; } = ""; + public bool PerSaveConfigs { get; set; } } } diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index 21551771..f0f876fa 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -24,7 +24,18 @@ namespace StardewModdingAPI public IMonitor Monitor { get; internal set; } /// The mod's manifest. - public Manifest Manifest { get; internal set; } + [Obsolete("Use " + nameof(Mod) + "." + nameof(ModManifest))] + public Manifest Manifest + { + get + { + Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Manifest)}", "1.5", DeprecationLevel.Notice); + return (Manifest)this.ModManifest; + } + } + + /// The mod's manifest. + public IManifest ModManifest { get; internal set; } /// The full path to the mod's directory on the disk. [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.DirectoryPath) + " instead")] @@ -94,7 +105,7 @@ namespace StardewModdingAPI Program.DeprecationManager.Warn($"{nameof(Mod)}.{nameof(Mod.PerSaveConfigFolder)}", "1.0", DeprecationLevel.Notice); Program.DeprecationManager.MarkWarned($"{nameof(Mod)}.{nameof(Mod.PathOnDisk)}", "1.0"); // avoid redundant warnings - if (!this.Manifest.PerSaveConfigs) + if (!((Manifest)this.Manifest).PerSaveConfigs) { this.Monitor.Log("Tried to fetch the per-save config folder, but this mod isn't configured to use per-save config files.", LogLevel.Error); return ""; diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 62b9dabd..7c9cdcc3 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -98,7 +98,7 @@ namespace StardewModdingAPI Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB"); // add info header - Program.Monitor.Log($"SMAPI {Constants.Version} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info); + Program.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info); // load user settings { @@ -191,9 +191,9 @@ namespace StardewModdingAPI try { GitRelease release = UpdateHelper.GetLatestVersionAsync(Constants.GitHubRepository).Result; - Version latestVersion = new Version(release.Tag); - if (latestVersion.IsNewerThan(Constants.Version)) - Program.Monitor.Log($"You can update SMAPI from version {Constants.Version} to {latestVersion}", LogLevel.Alert); + ISemanticVersion latestVersion = new SemanticVersion(release.Tag); + if (latestVersion.IsNewerThan(Constants.ApiVersion)) + Program.Monitor.Log($"You can update SMAPI from version {Constants.ApiVersion} to {latestVersion}", LogLevel.Alert); } catch (Exception ex) { @@ -212,7 +212,7 @@ namespace StardewModdingAPI Program.StardewAssembly = Assembly.UnsafeLoadFrom(Program.GameExecutablePath); Program.StardewProgramType = Program.StardewAssembly.GetType("StardewValley.Program", true); Program.StardewGameInfo = Program.StardewProgramType.GetField("gamePtr"); - Game1.version += $"-Z_MODDED | SMAPI {Constants.Version}"; + Game1.version += $"-Z_MODDED | SMAPI {Constants.ApiVersion}"; // add error interceptors #if SMAPI_FOR_WINDOWS @@ -335,7 +335,7 @@ namespace StardewModdingAPI string errorPrefix = $"Couldn't load mod for manifest '{manifestPath}'"; // read manifest - Manifest manifest; + ManifestImpl manifest; try { // read manifest text @@ -347,7 +347,7 @@ namespace StardewModdingAPI } // deserialise manifest - manifest = helper.ReadJsonFile("manifest.json"); + manifest = helper.ReadJsonFile("manifest.json"); if (manifest == null) { Program.Monitor.Log($"{errorPrefix}: the manifest file does not exist.", LogLevel.Error); @@ -374,8 +374,8 @@ namespace StardewModdingAPI { try { - Version minVersion = new Version(manifest.MinimumApiVersion); - if (minVersion.IsNewerThan(Constants.Version)) + ISemanticVersion minVersion = new SemanticVersion(manifest.MinimumApiVersion); + if (minVersion.IsNewerThan(Constants.ApiVersion)) { Program.Monitor.Log($"{errorPrefix}: this mod requires SMAPI {minVersion} or later. Please update SMAPI to the latest version to use this mod.", LogLevel.Error); continue; @@ -473,11 +473,11 @@ namespace StardewModdingAPI Program.ModRegistry.Add(manifest, modAssembly); // hook up mod - modEntry.Manifest = manifest; + modEntry.ModManifest = manifest; modEntry.Helper = helper; modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; modEntry.PathOnDisk = directory; - Program.Monitor.Log($"Loaded mod: {modEntry.Manifest.Name} by {modEntry.Manifest.Author}, v{modEntry.Manifest.Version} | {modEntry.Manifest.Description}", LogLevel.Info); + Program.Monitor.Log($"Loaded mod: {modEntry.ModManifest.Name} by {modEntry.ModManifest.Author}, v{modEntry.ModManifest.Version} | {modEntry.ModManifest.Description}", LogLevel.Info); Program.ModsLoaded += 1; modEntry.Entry(); // deprecated since 1.0 modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs new file mode 100644 index 00000000..b3d9ee4a --- /dev/null +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -0,0 +1,130 @@ +using System; +using System.Text.RegularExpressions; + +namespace StardewModdingAPI +{ + /// A semantic version with an optional release tag. + public class SemanticVersion : ISemanticVersion + { + /********* + ** Properties + *********/ + /// A regular expression matching a semantic version string. + /// Derived from https://github.com/maxhauser/semver. + private static readonly Regex Regex = new Regex(@"^(?\d+)(\.(?\d+))?(\.(?\d+))?(?.*)$", RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); + + + /********* + ** Accessors + *********/ + /// The major version incremented for major API changes. + public int MajorVersion { get; set; } + + /// The minor version incremented for backwards-compatible changes. + public int MinorVersion { get; set; } + + /// The patch version for backwards-compatible bug fixes. + public int PatchVersion { get; set; } + + /// An optional build tag. + public string Build { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The major version incremented for major API changes. + /// The minor version incremented for backwards-compatible changes. + /// The patch version for backwards-compatible bug fixes. + /// An optional build tag. + public SemanticVersion(int major, int minor, int patch, string build = null) + { + this.MajorVersion = major; + this.MinorVersion = minor; + this.PatchVersion = patch; + this.Build = build; + } + + /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. + /// The version to compare with this instance. + public int CompareTo(ISemanticVersion other) + { + // compare version numbers + if (this.MajorVersion != other.MajorVersion) + return this.MajorVersion - other.MajorVersion; + if (this.MinorVersion != other.MinorVersion) + return this.MinorVersion - other.MinorVersion; + if (this.PatchVersion != other.PatchVersion) + return this.PatchVersion - other.PatchVersion; + + // stable version (without tag) supercedes prerelease (with tag) + bool curHasTag = !string.IsNullOrWhiteSpace(this.Build); + bool otherHasTag = !string.IsNullOrWhiteSpace(other.Build); + if (!curHasTag && otherHasTag) + return 1; + if (curHasTag && !otherHasTag) + return -1; + + // else compare by string + return string.Compare(this.ToString(), other.ToString(), StringComparison.InvariantCultureIgnoreCase); + } + + /// Get whether this version is older than the specified version. + /// The version to compare with this instance. + public bool IsOlderThan(ISemanticVersion other) + { + return this.CompareTo(other) < 0; + } + + /// Get whether this version is newer than the specified version. + /// The version to compare with this instance. + public bool IsNewerThan(ISemanticVersion other) + { + return this.CompareTo(other) > 0; + } + + /// Get a string representation of the version. + public override string ToString() + { + // version + string result = this.PatchVersion != 0 + ? $"{this.MajorVersion}.{this.MinorVersion}.{this.PatchVersion}" + : $"{this.MajorVersion}.{this.MinorVersion}"; + + // tag + string tag = this.GetNormalisedTag(this.Build); + if (tag != null) + result += $"-{tag}"; + return result; + } + + + /********* + ** Private methods + *********/ + /// Construct an instance. + /// The semantic version string. + internal SemanticVersion(string version) + { + var match = SemanticVersion.Regex.Match(version); + if (!match.Success) + throw new FormatException($"The input '{version}' is not a semantic version."); + + this.MajorVersion = int.Parse(match.Groups["major"].Value); + this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; + this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; + this.Build = (match.Groups["build"].Success ? match.Groups["build"].Value : "").Trim(' ', '-', '.'); + } + + /// Get a normalised build tag. + /// The tag to normalise. + private string GetNormalisedTag(string tag) + { + tag = tag?.Trim().Trim('-', '.'); + if (string.IsNullOrWhiteSpace(tag) || tag == "0") + return null; + return tag; + } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 65083e67..875bc1f3 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -166,8 +166,10 @@ + + @@ -190,6 +192,7 @@ + diff --git a/src/StardewModdingAPI/Version.cs b/src/StardewModdingAPI/Version.cs index 7c6d319c..9c13381a 100644 --- a/src/StardewModdingAPI/Version.cs +++ b/src/StardewModdingAPI/Version.cs @@ -1,21 +1,13 @@ using System; -using System.Text.RegularExpressions; using Newtonsoft.Json; using StardewModdingAPI.Framework; namespace StardewModdingAPI { /// A semantic version with an optional release tag. - public struct Version : IComparable + [Obsolete("Use " + nameof(SemanticVersion) + " or " + nameof(Manifest) + "." + nameof(Manifest.Version) + " instead")] + public struct Version : ISemanticVersion { - /********* - ** Properties - *********/ - /// A regular expression matching a semantic version string. - /// Derived from https://github.com/maxhauser/semver. - private static readonly Regex Regex = new Regex(@"^(?\d+)(\.(?\d+))?(\.(?\d+))?(?.*)$", RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); - - /********* ** Accessors *********/ @@ -39,7 +31,7 @@ namespace StardewModdingAPI get { Program.DeprecationManager.Warn($"{nameof(Version)}.{nameof(Version.VersionString)}", "1.0", DeprecationLevel.Notice); - return this.ToString(); + return this.GetSemanticVersion().ToString(); } } @@ -53,92 +45,72 @@ namespace StardewModdingAPI /// The patch version for backwards-compatible bug fixes. /// An optional build tag. public Version(int major, int minor, int patch, string build) + : this(major, minor, patch, build, suppressDeprecationWarning: false) + { } + + /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. + /// The version to compare with this instance. + public int CompareTo(Version other) { - this.MajorVersion = major; - this.MinorVersion = minor; - this.PatchVersion = patch; - this.Build = build; + return this.GetSemanticVersion().CompareTo(other); } - /// Construct an instance. - /// The semantic version string. - internal Version(string version) + /// Get whether this version is newer than the specified version. + /// The version to compare with this instance. + [Obsolete("Use " + nameof(ISemanticVersion) + "." + nameof(ISemanticVersion.IsNewerThan) + " instead")] + public bool IsNewerThan(Version other) { - var match = Version.Regex.Match(version); - if (!match.Success) - throw new FormatException($"The input '{version}' is not a semantic version."); - - this.MajorVersion = int.Parse(match.Groups["major"].Value); - this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; - this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; - this.Build = (match.Groups["build"].Success ? match.Groups["build"].Value : "").Trim(' ', '-', '.'); + return this.GetSemanticVersion().IsNewerThan(other); } - /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. - /// The version to compare with this instance. - public int CompareTo(Version other) + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + /// An object to compare with this instance. + int IComparable.CompareTo(ISemanticVersion other) { - // compare version numbers - if (this.MajorVersion != other.MajorVersion) - return this.MajorVersion - other.MajorVersion; - if (this.MinorVersion != other.MinorVersion) - return this.MinorVersion - other.MinorVersion; - if (this.PatchVersion != other.PatchVersion) - return this.PatchVersion - other.PatchVersion; - - // stable version (without tag) supercedes prerelease (with tag) - bool curHasTag = !string.IsNullOrWhiteSpace(this.Build); - bool otherHasTag = !string.IsNullOrWhiteSpace(other.Build); - if (!curHasTag && otherHasTag) - return 1; - if (curHasTag && !otherHasTag) - return -1; - - // else compare by string - return string.Compare(this.ToString(), other.ToString(), StringComparison.InvariantCultureIgnoreCase); + return this.GetSemanticVersion().CompareTo(other); } /// Get whether this version is older than the specified version. /// The version to compare with this instance. - public bool IsOlderThan(Version other) + bool ISemanticVersion.IsOlderThan(ISemanticVersion other) { - return this.CompareTo(other) < 0; + return this.GetSemanticVersion().IsOlderThan(other); } /// Get whether this version is newer than the specified version. /// The version to compare with this instance. - public bool IsNewerThan(Version other) - { - return this.CompareTo(other) > 0; - } - - /// Get a string representation of the version. - public override string ToString() + bool ISemanticVersion.IsNewerThan(ISemanticVersion other) { - // version - string result = this.PatchVersion != 0 - ? $"{this.MajorVersion}.{this.MinorVersion}.{this.PatchVersion}" - : $"{this.MajorVersion}.{this.MinorVersion}"; - - // tag - string tag = this.GetNormalisedTag(this.Build); - if (tag != null) - result += $"-{tag}"; - return result; + return this.GetSemanticVersion().IsNewerThan(other); } /********* ** Private methods *********/ - /// Get a normalised build tag. - /// The tag to normalise. - private string GetNormalisedTag(string tag) + /// Construct an instance. + /// The major version incremented for major API changes. + /// The minor version incremented for backwards-compatible changes. + /// The patch version for backwards-compatible bug fixes. + /// An optional build tag. + /// Whether to suppress the deprecation warning. + internal Version(int major, int minor, int patch, string build, bool suppressDeprecationWarning) + { + if (!suppressDeprecationWarning) + Program.DeprecationManager.Warn($"{nameof(Version)}", "1.5", DeprecationLevel.Notice); + + this.MajorVersion = major; + this.MinorVersion = minor; + this.PatchVersion = patch; + this.Build = build; + } + + /// Get the equivalent semantic version. + /// This is a hack so the struct can wrap without a mutable backing field, which would cause a due to recreating the struct value on each change. + private SemanticVersion GetSemanticVersion() { - tag = tag?.Trim().Trim('-', '.'); - if (string.IsNullOrWhiteSpace(tag) || tag == "0") - return null; - return tag; + return new SemanticVersion(this.MajorVersion, this.MinorVersion, this.PatchVersion, this.Build); } } } -- cgit From a8cc3636995c9fc5eb08fa9d42129a05d79bb666 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Dec 2016 16:58:47 -0500 Subject: fix legacy version wrapper not implementing ToString method (#197) --- src/StardewModdingAPI/ISemanticVersion.cs | 3 +++ src/StardewModdingAPI/Version.cs | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/StardewModdingAPI/ISemanticVersion.cs b/src/StardewModdingAPI/ISemanticVersion.cs index f50752fe..3b9bdb44 100644 --- a/src/StardewModdingAPI/ISemanticVersion.cs +++ b/src/StardewModdingAPI/ISemanticVersion.cs @@ -31,5 +31,8 @@ namespace StardewModdingAPI /// Get whether this version is newer than the specified version. /// The version to compare with this instance. bool IsNewerThan(ISemanticVersion other); + + /// Get a string representation of the version. + string ToString(); } } \ No newline at end of file diff --git a/src/StardewModdingAPI/Version.cs b/src/StardewModdingAPI/Version.cs index 9c13381a..87cd4f3d 100644 --- a/src/StardewModdingAPI/Version.cs +++ b/src/StardewModdingAPI/Version.cs @@ -85,6 +85,11 @@ namespace StardewModdingAPI return this.GetSemanticVersion().IsNewerThan(other); } + /// Get a string representation of the version. + public override string ToString() + { + return this.GetSemanticVersion().ToString(); + } /********* ** Private methods -- cgit From 45ee74219ee931b5fef3b67c08adf79d55aa091d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Dec 2016 17:42:51 -0500 Subject: fix issue where changing the active menu inside a menu change handler didn't trigger a new event (#194) --- src/StardewModdingAPI/Inheritance/SGame.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Inheritance/SGame.cs b/src/StardewModdingAPI/Inheritance/SGame.cs index f70d0696..16803a73 100644 --- a/src/StardewModdingAPI/Inheritance/SGame.cs +++ b/src/StardewModdingAPI/Inheritance/SGame.cs @@ -913,11 +913,17 @@ namespace StardewModdingAPI.Inheritance // raise menu changed if (Game1.activeClickableMenu != this.PreviousActiveMenu) { + // raise events + IClickableMenu previousMenu = this.PreviousActiveMenu; + IClickableMenu newMenu = Game1.activeClickableMenu; if (Game1.activeClickableMenu != null) - MenuEvents.InvokeMenuChanged(this.Monitor, this.PreviousActiveMenu, Game1.activeClickableMenu); + MenuEvents.InvokeMenuChanged(this.Monitor, previousMenu, newMenu); else - MenuEvents.InvokeMenuClosed(this.Monitor, this.PreviousActiveMenu); - this.PreviousActiveMenu = Game1.activeClickableMenu; + MenuEvents.InvokeMenuClosed(this.Monitor, previousMenu); + + // update previous menu + // (if the menu was changed in one of the handlers, deliberately defer detection until the next update so mods can be notified of the new menu change) + this.PreviousActiveMenu = newMenu; } // raise location list changed -- cgit From ea65b2b7df78fd075caecac96937e9870e06e646 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Dec 2016 11:45:52 -0500 Subject: correct semantic version pre-release label precedence (#195) --- src/StardewModdingAPI/SemanticVersion.cs | 59 ++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs index b3d9ee4a..cf435aaa 100644 --- a/src/StardewModdingAPI/SemanticVersion.cs +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -48,25 +48,56 @@ namespace StardewModdingAPI /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. /// The version to compare with this instance. + /// The implementation is defined by Semantic Version 2.0 (http://semver.org/). public int CompareTo(ISemanticVersion other) { - // compare version numbers + const int same = 0; + const int curNewer = 1; + const int curOlder = -1; + + // compare stable versions if (this.MajorVersion != other.MajorVersion) - return this.MajorVersion - other.MajorVersion; + return this.MajorVersion.CompareTo(other.MajorVersion); if (this.MinorVersion != other.MinorVersion) - return this.MinorVersion - other.MinorVersion; + return this.MinorVersion.CompareTo(other.MinorVersion); if (this.PatchVersion != other.PatchVersion) - return this.PatchVersion - other.PatchVersion; - - // stable version (without tag) supercedes prerelease (with tag) - bool curHasTag = !string.IsNullOrWhiteSpace(this.Build); - bool otherHasTag = !string.IsNullOrWhiteSpace(other.Build); - if (!curHasTag && otherHasTag) - return 1; - if (curHasTag && !otherHasTag) - return -1; - - // else compare by string + return this.PatchVersion.CompareTo(other.PatchVersion); + if (this.Build == other.Build) + return same; + + // stable supercedes pre-release + bool curIsStable = string.IsNullOrWhiteSpace(this.Build); + bool otherIsStable = string.IsNullOrWhiteSpace(other.Build); + if (curIsStable) + return curNewer; + if (otherIsStable) + return curOlder; + + // compare two pre-release tag values + string[] curParts = this.Build.Split('.'); + string[] otherParts = other.Build.Split('.'); + for (int i = 0; i < curParts.Length; i++) + { + // longer prerelease tag supercedes if otherwise equal + if (otherParts.Length <= i) + return curNewer; + + // compare if different + if (curParts[i] != otherParts[i]) + { + // compare numerically if possible + { + int curNum, otherNum; + if (int.TryParse(curParts[i], out curNum) && int.TryParse(otherParts[i], out otherNum)) + return curNum.CompareTo(otherNum); + } + + // else compare lexically + return string.Compare(curParts[i], otherParts[i], StringComparison.OrdinalIgnoreCase); + } + } + + // fallback (this should never happen) return string.Compare(this.ToString(), other.ToString(), StringComparison.InvariantCultureIgnoreCase); } -- cgit From c257d705758a23cf28ce2c1f00b6d3d42cd30a26 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Dec 2016 13:27:56 -0500 Subject: rename SMAPI config file for consistency (#192, #202) --- README.md | 8 ++++---- src/StardewModdingAPI.Installer/InteractiveInstaller.cs | 5 +++-- .../StardewModdingAPI.Installer.csproj | 4 ++-- src/StardewModdingAPI/Program.cs | 2 +- src/StardewModdingAPI/StardewModdingAPI-settings.json | 4 ---- src/StardewModdingAPI/StardewModdingAPI.config.json | 4 ++++ src/StardewModdingAPI/StardewModdingAPI.csproj | 3 ++- 7 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 src/StardewModdingAPI/StardewModdingAPI-settings.json create mode 100644 src/StardewModdingAPI/StardewModdingAPI.config.json (limited to 'src') diff --git a/README.md b/README.md index 39cfb25c..c4bcd8d4 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,9 @@ directory containing `src`). Mono.Cecil.Rocks.dll Newtonsoft.Json.dll StardewModdingAPI + StardewModdingAPI.config.json StardewModdingAPI.exe StardewModdingAPI.exe.mdb - StardewModdingAPI-settings.json StardewModdingAPI.AssemblyRewriters.dll System.Numerics.dll System.Runtime.Caching.dll @@ -90,10 +90,10 @@ directory containing `src`). Mono.Cecil.dll Mono.Cecil.Rocks.dll Newtonsoft.Json.dll + StardewModdingAPI.config.json StardewModdingAPI.exe StardewModdingAPI.pdb StardewModdingAPI.xml - StardewModdingAPI-settings.json StardewModdingAPI.AssemblyRewriters.dll steam_appid.txt install.exe @@ -102,7 +102,7 @@ directory containing `src`). 4. Open a terminal in the `SMAPI-` directory and run `chmod 755 Mono/StardewModdingAPI`. 5. Copy & paste the `SMAPI-` directory as `SMAPI--for-developers`. 6. In the `SMAPI-` directory, delete the following files: - * `Mono/StardewModdingAPI-settings.json` + * `Mono/StardewModdingAPI.config.json` + * `Windows/StardewModdingAPI.config.json` * `Windows/StardewModdingAPI.xml` - * `Windows/StardewModdingAPI-settings.json` 7. Compress the two folders into `SMAPI-.zip` and `SMAPI--for-developers.zip`. \ No newline at end of file diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index 4cef1a12..ce6c83d9 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -55,7 +55,7 @@ namespace StardewModdingApi.Installer { // common "StardewModdingAPI.exe", - "StardewModdingAPI-settings.json", + "StardewModdingAPI.config.json", "StardewModdingAPI.AssemblyRewriters.dll", "steam_appid.txt", @@ -72,7 +72,8 @@ namespace StardewModdingApi.Installer "StardewModdingAPI.pdb", // obsolete - "Mods/.cache" + "Mods/.cache", // 1.3-1.4 + "StardewModdingAPI-settings.json" // 1.0-1.4 }; diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index f82bce0f..c9dedd45 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -73,7 +73,7 @@ - + @@ -87,7 +87,7 @@ - + diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 7c9cdcc3..9de7496e 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -102,7 +102,7 @@ namespace StardewModdingAPI // load user settings { - string settingsFileName = $"{typeof(Program).Assembly.GetName().Name}-settings.json"; + string settingsFileName = $"{typeof(Program).Assembly.GetName().Name}.config.json"; string settingsPath = Path.Combine(Constants.ExecutionPath, settingsFileName); if (File.Exists(settingsPath)) { diff --git a/src/StardewModdingAPI/StardewModdingAPI-settings.json b/src/StardewModdingAPI/StardewModdingAPI-settings.json deleted file mode 100644 index d27d0141..00000000 --- a/src/StardewModdingAPI/StardewModdingAPI-settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - /* show all deprecation notices in the console? */ - "DeveloperMode": true -} diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json new file mode 100644 index 00000000..d27d0141 --- /dev/null +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -0,0 +1,4 @@ +{ + /* show all deprecation notices in the console? */ + "DeveloperMode": true +} diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 875bc1f3..cbcd9964 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -202,7 +202,7 @@ Designer - + Always @@ -251,6 +251,7 @@ + -- cgit From 444364f418f567405bbd6ba6277432a42c89357d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Dec 2016 13:33:59 -0500 Subject: fix version pre-release tags not consistently normalised (#195) --- src/StardewModdingAPI/SemanticVersion.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs index cf435aaa..9694375e 100644 --- a/src/StardewModdingAPI/SemanticVersion.cs +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -13,6 +13,9 @@ namespace StardewModdingAPI /// Derived from https://github.com/maxhauser/semver. private static readonly Regex Regex = new Regex(@"^(?\d+)(\.(?\d+))?(\.(?\d+))?(?.*)$", RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); + /// The backing field for . + private string _build; + /********* ** Accessors @@ -27,7 +30,11 @@ namespace StardewModdingAPI public int PatchVersion { get; set; } /// An optional build tag. - public string Build { get; set; } + public string Build + { + get { return this._build; } + set { this._build = this.GetNormalisedTag(value); } + } /********* @@ -124,7 +131,7 @@ namespace StardewModdingAPI : $"{this.MajorVersion}.{this.MinorVersion}"; // tag - string tag = this.GetNormalisedTag(this.Build); + string tag = this.Build; if (tag != null) result += $"-{tag}"; return result; @@ -145,7 +152,7 @@ namespace StardewModdingAPI this.MajorVersion = int.Parse(match.Groups["major"].Value); this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; - this.Build = (match.Groups["build"].Success ? match.Groups["build"].Value : "").Trim(' ', '-', '.'); + this.Build = match.Groups["build"].Success ? match.Groups["build"].Value : null; } /// Get a normalised build tag. @@ -153,8 +160,10 @@ namespace StardewModdingAPI private string GetNormalisedTag(string tag) { tag = tag?.Trim().Trim('-', '.'); - if (string.IsNullOrWhiteSpace(tag) || tag == "0") + if (string.IsNullOrWhiteSpace(tag)) return null; + if (tag == "0") + return null; // from incorrect examples in old SMAPI documentation return tag; } } -- cgit From fa71bdd6c724fa02a5b6d58fb2c48a3d007d8a52 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 21 Dec 2016 13:43:04 -0500 Subject: make SemanticVersion constructor from version string public --- src/StardewModdingAPI/Program.cs | 2 +- src/StardewModdingAPI/SemanticVersion.cs | 31 ++++++++++++++++--------------- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 9de7496e..8a87c15d 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -381,7 +381,7 @@ namespace StardewModdingAPI continue; } } - catch (FormatException ex) when (ex.Message.Contains("not a semantic version")) + catch (FormatException ex) when (ex.Message.Contains("not a valid semantic version")) { Program.Monitor.Log($"{errorPrefix}: the mod specified an invalid minimum SMAPI version '{manifest.MinimumApiVersion}'. This should be a semantic version number like {Constants.Version}.", LogLevel.Error); continue; diff --git a/src/StardewModdingAPI/SemanticVersion.cs b/src/StardewModdingAPI/SemanticVersion.cs index 9694375e..daefda51 100644 --- a/src/StardewModdingAPI/SemanticVersion.cs +++ b/src/StardewModdingAPI/SemanticVersion.cs @@ -53,6 +53,21 @@ namespace StardewModdingAPI this.Build = build; } + /// Construct an instance. + /// The semantic version string. + /// The is not a valid semantic version. + internal SemanticVersion(string version) + { + var match = SemanticVersion.Regex.Match(version); + if (!match.Success) + throw new FormatException($"The input '{version}' is not a valid semantic version."); + + this.MajorVersion = int.Parse(match.Groups["major"].Value); + this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; + this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; + this.Build = match.Groups["build"].Success ? match.Groups["build"].Value : null; + } + /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. /// The version to compare with this instance. /// The implementation is defined by Semantic Version 2.0 (http://semver.org/). @@ -141,20 +156,6 @@ namespace StardewModdingAPI /********* ** Private methods *********/ - /// Construct an instance. - /// The semantic version string. - internal SemanticVersion(string version) - { - var match = SemanticVersion.Regex.Match(version); - if (!match.Success) - throw new FormatException($"The input '{version}' is not a semantic version."); - - this.MajorVersion = int.Parse(match.Groups["major"].Value); - this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; - this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; - this.Build = match.Groups["build"].Success ? match.Groups["build"].Value : null; - } - /// Get a normalised build tag. /// The tag to normalise. private string GetNormalisedTag(string tag) @@ -167,4 +168,4 @@ namespace StardewModdingAPI return tag; } } -} \ No newline at end of file +} -- cgit From f7eda265d9dd11af7bc9ce2540d45ba2668e2345 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 10:48:05 -0500 Subject: track loaded mod instances & manifests via mod registry (#201) --- src/StardewModdingAPI/Framework/ModRegistry.cs | 18 ++++++-- src/StardewModdingAPI/IMod.cs | 26 +++++++++++ src/StardewModdingAPI/Mod.cs | 2 +- src/StardewModdingAPI/Program.cs | 60 ++++++++++++++++---------- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 5 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 src/StardewModdingAPI/IMod.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs index ba56a447..b593142d 100644 --- a/src/StardewModdingAPI/Framework/ModRegistry.cs +++ b/src/StardewModdingAPI/Framework/ModRegistry.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; namespace StardewModdingAPI.Framework @@ -11,6 +12,9 @@ namespace StardewModdingAPI.Framework /********* ** Properties *********/ + /// The registered mod data. + private readonly List Mods = new List(); + /// The friendly mod names treated as deprecation warning sources (assembly full name => mod name). private readonly IDictionary ModNamesByAssembly = new Dictionary(); @@ -19,11 +23,17 @@ namespace StardewModdingAPI.Framework ** Public methods *********/ /// Register a mod as a possible source of deprecation warnings. - /// The mod manifest. - /// The mod assembly. - public void Add(Manifest manifest, Assembly assembly) + /// The mod instance. + public void Add(IMod mod) + { + this.Mods.Add(mod); + this.ModNamesByAssembly[mod.GetType().Assembly.FullName] = mod.ModManifest.Name; + } + + /// Get all enabled mods. + public IEnumerable GetMods() { - this.ModNamesByAssembly[assembly.FullName] = manifest.Name; + return (from mod in this.Mods select mod); } /// Get the friendly name for the closest assembly registered as a source of deprecation warnings. diff --git a/src/StardewModdingAPI/IMod.cs b/src/StardewModdingAPI/IMod.cs new file mode 100644 index 00000000..35ac7c0f --- /dev/null +++ b/src/StardewModdingAPI/IMod.cs @@ -0,0 +1,26 @@ +namespace StardewModdingAPI +{ + /// The implementation for a Stardew Valley mod. + public interface IMod + { + /********* + ** Accessors + *********/ + /// Provides simplified APIs for writing mods. + IModHelper Helper { get; } + + /// Writes messages to the console and log file. + IMonitor Monitor { get; } + + /// The mod's manifest. + IManifest ModManifest { get; } + + + /********* + ** Public methods + *********/ + /// The mod entry point, called after the mod is first loaded. + /// Provides simplified APIs for writing mods. + void Entry(IModHelper helper); + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index f0f876fa..d12a7e05 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -5,7 +5,7 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI { /// The base class for a mod. - public class Mod + public class Mod : IMod { /********* ** Properties diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 8a87c15d..f2d7faa8 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -462,37 +462,53 @@ namespace StardewModdingAPI continue; } - // hook up mod + // get mod instance + Mod mod; try { + // get implementation TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); - Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); - if (modEntry != null) + mod = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); + if (mod == null) { - // track mod - Program.ModRegistry.Add(manifest, modAssembly); - - // hook up mod - modEntry.ModManifest = manifest; - modEntry.Helper = helper; - modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; - modEntry.PathOnDisk = directory; - Program.Monitor.Log($"Loaded mod: {modEntry.ModManifest.Name} by {modEntry.ModManifest.Author}, v{modEntry.ModManifest.Version} | {modEntry.ModManifest.Description}", LogLevel.Info); - Program.ModsLoaded += 1; - modEntry.Entry(); // deprecated since 1.0 - modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 - modEntry.Entry(modEntry.Helper); // deprecated since 1.1 - - // raise deprecation warning for old Entry() method - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + Program.Monitor.Log($"{errorPrefix}: the mod's entry class could not be instantiated."); + continue; } + + // inject data + mod.ModManifest = manifest; + mod.Helper = helper; + mod.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + mod.PathOnDisk = directory; + + // track mod + Program.ModRegistry.Add(mod); + Program.ModsLoaded += 1; + Program.Monitor.Log($"Loaded mod: {manifest.Name} by {manifest.Author}, v{manifest.Version} | {manifest.Description}", LogLevel.Info); } catch (Exception ex) { Program.Monitor.Log($"{errorPrefix}: an error occurred while loading the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error); + continue; + } + + // call mod entry + try + { + // call entry methods + mod.Entry(); // deprecated since 1.0 + mod.Entry((ModHelper)mod.Helper); // deprecated since 1.1 + mod.Entry(mod.Helper); + + // raise deprecation warning for old Entry() methods + if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); + if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + } + catch (Exception ex) + { + Program.Monitor.Log($"The {manifest.Name} mod failed on entry initialisation. It will still be loaded, but may not function correctly.\n{ex.GetLogSummary()}", LogLevel.Warn); } } diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index cbcd9964..9dec9881 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -167,6 +167,7 @@ + -- cgit From ca3cf890008ebcf0557b29004514050484a08001 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 11:20:01 -0500 Subject: autogenerate SMAPI config (#202) --- src/StardewModdingAPI/Constants.cs | 3 ++ src/StardewModdingAPI/Program.cs | 33 ++++++++++++---------- .../StardewModdingAPI.config.json | 1 - 3 files changed, 21 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 57a89e76..6df9b76c 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -68,6 +68,9 @@ namespace StardewModdingAPI /// The file path to the error log where the latest output should be saved. public static string LogPath => Path.Combine(Constants.LogDir, "MODDED_ProgramLog.Log_LATEST.txt"); + /// The file path for the SMAPI configuration file. + internal static string ApiConfigPath => Path.Combine(Constants.ExecutionPath, $"{typeof(Program).Assembly.GetName().Name}.config.json"); + /********* ** Protected methods diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index f2d7faa8..e316dbd8 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -49,8 +49,8 @@ namespace StardewModdingAPI /// The core logger for SMAPI. private static readonly Monitor Monitor = new Monitor("SMAPI", Program.LogFile); - /// Whether SMAPI is running in developer mode. - private static bool DeveloperMode; + /// The user settings for SMAPI. + private static UserSettings Settings; /// Tracks whether the game should exit immediately and any pending initialisation should be cancelled. private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); @@ -100,26 +100,29 @@ namespace StardewModdingAPI // add info header Program.Monitor.Log($"SMAPI {Constants.ApiVersion} with Stardew Valley {Game1.version} on {Environment.OSVersion}", LogLevel.Info); - // load user settings + // initialise user settings { - string settingsFileName = $"{typeof(Program).Assembly.GetName().Name}.config.json"; - string settingsPath = Path.Combine(Constants.ExecutionPath, settingsFileName); + string settingsPath = Constants.ApiConfigPath; if (File.Exists(settingsPath)) { string json = File.ReadAllText(settingsPath); - UserSettings settings = JsonConvert.DeserializeObject(json); - Program.DeveloperMode = settings?.DeveloperMode == true; - - if (Program.DeveloperMode) - { - Program.Monitor.ShowTraceInConsole = true; - Program.Monitor.Log($"SMAPI is running in developer mode. The console may be much more verbose. You can disable developer mode by deleting the {settingsFileName} file in the game directory.", LogLevel.Alert); - } + Program.Settings = JsonConvert.DeserializeObject(json); } + else + Program.Settings = new UserSettings(); + + File.WriteAllText(settingsPath, JsonConvert.SerializeObject(Program.Settings, Formatting.Indented)); + } + + // add warning headers + if (Program.Settings.DeveloperMode) + { + Program.Monitor.ShowTraceInConsole = true; + Program.Monitor.Log($"SMAPI is running in developer mode. The console may be much more verbose. You can disable developer mode by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Alert); } // initialise legacy log - Log.Monitor = new Monitor("legacy mod", Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + Log.Monitor = new Monitor("legacy mod", Program.LogFile) { ShowTraceInConsole = Program.Settings.DeveloperMode }; Log.ModRegistry = Program.ModRegistry; // hook into & launch the game @@ -478,7 +481,7 @@ namespace StardewModdingAPI // inject data mod.ModManifest = manifest; mod.Helper = helper; - mod.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + mod.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.Settings.DeveloperMode }; mod.PathOnDisk = directory; // track mod diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index d27d0141..771c28e2 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -1,4 +1,3 @@ { - /* show all deprecation notices in the console? */ "DeveloperMode": true } -- cgit From 90f5233cc7d8202a89e1878e1183562fe5ba17b9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 11:27:48 -0500 Subject: add config setting to disable update checks (#202) --- release-notes.md | 1 + src/StardewModdingAPI/Framework/UserSettings.cs | 6 ++++++ src/StardewModdingAPI/Program.cs | 7 +++++-- src/StardewModdingAPI/StardewModdingAPI.config.json | 3 ++- 4 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 04a9cc04..804d78ba 100644 --- a/release-notes.md +++ b/release-notes.md @@ -4,6 +4,7 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/stable...develop). For players: + * Added option to disable update checks. * Fixed error when a mod uses the new reflection API on a missing field or method. For developers: diff --git a/src/StardewModdingAPI/Framework/UserSettings.cs b/src/StardewModdingAPI/Framework/UserSettings.cs index 199d19b3..6a4fb353 100644 --- a/src/StardewModdingAPI/Framework/UserSettings.cs +++ b/src/StardewModdingAPI/Framework/UserSettings.cs @@ -3,7 +3,13 @@ /// Contains user settings from SMAPI's JSON configuration file. internal class UserSettings { + /********* + ** Accessors + *********/ /// Whether to enable development features. public bool DeveloperMode { get; set; } + + /// Whether to check if a newer version of SMAPI is available on startup. + public bool CheckForUpdates { get; set; } = true; } } diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index e316dbd8..9ecb91e3 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -118,8 +118,10 @@ namespace StardewModdingAPI if (Program.Settings.DeveloperMode) { Program.Monitor.ShowTraceInConsole = true; - Program.Monitor.Log($"SMAPI is running in developer mode. The console may be much more verbose. You can disable developer mode by editing or deleting {Constants.ApiConfigPath}.", LogLevel.Alert); + Program.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 or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); } + if (!Program.Settings.CheckForUpdates) + Program.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 editing or deleting {Constants.ApiConfigPath}.", LogLevel.Warn); // initialise legacy log Log.Monitor = new Monitor("legacy mod", Program.LogFile) { ShowTraceInConsole = Program.Settings.DeveloperMode }; @@ -148,7 +150,8 @@ namespace StardewModdingAPI } // check for update when game loads - GameEvents.GameLoaded += (sender, e) => Program.CheckForUpdateAsync(); + if (Program.Settings.CheckForUpdates) + GameEvents.GameLoaded += (sender, e) => Program.CheckForUpdateAsync(); // launch game Program.StartGame(); diff --git a/src/StardewModdingAPI/StardewModdingAPI.config.json b/src/StardewModdingAPI/StardewModdingAPI.config.json index 771c28e2..2abaf73a 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.config.json +++ b/src/StardewModdingAPI/StardewModdingAPI.config.json @@ -1,3 +1,4 @@ { - "DeveloperMode": true + "DeveloperMode": true, + "CheckForUpdates": true } -- cgit From 3fd16a65f181c710fbbe872f36428176efee7ffb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 12:45:42 -0500 Subject: move models into namespace (#192) --- src/StardewModdingAPI/Framework/GitRelease.cs | 19 ------------------- src/StardewModdingAPI/Framework/Models/GitRelease.cs | 19 +++++++++++++++++++ .../Framework/Models/UserSettings.cs | 15 +++++++++++++++ src/StardewModdingAPI/Framework/UpdateHelper.cs | 1 + src/StardewModdingAPI/Framework/UserSettings.cs | 15 --------------- src/StardewModdingAPI/Program.cs | 1 + src/StardewModdingAPI/StardewModdingAPI.csproj | 4 ++-- 7 files changed, 38 insertions(+), 36 deletions(-) delete mode 100644 src/StardewModdingAPI/Framework/GitRelease.cs create mode 100644 src/StardewModdingAPI/Framework/Models/GitRelease.cs create mode 100644 src/StardewModdingAPI/Framework/Models/UserSettings.cs delete mode 100644 src/StardewModdingAPI/Framework/UserSettings.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/GitRelease.cs b/src/StardewModdingAPI/Framework/GitRelease.cs deleted file mode 100644 index 0da57efd..00000000 --- a/src/StardewModdingAPI/Framework/GitRelease.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace StardewModdingAPI.Framework -{ - /// Metadata about a GitHub release tag. - internal class GitRelease - { - /********* - ** Accessors - *********/ - /// The display name. - [JsonProperty("name")] - public string Name { get; set; } - - /// The semantic version string. - [JsonProperty("tag_name")] - public string Tag { get; set; } - } -} \ No newline at end of file diff --git a/src/StardewModdingAPI/Framework/Models/GitRelease.cs b/src/StardewModdingAPI/Framework/Models/GitRelease.cs new file mode 100644 index 00000000..bc53468f --- /dev/null +++ b/src/StardewModdingAPI/Framework/Models/GitRelease.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace StardewModdingAPI.Framework.Models +{ + /// Metadata about a GitHub release tag. + internal class GitRelease + { + /********* + ** Accessors + *********/ + /// The display name. + [JsonProperty("name")] + public string Name { get; set; } + + /// The semantic version string. + [JsonProperty("tag_name")] + public string Tag { get; set; } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Framework/Models/UserSettings.cs b/src/StardewModdingAPI/Framework/Models/UserSettings.cs new file mode 100644 index 00000000..a0074f77 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Models/UserSettings.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// Contains user settings from SMAPI's JSON configuration file. + internal class UserSettings + { + /********* + ** Accessors + *********/ + /// Whether to enable development features. + public bool DeveloperMode { get; set; } + + /// Whether to check if a newer version of SMAPI is available on startup. + public bool CheckForUpdates { get; set; } = true; + } +} diff --git a/src/StardewModdingAPI/Framework/UpdateHelper.cs b/src/StardewModdingAPI/Framework/UpdateHelper.cs index ddd1d840..e01e55c8 100644 --- a/src/StardewModdingAPI/Framework/UpdateHelper.cs +++ b/src/StardewModdingAPI/Framework/UpdateHelper.cs @@ -3,6 +3,7 @@ using System.Net; using System.Reflection; using System.Threading.Tasks; using Newtonsoft.Json; +using StardewModdingAPI.Framework.Models; namespace StardewModdingAPI.Framework { diff --git a/src/StardewModdingAPI/Framework/UserSettings.cs b/src/StardewModdingAPI/Framework/UserSettings.cs deleted file mode 100644 index 6a4fb353..00000000 --- a/src/StardewModdingAPI/Framework/UserSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace StardewModdingAPI.Framework -{ - /// Contains user settings from SMAPI's JSON configuration file. - internal class UserSettings - { - /********* - ** Accessors - *********/ - /// Whether to enable development features. - public bool DeveloperMode { get; set; } - - /// Whether to check if a newer version of SMAPI is available on startup. - public bool CheckForUpdates { get; set; } = true; - } -} diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 9ecb91e3..cc3cb2bc 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -14,6 +14,7 @@ using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Events; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.AssemblyRewriting; +using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Inheritance; using StardewValley; using Monitor = StardewModdingAPI.Framework.Monitor; diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 9dec9881..0c6697cb 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -174,8 +174,8 @@ - - + + -- cgit From fdae87d340e90793ed00fa1766baf9dbd5bec9b6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 12:47:12 -0500 Subject: skip mods known to be incompatible and display error with update links (#192) --- README.md | 2 ++ .../InteractiveInstaller.cs | 1 + .../StardewModdingAPI.Installer.csproj | 2 ++ src/StardewModdingAPI/Constants.cs | 3 +++ .../Framework/Models/IncompatibleMod.cs | 24 ++++++++++++++++++++++ src/StardewModdingAPI/Manifest.cs | 2 +- src/StardewModdingAPI/Program.cs | 22 ++++++++++++++++++++ src/StardewModdingAPI/StardewModdingAPI.csproj | 5 +++++ src/StardewModdingAPI/StardewModdingAPI.data.json | 16 +++++++++++++++ 9 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs create mode 100644 src/StardewModdingAPI/StardewModdingAPI.data.json (limited to 'src') diff --git a/README.md b/README.md index c4bcd8d4..eb21f379 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ directory containing `src`). Newtonsoft.Json.dll StardewModdingAPI StardewModdingAPI.config.json + StardewModdingAPI.data.json StardewModdingAPI.exe StardewModdingAPI.exe.mdb StardewModdingAPI.AssemblyRewriters.dll @@ -91,6 +92,7 @@ directory containing `src`). Mono.Cecil.Rocks.dll Newtonsoft.Json.dll StardewModdingAPI.config.json + StardewModdingAPI.data.json StardewModdingAPI.exe StardewModdingAPI.pdb StardewModdingAPI.xml diff --git a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs index ce6c83d9..5f89caf2 100644 --- a/src/StardewModdingAPI.Installer/InteractiveInstaller.cs +++ b/src/StardewModdingAPI.Installer/InteractiveInstaller.cs @@ -56,6 +56,7 @@ namespace StardewModdingApi.Installer // common "StardewModdingAPI.exe", "StardewModdingAPI.config.json", + "StardewModdingAPI.data.json", "StardewModdingAPI.AssemblyRewriters.dll", "steam_appid.txt", diff --git a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj index c9dedd45..4e4872b6 100644 --- a/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj +++ b/src/StardewModdingAPI.Installer/StardewModdingAPI.Installer.csproj @@ -74,6 +74,7 @@ + @@ -88,6 +89,7 @@ + diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 6df9b76c..4f7a0c6e 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -71,6 +71,9 @@ namespace StardewModdingAPI /// The file path for the SMAPI configuration file. internal static string ApiConfigPath => Path.Combine(Constants.ExecutionPath, $"{typeof(Program).Assembly.GetName().Name}.config.json"); + /// The file path for the SMAPI data file containing metadata about known mods. + internal static string ApiModMetadataPath => Path.Combine(Constants.ExecutionPath, $"{typeof(Program).Assembly.GetName().Name}.data.json"); + /********* ** Protected methods diff --git a/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs b/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs new file mode 100644 index 00000000..f3ee7d0b --- /dev/null +++ b/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs @@ -0,0 +1,24 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// Contains abstract metadata about an incompatible mod. + internal class IncompatibleMod + { + /********* + ** Accessors + *********/ + /// The unique mod ID. + public string ID { get; set; } + + /// The mod name. + public string Name { get; set; } + + /// The most recent incompatible mod version. + public string Version { get; set; } + + /// The URL the user can check for an official updated version. + public string UpdateUrl { get; set; } + + /// The URL the user can check for an unofficial updated version. + public string UnofficialUpdateUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Manifest.cs b/src/StardewModdingAPI/Manifest.cs index 981ff023..018b31ae 100644 --- a/src/StardewModdingAPI/Manifest.cs +++ b/src/StardewModdingAPI/Manifest.cs @@ -40,7 +40,7 @@ namespace StardewModdingAPI public string EntryDll { get; set; } /// The unique mod ID. - public string UniqueID { get; set; } = Guid.NewGuid().ToString(); + public string UniqueID { get; set; } /**** diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index cc3cb2bc..7de22ee9 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -315,6 +315,11 @@ namespace StardewModdingAPI ModAssemblyLoader modAssemblyLoader = new ModAssemblyLoader(Program.CacheDirName, Program.TargetPlatform, Program.Monitor); AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); + // get known incompatible mods + IDictionary incompatibleMods = File.Exists(Constants.ApiModMetadataPath) + ? JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiModMetadataPath)).ToDictionary(p => p.ID, p => p) + : new Dictionary(0); + // load mods foreach (string directory in Directory.GetDirectories(Program.ModPath)) { @@ -376,6 +381,23 @@ namespace StardewModdingAPI continue; } + // validate known incompatible mods + IncompatibleMod incompatible; + if (incompatibleMods.TryGetValue(manifest.UniqueID ?? $"{manifest.Name}|{manifest.Author}|{manifest.EntryDll}", out incompatible)) + { + if (!manifest.Version.IsNewerThan(new SemanticVersion(incompatible.Version))) + { + string warning = $"Skipped {incompatible.Name} ≤v{incompatible.Version} because this version is not compatible with the latest version of the game. Please check for a newer version of the mod here:"; + if (!string.IsNullOrWhiteSpace(incompatible.UpdateUrl)) + warning += $"{Environment.NewLine}- official mod: {incompatible.UpdateUrl}"; + if (!string.IsNullOrWhiteSpace(incompatible.UnofficialUpdateUrl)) + warning += $"{Environment.NewLine}- unofficial update: {incompatible.UnofficialUpdateUrl}"; + + Program.Monitor.Log(warning, LogLevel.Error); + continue; + } + } + // validate version if (!string.IsNullOrWhiteSpace(manifest.MinimumApiVersion)) { diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index 0c6697cb..07b1ff5e 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -161,6 +161,7 @@ + @@ -206,6 +207,9 @@ Always + + Always + Always @@ -253,6 +257,7 @@ + diff --git a/src/StardewModdingAPI/StardewModdingAPI.data.json b/src/StardewModdingAPI/StardewModdingAPI.data.json new file mode 100644 index 00000000..91321c69 --- /dev/null +++ b/src/StardewModdingAPI/StardewModdingAPI.data.json @@ -0,0 +1,16 @@ +/* + + +This file contains advanced metadata for SMAPI. You shouldn't change this file. + + +*/ +[ + { + "ID": "CJBCheatsMenu", + "Name": "CJB Cheats Menu", + "Version": "1.12", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/4", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + } +] -- cgit From f6f52b653e59778f9e0b2684faa1ad554acce02f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 13:08:45 -0500 Subject: add known incompatible mods, update release notes (#192) --- release-notes.md | 1 + src/StardewModdingAPI/Program.cs | 6 ++++-- src/StardewModdingAPI/StardewModdingAPI.data.json | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 804d78ba..11f393bd 100644 --- a/release-notes.md +++ b/release-notes.md @@ -5,6 +5,7 @@ See [log](https://github.com/Pathoschild/SMAPI/compare/stable...develop). For players: * Added option to disable update checks. + * SMAPI will now show a friendly error with update links when you try to use a known incompatible mod version. * Fixed error when a mod uses the new reflection API on a missing field or method. For developers: diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 7de22ee9..c3bd1646 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -323,8 +323,10 @@ namespace StardewModdingAPI // load mods foreach (string directory in Directory.GetDirectories(Program.ModPath)) { + string directoryName = new DirectoryInfo(directory).Name; + // ignore internal directory - if (new DirectoryInfo(directory).Name == ".cache") + if (directoryName == ".cache") continue; // check for cancellation @@ -341,7 +343,7 @@ namespace StardewModdingAPI string manifestPath = Path.Combine(directory, "manifest.json"); if (!File.Exists(manifestPath)) { - Program.Monitor.Log($"Ignored folder \"{new DirectoryInfo(directory).Name}\" which doesn't have a manifest.json.", LogLevel.Warn); + Program.Monitor.Log($"Ignored folder \"{directoryName}\" which doesn't have a manifest.json.", LogLevel.Warn); continue; } string errorPrefix = $"Couldn't load mod for manifest '{manifestPath}'"; diff --git a/src/StardewModdingAPI/StardewModdingAPI.data.json b/src/StardewModdingAPI/StardewModdingAPI.data.json index 91321c69..2f1d67e8 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.data.json +++ b/src/StardewModdingAPI/StardewModdingAPI.data.json @@ -6,11 +6,32 @@ This file contains advanced metadata for SMAPI. You shouldn't change this file. */ [ + { + "ID": "SPDSprinklersMod", + "Name": "Better Sprinklers", + "Version": "2.1", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + }, + { + "ID": "SPDChestLabel", + "Name": "Chest Label System", + "Version": "1.5", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + }, { "ID": "CJBCheatsMenu", "Name": "CJB Cheats Menu", "Version": "1.12", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/4", "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + }, + { + "ID": "CJBItemSpawner", + "Name": "CJB Item Spawner", + "Version": "1.5", + "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" } ] -- cgit From c7a08d08db3305a7cfd3a6438beda48b0791eaac Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 22:34:49 -0500 Subject: add support for unofficial updates which suffix the official version number with a pre-release label (#192) --- .../Framework/Models/IncompatibleMod.cs | 23 ++++++++++++++++++++++ src/StardewModdingAPI/Program.cs | 18 ++++++++--------- src/StardewModdingAPI/StardewModdingAPI.data.json | 12 +++++++---- 3 files changed, 40 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs b/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs index f3ee7d0b..9bf06552 100644 --- a/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs +++ b/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs @@ -1,3 +1,5 @@ +using System.Text.RegularExpressions; + namespace StardewModdingAPI.Framework.Models { /// Contains abstract metadata about an incompatible mod. @@ -20,5 +22,26 @@ namespace StardewModdingAPI.Framework.Models /// The URL the user can check for an unofficial updated version. public string UnofficialUpdateUrl { get; set; } + + /// A regular expression matching version strings to consider compatible, even if they technically precede . + public string ForceCompatibleVersion { get; set; } + + + /********* + ** Public methods + *********/ + /// Get whether the specified version is compatible according to this metadata. + /// The current version of the matching mod. + public bool IsCompatible(ISemanticVersion version) + { + ISemanticVersion incompatibleVersion = new SemanticVersion(this.Version); + + // allow newer versions + if (version.IsNewerThan(incompatibleVersion)) + return true; + + // allow versions matching override + return !string.IsNullOrWhiteSpace(this.ForceCompatibleVersion) && Regex.IsMatch(version.ToString(), this.ForceCompatibleVersion, RegexOptions.IgnoreCase); + } } } \ No newline at end of file diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index c3bd1646..0c232b1d 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -384,23 +384,23 @@ namespace StardewModdingAPI } // validate known incompatible mods - IncompatibleMod incompatible; - if (incompatibleMods.TryGetValue(manifest.UniqueID ?? $"{manifest.Name}|{manifest.Author}|{manifest.EntryDll}", out incompatible)) + IncompatibleMod compatibility; + if (incompatibleMods.TryGetValue(manifest.UniqueID ?? $"{manifest.Name}|{manifest.Author}|{manifest.EntryDll}", out compatibility)) { - if (!manifest.Version.IsNewerThan(new SemanticVersion(incompatible.Version))) + if (!compatibility.IsCompatible(manifest.Version)) { - string warning = $"Skipped {incompatible.Name} ≤v{incompatible.Version} because this version is not compatible with the latest version of the game. Please check for a newer version of the mod here:"; - if (!string.IsNullOrWhiteSpace(incompatible.UpdateUrl)) - warning += $"{Environment.NewLine}- official mod: {incompatible.UpdateUrl}"; - if (!string.IsNullOrWhiteSpace(incompatible.UnofficialUpdateUrl)) - warning += $"{Environment.NewLine}- unofficial update: {incompatible.UnofficialUpdateUrl}"; + string warning = $"Skipped {compatibility.Name} ≤v{compatibility.Version} because this version is not compatible with the latest version of the game. Please check for a newer version of the mod here:"; + if (!string.IsNullOrWhiteSpace(compatibility.UpdateUrl)) + warning += $"{Environment.NewLine}- official mod: {compatibility.UpdateUrl}"; + if (!string.IsNullOrWhiteSpace(compatibility.UnofficialUpdateUrl)) + warning += $"{Environment.NewLine}- unofficial update: {compatibility.UnofficialUpdateUrl}"; Program.Monitor.Log(warning, LogLevel.Error); continue; } } - // validate version + // validate SMAPI version if (!string.IsNullOrWhiteSpace(manifest.MinimumApiVersion)) { try diff --git a/src/StardewModdingAPI/StardewModdingAPI.data.json b/src/StardewModdingAPI/StardewModdingAPI.data.json index 2f1d67e8..49b45018 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.data.json +++ b/src/StardewModdingAPI/StardewModdingAPI.data.json @@ -11,27 +11,31 @@ This file contains advanced metadata for SMAPI. You shouldn't change this file. "Name": "Better Sprinklers", "Version": "2.1", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/41", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031", + "ForceCompatibleVersion": "^2.1-EntoPatch" }, { "ID": "SPDChestLabel", "Name": "Chest Label System", "Version": "1.5", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/242", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031", + "ForceCompatibleVersion": "^1.5-EntoPatch" }, { "ID": "CJBCheatsMenu", "Name": "CJB Cheats Menu", "Version": "1.12", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/4", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031", + "ForceCompatibleVersion": "^1.12-EntoPatch" }, { "ID": "CJBItemSpawner", "Name": "CJB Item Spawner", "Version": "1.5", "UpdateUrl": "http://www.nexusmods.com/stardewvalley/mods/93", - "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031" + "UnofficialUpdateUrl": "http://community.playstarbound.com/threads/125031", + "ForceCompatibleVersion": "^1.5-EntoPatch" } ] -- cgit From 1fdc0c0b3586bd02119a8d55baf103acf63e86d5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 23 Dec 2016 11:20:06 -0500 Subject: catch errors when reading metadata file just in case (#192) --- src/StardewModdingAPI/Program.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 0c232b1d..a48fa716 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -316,9 +316,18 @@ namespace StardewModdingAPI AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => modAssemblyLoader.ResolveAssembly(e.Name); // get known incompatible mods - IDictionary incompatibleMods = File.Exists(Constants.ApiModMetadataPath) - ? JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiModMetadataPath)).ToDictionary(p => p.ID, p => p) - : new Dictionary(0); + IDictionary incompatibleMods; + try + { + incompatibleMods = File.Exists(Constants.ApiModMetadataPath) + ? JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiModMetadataPath)).ToDictionary(p => p.ID, p => p) + : new Dictionary(0); + } + catch (Exception ex) + { + incompatibleMods = new Dictionary(); + Program.Monitor.Log($"Couldn't read metadata file at {Constants.ApiModMetadataPath}. SMAPI will still run, but some features may be disabled.\n{ex}", LogLevel.Warn); + } // load mods foreach (string directory in Directory.GetDirectories(Program.ModPath)) -- cgit From 8416c9009e37def03ff894dc660dec34a05c0558 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 23 Dec 2016 12:36:03 -0500 Subject: increase deprecation levels for less-used deprecated code --- release-notes.md | 1 + src/StardewModdingAPI/Inheritance/SObject.cs | 2 +- src/StardewModdingAPI/LogWriter.cs | 2 +- src/StardewModdingAPI/Program.cs | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 11f393bd..9eeae111 100644 --- a/release-notes.md +++ b/release-notes.md @@ -11,6 +11,7 @@ For players: For developers: * Deprecated `Version` in favour of `SemanticVersion`. _This new implementation is [semver 2.0](http://semver.org/)-compliant, introduces `NewerThan(version)` and `OlderThan(version)` convenience methods, adds support for parsing a version string into a `SemanticVersion`, and fixes various bugs with the former implementation._ + * Increased deprecation levels for `SObject`, `Extensions`, `LogWriter` (not `Log`), `SPlayer`, and `Mod.Entry(ModHelper)` (not `Mod.Entry(IModHelper)`). ## 1.4 See [log](https://github.com/Pathoschild/SMAPI/compare/1.3...1.4). diff --git a/src/StardewModdingAPI/Inheritance/SObject.cs b/src/StardewModdingAPI/Inheritance/SObject.cs index 4a218f33..eae5424d 100644 --- a/src/StardewModdingAPI/Inheritance/SObject.cs +++ b/src/StardewModdingAPI/Inheritance/SObject.cs @@ -49,7 +49,7 @@ namespace StardewModdingAPI.Inheritance *********/ public SObject() { - Program.DeprecationManager.Warn(nameof(SObject), "0.39.3", DeprecationLevel.Notice); + Program.DeprecationManager.Warn(nameof(SObject), "0.39.3", DeprecationLevel.Info); this.name = "Modded Item Name"; this.Description = "Modded Item Description"; diff --git a/src/StardewModdingAPI/LogWriter.cs b/src/StardewModdingAPI/LogWriter.cs index 11bcf5f3..058fa649 100644 --- a/src/StardewModdingAPI/LogWriter.cs +++ b/src/StardewModdingAPI/LogWriter.cs @@ -55,7 +55,7 @@ namespace StardewModdingAPI /// Raise a deprecation warning. private void WarnDeprecated() { - Program.DeprecationManager.Warn($"the {nameof(LogWriter)} class", "1.0", DeprecationLevel.Notice); + Program.DeprecationManager.Warn($"the {nameof(LogWriter)} class", "1.0", DeprecationLevel.Info); } } } \ No newline at end of file diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index a48fa716..090098ca 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -542,9 +542,9 @@ namespace StardewModdingAPI // raise deprecation warning for old Entry() methods if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); + Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.Notice); if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + Program.DeprecationManager.Warn(manifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}({nameof(ModHelper)}) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.1", DeprecationLevel.Info); } catch (Exception ex) { -- cgit From b75d86e7cc19f9bc961abb475f22e8f2b059533c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 23 Dec 2016 12:43:42 -0500 Subject: update for SMAPI 1.5 release --- release-notes.md | 9 +++++---- src/GlobalAssemblyInfo.cs | 4 ++-- src/StardewModdingAPI/Constants.cs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/release-notes.md b/release-notes.md index 9eeae111..a11d9ea8 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,16 +1,17 @@ # Release notes ## 1.5 -See [log](https://github.com/Pathoschild/SMAPI/compare/stable...develop). +See [log](https://github.com/Pathoschild/SMAPI/compare/1.4...1.5). For players: - * Added option to disable update checks. + * Added an option to disable update checks. * SMAPI will now show a friendly error with update links when you try to use a known incompatible mod version. - * Fixed error when a mod uses the new reflection API on a missing field or method. + * Fixed an error when a mod uses the new reflection API on a missing field or method. + * Fixed an issue where mods weren't notified of a menu change if it changed while SMAPI was still notifying mods of the previous change. For developers: * Deprecated `Version` in favour of `SemanticVersion`. - _This new implementation is [semver 2.0](http://semver.org/)-compliant, introduces `NewerThan(version)` and `OlderThan(version)` convenience methods, adds support for parsing a version string into a `SemanticVersion`, and fixes various bugs with the former implementation._ + _This new implementation is [semver 2.0](http://semver.org/)-compliant, introduces `NewerThan(version)` and `OlderThan(version)` convenience methods, adds support for parsing a version string into a `SemanticVersion`, and fixes various bugs with the former implementation. This also replaces `Manifest` with `IManifest`._ * Increased deprecation levels for `SObject`, `Extensions`, `LogWriter` (not `Log`), `SPlayer`, and `Mod.Entry(ModHelper)` (not `Mod.Entry(IModHelper)`). ## 1.4 diff --git a/src/GlobalAssemblyInfo.cs b/src/GlobalAssemblyInfo.cs index 0dfb42bb..7f1fa401 100644 --- a/src/GlobalAssemblyInfo.cs +++ b/src/GlobalAssemblyInfo.cs @@ -2,5 +2,5 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.4.0.0")] -[assembly: AssemblyFileVersion("1.4.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] \ No newline at end of file diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 4f7a0c6e..a79fd382 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -30,7 +30,7 @@ namespace StardewModdingAPI public static readonly Version Version = (Version)Constants.ApiVersion; /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion => new Version(1, 4, 0, null, suppressDeprecationWarning: true); + public static ISemanticVersion ApiVersion => new Version(1, 5, 0, null, suppressDeprecationWarning: true); /// The minimum supported version of Stardew Valley. public const string MinimumGameVersion = "1.1"; -- cgit