using System;
using System.IO;
using StardewModdingAPI.Framework.ModHelpers;
using StardewModdingAPI.Toolkit.Serialization;
using StardewModdingAPI.Toolkit.Utilities;
using StardewModdingAPI.Toolkit.Utilities.PathLookups;
namespace StardewModdingAPI.Framework
{
/// Manages access to a content pack's metadata and files.
internal class ContentPack : IContentPack
{
/*********
** Fields
*********/
/// Encapsulates SMAPI's JSON file parsing.
private readonly JsonHelper JsonHelper;
/// A lookup for files within the .
private readonly IFileLookup FileLookup;
/*********
** Accessors
*********/
///
public string DirectoryPath { get; }
///
public IManifest Manifest { get; }
///
public ITranslationHelper Translation => this.TranslationImpl;
///
public IModContentHelper ModContent { get; }
/// The underlying translation helper.
internal TranslationHelper TranslationImpl { get; set; }
/*********
** Public methods
*********/
/// Construct an instance.
/// The full path to the content pack's folder.
/// The content pack's manifest.
/// Provides an API for loading content assets from the content pack's folder.
/// Provides translations stored in the content pack's i18n folder.
/// Encapsulates SMAPI's JSON file parsing.
/// A lookup for files within the .
public ContentPack(string directoryPath, IManifest manifest, IModContentHelper content, TranslationHelper translation, JsonHelper jsonHelper, IFileLookup fileLookup)
{
this.DirectoryPath = directoryPath;
this.Manifest = manifest;
this.ModContent = content;
this.TranslationImpl = translation;
this.JsonHelper = jsonHelper;
this.FileLookup = fileLookup;
}
///
public bool HasFile(string path)
{
path = PathUtilities.NormalizePath(path);
return this.GetFile(path).Exists;
}
///
public TModel? ReadJsonFile(string path) where TModel : class
{
path = PathUtilities.NormalizePath(path);
FileInfo file = this.GetFile(path);
return file.Exists && this.JsonHelper.ReadJsonFileIfExists(file.FullName, out TModel? model)
? model
: null;
}
///
public void WriteJsonFile(string path, TModel data) where TModel : class
{
path = PathUtilities.NormalizePath(path);
FileInfo file = this.GetFile(path);
bool didExist = file.Exists;
this.JsonHelper.WriteJsonFile(file.FullName, data);
if (!didExist)
{
this.FileLookup.Add(
Path.GetRelativePath(this.DirectoryPath, file.FullName)
);
}
}
#if SMAPI_DEPRECATED
///
[Obsolete($"Use {nameof(IContentPack.ModContent)}.{nameof(IModContentHelper.Load)} instead. This method will be removed in SMAPI 4.0.0.")]
public T LoadAsset(string key)
where T : notnull
{
return this.ModContent.Load(key);
}
///
[Obsolete($"Use {nameof(IContentPack.ModContent)}.{nameof(IModContentHelper.GetInternalAssetName)} instead. This method will be removed in SMAPI 4.0.0.")]
public string GetActualAssetKey(string key)
{
return this.ModContent.GetInternalAssetName(key).Name;
}
#endif
/*********
** Private methods
*********/
/// Get the underlying file info.
/// The normalized file path relative to the content pack directory.
private FileInfo GetFile(string relativePath)
{
if (!PathUtilities.IsSafeRelativePath(relativePath))
throw new InvalidOperationException($"You must call {nameof(IContentPack)} methods with a relative path.");
return this.FileLookup.GetFile(relativePath);
}
}
}