From a6071feaf84518c436fba0d148e3ea7d547663da Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 2 Nov 2017 01:34:21 -0400 Subject: fix custom asset loads failing on Linux/Mac (#383) --- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 22 +---------- src/SMAPI/Framework/SContentManager.cs | 52 ++++++++++++------------- 2 files changed, 28 insertions(+), 46 deletions(-) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index be9594ee..7665eb78 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -26,9 +26,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The absolute path to the mod folder. private readonly string ModFolderPath; - /// The path to the mod's folder, relative to the game's content folder (e.g. "../Mods/ModName"). - private readonly string ModFolderPathFromContent; - /// The friendly mod name for use in errors. private readonly string ModName; @@ -73,7 +70,6 @@ namespace StardewModdingAPI.Framework.ModHelpers this.ContentManager = contentManager; this.ModFolderPath = modFolderPath; this.ModName = modName; - this.ModFolderPathFromContent = this.ContentManager.GetRelativePath(modFolderPath); this.Monitor = monitor; } @@ -102,7 +98,7 @@ namespace StardewModdingAPI.Framework.ModHelpers throw GetContentError($"there's no matching file at path '{file.FullName}'."); // get asset path - string assetName = this.GetModAssetPath(key, file.FullName); + string assetName = this.ContentManager.GetAssetNameFromFilePath(file.FullName); // try cache if (this.ContentManager.IsLoaded(assetName)) @@ -151,7 +147,7 @@ namespace StardewModdingAPI.Framework.ModHelpers case ContentSource.ModFolder: FileInfo file = this.GetModFile(key); - return this.ContentManager.NormaliseAssetName(this.GetModAssetPath(key, file.FullName)); + return this.ContentManager.NormaliseAssetName(this.ContentManager.GetAssetNameFromFilePath(file.FullName)); default: throw new NotSupportedException($"Unknown content source '{source}'."); @@ -356,19 +352,5 @@ namespace StardewModdingAPI.Framework.ModHelpers // get file return new FileInfo(path); } - - /// Get the asset path which loads a mod folder through a content manager. - /// The file path relative to the mod's folder. - /// The absolute file path. - private string GetModAssetPath(string localPath, string absolutePath) - { -#if SMAPI_FOR_WINDOWS - // XNA doesn't allow absolute asset paths, so get a path relative to the content folder - return Path.Combine(this.ModFolderPathFromContent, localPath); -#else - // MonoGame is weird about relative paths on Mac, but allows absolute paths - return absolutePath; -#endif - } } } diff --git a/src/SMAPI/Framework/SContentManager.cs b/src/SMAPI/Framework/SContentManager.cs index a755a6df..524b2d17 100644 --- a/src/SMAPI/Framework/SContentManager.cs +++ b/src/SMAPI/Framework/SContentManager.cs @@ -102,7 +102,7 @@ namespace StardewModdingAPI.Framework this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); this.Cache = new ContentCache(this, reflection, SContentManager.PossiblePathSeparators, SContentManager.PreferredPathSeparator); this.GetKeyLocale = reflection.GetPrivateMethod(this, "languageCode"); - this.ModContentPrefix = this.GetRelativePath(Constants.ModPath); + this.ModContentPrefix = this.GetAssetNameFromFilePath(Constants.ModPath); // get asset data this.CoreAssets = new CoreAssets(this.NormaliseAssetName); @@ -140,19 +140,17 @@ namespace StardewModdingAPI.Framework throw new ArgumentException("The asset key or local path contains invalid characters."); } - /// Get a directory path relative to the content root. - /// The target file path. - public string GetRelativePath(string targetPath) + /// Convert an absolute file path into a appropriate asset name. + /// The absolute path to the file. + public string GetAssetNameFromFilePath(string absolutePath) { - // convert to URIs - Uri from = new Uri(this.FullRootDirectory + "/"); - Uri to = new Uri(targetPath + "/"); - if (from.Scheme != to.Scheme) - throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{this.FullRootDirectory}'."); - - // get relative path - return Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()) - .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar); // use correct separator for platform +#if SMAPI_FOR_WINDOWS + // XNA doesn't allow absolute asset paths, so get a path relative to the content folder + return this.GetRelativePath(absolutePath); +#else + // MonoGame is weird about relative paths on Mac, but allows absolute paths + return absolutePath; +#endif } /**** @@ -395,6 +393,21 @@ namespace StardewModdingAPI.Framework /**** ** Asset name/key handling ****/ + /// Get a directory or file path relative to the content root. + /// The target file path. + private string GetRelativePath(string targetPath) + { + // convert to URIs + Uri from = new Uri(this.FullRootDirectory + "/"); + Uri to = new Uri(targetPath + "/"); + if (from.Scheme != to.Scheme) + throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{this.FullRootDirectory}'."); + + // get relative path + return Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()) + .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar); // use correct separator for platform + } + /// Get the locale codes (like ja-JP) used in asset keys. /// Simplifies access to private game code. private IDictionary GetKeyLocales(Reflector reflection) @@ -551,19 +564,6 @@ namespace StardewModdingAPI.Framework return file; } - /// Get a file from the game's content folder. - /// The asset key. - private FileInfo GetContentFolderFile(string key) - { - // get file path - string path = Path.Combine(this.FullRootDirectory, key); - if (!path.EndsWith(".xnb")) - path += ".xnb"; - - // get file - return new FileInfo(path); - } - /// Load the initial asset from the registered . /// The basic asset metadata. /// Returns the loaded asset metadata, or null if no loader matched. -- cgit From 3a832b99bf3f82cfe39de776b5e15db6c8ddff1a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Nov 2017 14:54:32 -0500 Subject: add date.DaysSinceStart property, add unit tests, update release notes (#390) --- src/SMAPI/Framework/Models/ManifestDependency.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/Models/ManifestDependency.cs b/src/SMAPI/Framework/Models/ManifestDependency.cs index 5646b335..97f0775a 100644 --- a/src/SMAPI/Framework/Models/ManifestDependency.cs +++ b/src/SMAPI/Framework/Models/ManifestDependency.cs @@ -15,6 +15,7 @@ namespace StardewModdingAPI.Framework.Models /// Whether the dependency must be installed to use the mod. public bool IsRequired { get; set; } + /********* ** Public methods *********/ -- cgit From 5ae28b2a8caf764e0df0e3bfeca8941db5f4be87 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 27 Nov 2017 22:19:23 -0500 Subject: fix error when a mod has an invalid filename in the EntryDLL manifest field (#402) --- src/SMAPI/Framework/ModLoading/ModResolver.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index d0ef1b08..9802d9e9 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -142,6 +142,18 @@ namespace StardewModdingAPI.Framework.ModLoading continue; } + // validate DLL value + if (string.IsNullOrWhiteSpace(mod.Manifest.EntryDll)) + { + mod.SetStatus(ModMetadataStatus.Failed, "its manifest has no EntryDLL field."); + continue; + } + if (mod.Manifest.EntryDll.Intersect(Path.GetInvalidFileNameChars()).Any()) + { + mod.SetStatus(ModMetadataStatus.Failed, $"its manifest has invalid filename '{mod.Manifest.EntryDll}' for the EntryDLL field."); + continue; + } + // validate DLL path string assemblyPath = Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll); if (!File.Exists(assemblyPath)) -- cgit From 72a02c56d51f5e5b0e8e2fc7db59e1f0e6d93d5c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 2 Dec 2017 14:27:03 -0500 Subject: add NormaliseAssetName content helper method (#404) --- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/SMAPI/Framework') diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 7665eb78..4a1d3853 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Contracts; using System.IO; using System.Linq; using Microsoft.Xna.Framework.Content; @@ -134,6 +135,14 @@ namespace StardewModdingAPI.Framework.ModHelpers } } + /// Normalise an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like on generated asset names, and isn't necessary when passing asset names into other content helper methods. + /// The asset key. + [Pure] + public string NormaliseAssetName(string assetName) + { + return this.ContentManager.NormaliseAssetName(assetName); + } + /// Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists. /// The asset key to fetch (if the is ), or the local path to a content file relative to the mod folder. /// Where to search for a matching content asset. -- cgit