using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
using StardewModdingAPI.Toolkit.Framework.GameScanning;
using StardewModdingAPI.Toolkit.Framework.ModData;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
using StardewModdingAPI.Toolkit.Framework.UpdateData;
using StardewModdingAPI.Toolkit.Serialization;
namespace StardewModdingAPI.Toolkit
{
/// A convenience wrapper for the various tools.
public class ModToolkit
{
/*********
** Fields
*********/
/// The default HTTP user agent for the toolkit.
private readonly string UserAgent;
/// Maps vendor keys (like Nexus) to their mod URL template (where {0} is the mod ID). This doesn't affect update checks, which defer to the remote web API.
private readonly Dictionary VendorModUrls = new()
{
[ModSiteKey.Chucklefish] = "https://community.playstarbound.com/resources/{0}",
[ModSiteKey.GitHub] = "https://github.com/{0}/releases",
[ModSiteKey.Nexus] = "https://www.nexusmods.com/stardewvalley/mods/{0}"
};
/*********
** Accessors
*********/
/// Encapsulates SMAPI's JSON parsing.
public JsonHelper JsonHelper { get; } = new();
/*********
** Public methods
*********/
/// Construct an instance.
public ModToolkit()
{
ISemanticVersion version = new SemanticVersion(this.GetType().Assembly.GetName().Version!);
this.UserAgent = $"SMAPI Mod Handler Toolkit/{version}";
}
/// Find valid Stardew Valley install folders.
/// This checks default game locations, and on Windows checks the Windows registry for GOG/Steam install data. A folder is considered 'valid' if it contains the Stardew Valley executable for the current OS.
public IEnumerable GetGameFolders()
{
return new GameScanner().Scan();
}
/// Extract mod metadata from the wiki compatibility list.
public async Task GetWikiCompatibilityListAsync()
{
WikiClient client = new(this.UserAgent);
return await client.FetchModsAsync();
}
/// Get SMAPI's internal mod database.
/// The file path for the SMAPI metadata file.
public ModDatabase GetModDatabase(string metadataPath)
{
MetadataModel metadata = JsonConvert.DeserializeObject(File.ReadAllText(metadataPath));
ModDataRecord[] records = metadata.ModData.Select(pair => new ModDataRecord(pair.Key, pair.Value)).ToArray();
return new ModDatabase(records, this.GetUpdateUrl);
}
/// Extract information about all mods in the given folder.
/// The root folder containing mods.
/// Whether to match file paths case-insensitively, even on Linux.
public IEnumerable GetModFolders(string rootPath, bool useCaseInsensitiveFilePaths)
{
return new ModScanner(this.JsonHelper).GetModFolders(rootPath, useCaseInsensitiveFilePaths);
}
/// Extract information about all mods in the given folder.
/// The root folder containing mods. Only the will be searched, but this field allows it to be treated as a potential mod folder of its own.
/// The mod path to search.
/// Whether to match file paths case-insensitively, even on Linux.
public IEnumerable GetModFolders(string rootPath, string modPath, bool useCaseInsensitiveFilePaths)
{
return new ModScanner(this.JsonHelper).GetModFolders(rootPath, modPath, useCaseInsensitiveFilePaths);
}
/// Get an update URL for an update key (if valid).
/// The update key.
public string? GetUpdateUrl(string updateKey)
{
UpdateKey parsed = UpdateKey.Parse(updateKey);
if (!parsed.LooksValid)
return null;
if (this.VendorModUrls.TryGetValue(parsed.Site, out string? urlTemplate))
return string.Format(urlTemplate, parsed.ID);
return null;
}
}
}