add version info to ModMetadata, change update checking to consider preview versions

This commit is contained in:
Dan Volchek 2018-06-10 13:15:53 -07:00
parent 235d67623d
commit 5b9e365b5d
3 changed files with 60 additions and 7 deletions

View File

@ -45,6 +45,14 @@ namespace StardewModdingAPI.Framework
/// <summary>Whether the mod is a content pack.</summary> /// <summary>Whether the mod is a content pack.</summary>
bool IsContentPack { get; } bool IsContentPack { get; }
/// <summary>The latest version of the mod.</summary>
ISemanticVersion LatestVersion { get; }
/// <summary>The latest preview version of the mod, if any.</summary>
ISemanticVersion LatestPreviewVersion { get; }
/// <summary>The error checking for updates for this mod, if any.</summary>
string UpdateCheckError { get; }
/********* /*********
** Public methods ** Public methods
@ -72,6 +80,15 @@ namespace StardewModdingAPI.Framework
/// <param name="api">The mod-provided API.</param> /// <param name="api">The mod-provided API.</param>
IModMetadata SetApi(object api); IModMetadata SetApi(object api);
/// <summary>Set the update status, indicating no errors happened.</summary>
/// <param name="latestVersion">The latest version.</param>
/// <param name="latestPreviewVersion">The latest preview version.</param>
IModMetadata SetUpdateStatus(ISemanticVersion latestVersion, ISemanticVersion latestPreviewVersion);
/// <summary>Set the update status, indicating an error happened.</summary>
/// <param name="updateCheckError">The error checking for updates, if any.</param>
IModMetadata SetUpdateStatus(string updateCheckError);
/// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary> /// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary>
bool HasManifest(); bool HasManifest();

View File

@ -43,6 +43,15 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <summary>The mod-provided API (if any).</summary> /// <summary>The mod-provided API (if any).</summary>
public object Api { get; private set; } public object Api { get; private set; }
/// <summary>The latest version of the mod.</summary>
public ISemanticVersion LatestVersion { get; private set; }
/// <summary>The latest preview version of the mod, if any.</summary>
public ISemanticVersion LatestPreviewVersion { get; private set; }
/// <summary>The error checking for updates for this mod, if any.</summary>
public string UpdateCheckError { get; private set; }
/// <summary>Whether the mod is a content pack.</summary> /// <summary>Whether the mod is a content pack.</summary>
public bool IsContentPack => this.Manifest?.ContentPackFor != null; public bool IsContentPack => this.Manifest?.ContentPackFor != null;
@ -115,6 +124,24 @@ namespace StardewModdingAPI.Framework.ModLoading
return this; return this;
} }
/// <summary>Set the update status.</summary>
/// <param name="latestVersion">The latest version.</param>
/// <param name="latestPreviewVersion">The latest preview version.</param>
public IModMetadata SetUpdateStatus(ISemanticVersion latestVersion, ISemanticVersion latestPreviewVersion)
{
this.LatestVersion = latestVersion;
this.LatestPreviewVersion = latestPreviewVersion;
return this;
}
// <summary>Set the update status, indicating an error happened.</summary>
/// <param name="updateCheckError">The error checking for updates, if any.</param>
public IModMetadata SetUpdateStatus(string updateCheckError)
{
this.UpdateCheckError = updateCheckError;
return this;
}
/// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary> /// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary>
public bool HasManifest() public bool HasManifest()
{ {

View File

@ -662,7 +662,7 @@ namespace StardewModdingAPI
.ToArray(); .ToArray();
// extract latest versions // extract latest versions
IDictionary<IModMetadata, ModInfoModel> updatesByMod = new Dictionary<IModMetadata, ModInfoModel>(); IDictionary<IModMetadata, Tuple<ModInfoModel, bool>> updatesByMod = new Dictionary<IModMetadata, Tuple<ModInfoModel, bool>>();
foreach (var result in results) foreach (var result in results)
{ {
IModMetadata mod = result.Mod; IModMetadata mod = result.Mod;
@ -671,6 +671,7 @@ namespace StardewModdingAPI
// handle error // handle error
if (remoteInfo.Error != null) if (remoteInfo.Error != null)
{ {
mod.SetUpdateStatus(remoteInfo.Error);
this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: {remoteInfo.Error}", LogLevel.Trace); this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: {remoteInfo.Error}", LogLevel.Trace);
continue; continue;
} }
@ -679,17 +680,25 @@ namespace StardewModdingAPI
ISemanticVersion localVersion = mod.DataRecord?.GetLocalVersionForUpdateChecks(mod.Manifest.Version) ?? mod.Manifest.Version; ISemanticVersion localVersion = mod.DataRecord?.GetLocalVersionForUpdateChecks(mod.Manifest.Version) ?? mod.Manifest.Version;
if (!SemanticVersion.TryParse(mod.DataRecord?.GetRemoteVersionForUpdateChecks(remoteInfo.Version) ?? remoteInfo.Version, out ISemanticVersion remoteVersion)) if (!SemanticVersion.TryParse(mod.DataRecord?.GetRemoteVersionForUpdateChecks(remoteInfo.Version) ?? remoteInfo.Version, out ISemanticVersion remoteVersion))
{ {
this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: Mod has invalid version {remoteInfo.Version}", LogLevel.Trace); string errorInfo = $"Mod has invalid version {remoteInfo.Version}";
mod.SetUpdateStatus(errorInfo);
this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: {errorInfo}", LogLevel.Trace);
continue; continue;
} }
SemanticVersion.TryParse(remoteInfo.PreviewVersion, out ISemanticVersion remotePreviewVersion);
mod.SetUpdateStatus(remoteVersion, remotePreviewVersion);
// compare versions // compare versions
bool isUpdate = remoteVersion.IsNewerThan(localVersion); bool isNonPreviewUpdate = remoteVersion.IsNewerThan(localVersion);
this.VerboseLog($" {mod.DisplayName} ({result.Key}): {(isUpdate ? $"{mod.Manifest.Version}{(!localVersion.Equals(mod.Manifest.Version) ? $" [{localVersion}]" : "")} => {remoteInfo.Version}" : "okay")}."); bool isUpdate = isNonPreviewUpdate ||
(localVersion.IsNewerThan(remoteVersion) && remotePreviewVersion.IsNewerThan(localVersion));
this.VerboseLog($" {mod.DisplayName} ({result.Key}): {(isUpdate ? $"{mod.Manifest.Version}{(!localVersion.Equals(mod.Manifest.Version) ? $" [{localVersion}]" : "")} => {(isNonPreviewUpdate ? remoteInfo.Version : remoteInfo.PreviewVersion)}" : "okay")}.");
if (isUpdate) if (isUpdate)
{ {
if (!updatesByMod.TryGetValue(mod, out ModInfoModel other) || remoteVersion.IsNewerThan(other.Version)) if (!updatesByMod.TryGetValue(mod, out Tuple<ModInfoModel, bool> other) || (isNonPreviewUpdate ? remoteVersion : remotePreviewVersion).IsNewerThan(other.Item2 ? other.Item1.PreviewVersion : other.Item1.Version))
updatesByMod[mod] = remoteInfo; updatesByMod[mod] = new Tuple<ModInfoModel, bool>(remoteInfo, !isNonPreviewUpdate);
} }
} }
@ -699,7 +708,7 @@ namespace StardewModdingAPI
this.Monitor.Newline(); this.Monitor.Newline();
this.Monitor.Log($"You can update {updatesByMod.Count} mod{(updatesByMod.Count != 1 ? "s" : "")}:", LogLevel.Alert); this.Monitor.Log($"You can update {updatesByMod.Count} mod{(updatesByMod.Count != 1 ? "s" : "")}:", LogLevel.Alert);
foreach (var entry in updatesByMod.OrderBy(p => p.Key.DisplayName)) foreach (var entry in updatesByMod.OrderBy(p => p.Key.DisplayName))
this.Monitor.Log($" {entry.Key.DisplayName} {entry.Value.Version}: {entry.Value.Url}", LogLevel.Alert); this.Monitor.Log($" {entry.Key.DisplayName} {(entry.Value.Item2 ? entry.Value.Item1.PreviewVersion : entry.Value.Item1.Version)}: {entry.Value.Item1.Url}", LogLevel.Alert);
} }
else else
this.Monitor.Log(" All mods up to date.", LogLevel.Trace); this.Monitor.Log(" All mods up to date.", LogLevel.Trace);