using System; using System.IO; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using xTile; namespace StardewModdingAPI.Framework { /// Manages access to a content pack's metadata and files. internal class ContentPack : IContentPack { /********* ** Fields *********/ /// Provides an API for loading content assets. private readonly IContentHelper Content; /// Encapsulates SMAPI's JSON file parsing. private readonly JsonHelper JsonHelper; /********* ** Accessors *********/ /// public string DirectoryPath { get; } /// public IManifest Manifest { get; } /// public ITranslationHelper Translation { get; } /********* ** 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. /// Provides translations stored in the content pack's i18n folder. /// Encapsulates SMAPI's JSON file parsing. public ContentPack(string directoryPath, IManifest manifest, IContentHelper content, ITranslationHelper translation, JsonHelper jsonHelper) { this.DirectoryPath = directoryPath; this.Manifest = manifest; this.Content = content; this.Translation = translation; this.JsonHelper = jsonHelper; } /// public bool HasFile(string path) { this.AssertRelativePath(path, nameof(this.HasFile)); return File.Exists(Path.Combine(this.DirectoryPath, path)); } /// public TModel ReadJsonFile(string path) where TModel : class { this.AssertRelativePath(path, nameof(this.ReadJsonFile)); path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model) ? model : null; } /// public void WriteJsonFile(string path, TModel data) where TModel : class { this.AssertRelativePath(path, nameof(this.WriteJsonFile)); path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); this.JsonHelper.WriteJsonFile(path, data); } /// public T LoadAsset(string key) { return this.Content.Load(key, ContentSource.ModFolder); } /// public string GetActualAssetKey(string key) { return this.Content.GetActualAssetKey(key, ContentSource.ModFolder); } /********* ** Private methods *********/ /// Assert that a relative path was passed it to a content pack method. /// The path to check. /// The name of the method which was invoked. private void AssertRelativePath(string path, string methodName) { if (!PathUtilities.IsSafeRelativePath(path)) throw new InvalidOperationException($"You must call {nameof(IContentPack)}.{methodName} with a relative path."); } } }