Platonymous / Stardew-Valley-Mods

A collection of mods for Stardew Valley
GNU General Public License v3.0
108 stars 117 forks source link

[Portraiture] Content packs do not appear to work #152

Open rikai opened 5 months ago

rikai commented 5 months ago

Hello,

I followed the instructions listed on the Portraiture mod description for creating a content pack as listed here:

Create the portrait-spritesheets for the NPCs you want to replace, they should idealy be png files. The aspect ratio of the spritesheet and the layout of the faces needs to be the same as in the original and all faces need to be the same size, which size is up to you. The only difference to the original is that every spritesheet needs to have a least 2 faces (can be the same) even if the original only has one.
The new spritesheets needs to be saved with the same name as the original eg. "Abigail.png". Copy all your spritesheets into one folder and give it a unique name like "MyPortraitCollection". If you don't need it to be a contentpack, your done at this point.

Otherwise you need to add a manifest.json file either next to the portraits, or in a new folder called smth. like "[P] MyPortraits" with the folder that includes the spritesheets copied inside it. The manifest would look like this:

{
    "Name": "My Portrait Mod",
    "Author": "Me",
    "Version": "1.3",
    "Description": "My Portraits",
    "UniqueID": "My.Portraits",
    "UpdateKeys": [ "Nexus:00000" ],
    "ContentPackFor": {
        "UniqueID": "Platonymous.Portraiture"
    },
    "Dependencies": [
        {
            "UniqueID": "Platonymous.Portraiture",
            "IsRequired": true
        },
    ]
}

In the folder containing the manifest I created a "Portraits" folder that contains the Portraits. These portraits are confirmed to work using the non-content pack method without issue. I used the below manifest for testing using a set of portraits from another mod:

{
    "Name": "Anime Portraiture",
    "Author": "a",
    "Version": "1.0.0",
    "Description": "b",
    "UniqueID": "a.b",
    "UpdateKeys": [ "Nexus: 00001" ],
    "ContentPackFor": {
        "UniqueID": "Platonymous.Portraiture"
    },
    "Dependencies": [
        {
            "UniqueID": "Platonymous.Portraiture",
            "IsRequired": true
        }
    ]
}

image

The content pack is recognized and loaded as a content pack as seen above, however, an error is received once the game loads:

[16:28:19 ERROR Portraiture] This mod failed in the GameLoop.SaveLoaded event. Technical details: 
SContentLoadException: Failed loading asset 'Abigail.png' from SMAPI\a.b: the specified path doesn't exist.
   at StardewModdingAPI.Framework.ContentManagers.ModContentManager.ThrowLoadError(IAssetName assetName, ContentLoadErrorType errorType, String reasonPhrase, Exception exception) in SMAPI\Framework\ContentManagers\ModContentManager.cs:line 319
   at StardewModdingAPI.Framework.ContentManagers.ModContentManager.LoadExact[T](IAssetName assetName, Boolean useCache) in SMAPI\Framework\ContentManagers\ModContentManager.cs:line 114
   at StardewModdingAPI.Framework.ModHelpers.ModContentHelper.Load[T](String relativePath) in SMAPI\Framework\ModHelpers\ModContentHelper.cs:line 57
   at Portraiture.TextureLoader.loadAllPortraits() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\TextureLoader.cs:line 219
   at Portraiture.TextureLoader.loadTextures() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\TextureLoader.cs:line 32
   at Portraiture.PortraitureMod.Initialize() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\PortraitureMod.cs:line 112
   at Portraiture.PortraitureMod.OnSaveLoaded(Object sender, SaveLoadedEventArgs e) in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\PortraitureMod.cs:line 106
   at StardewModdingAPI.Framework.Events.ManagedEvent`1.Raise(TEventArgs args) in SMAPI\Framework\Events\ManagedEvent.cs:line 101

Moving the images to sit beside the manifest resolves this issue and is still recognized as a content pack, but instead crashes the mod in another way upon load:

[Portraiture] This mod failed in the GameLoop.SaveLoaded event. Technical details:
NullReferenceException: Object reference not set to an instance of an object.
   at Portraiture.TextureLoader.loadAllPortraits() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\TextureLoader.cs:line 226
   at Portraiture.TextureLoader.loadTextures() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\TextureLoader.cs:line 32
   at Portraiture.PortraitureMod.Initialize() in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\PortraitureMod.cs:line 112
   at Portraiture.PortraitureMod.OnSaveLoaded(Object sender, SaveLoadedEventArgs e) in C:\Users\deh\Dropbox\001_Modding\Modding\Stardew-Valley\Stardew-Valley-Mods\Portraiture\PortraitureMod.cs:line 106
   at StardewModdingAPI.Framework.Events.ManagedEvent`1.Raise(TEventArgs args) in SMAPI\Framework\Events\ManagedEvent.cs:line 101

This happens when loading any save, even a fresh one, and the mod loadout when testing this is very minimal as seen above. I also tested this with several portrait sets to eliminate weird image encoding as a potential issue.

I assume one of these methods is correct based on the original description, but it appears that something may have broken in the 1.6 transition if that is indeed the case. Please let me know if you require any additional information!

rikai commented 5 months ago

After some further investigation, I was able to track down the issues at least partially. The first issue seems to be due to some issues with not correctly loading the paths in the loop for the content pack code. Some messing around seems to have fixed this, but C# is not my forte, so I'm not sure I fixed it in a way that makes actual sense.

In short, I modified this section of the code to the following:

            foreach (StardewModdingAPI.IContentPack pack in contentPacks)
            {
                string folderName = pack.Manifest.UniqueID;

                folders.Add(folderName);
                foreach (string file in Directory.EnumerateFiles(pack.DirectoryPath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".png") || s.EndsWith(".xnb")))
                {
                    string fileName = Path.GetFileName(file);
                    string name = Path.GetFileNameWithoutExtension(file);
                    string extension = Path.GetExtension(file).ToLower();

                    if (extension == "xnb")
                        fileName = name;
                    string relativePath = Path.GetRelativePath(pack.DirectoryPath, file);
                    Texture2D texture = pack.ModContent.Load<Texture2D>(relativePath.Replace("\\", "/"));
                    int tileWidth = Math.Max(texture.Width / 2, 64);
                    float scale = tileWidth / 64f;

                    ScaledTexture2D scaled = ScaledTexture2D.FromTexture(Game1.getCharacterFromName(name).Portrait, texture, scale);
                    if (!pTextures.ContainsKey(folderName + ">" + name))
                        pTextures.Add(folderName + ">" + name, scaled);
                    else
                        pTextures[folderName + ">" + name] = scaled;
                }
            }

As I said though, I'm not sure if this is a GOOD fix, just what seemed to fix the folder issue for me with just some minor changes, and I thought sharing it might help understand where the issue may lie.

I also seem to have found the cause of the second crash, but the ability to understand how to fix that one is a bit beyond my capabilities.

In short, it seems that the logic used for the portrait loading via the Portraits folder is not being used with content packs and this is causing null reference exceptions when trying to load variant portraits such as Abigail_Beach, as it's looking for an NPC named Abigail_Beach. This also causes crashes for NPCs that do exist that may just not necessarily be loaded in a save immediately, such as the Bear.

I was able to verify this was the case in combination with the above fix by creating a pack that only loaded non-variant base NPCs, and the content pack loaded without issues. The moment I add a portrait for an NPC that does not exist yet or add a variant photo such as _Beach or _Summer, the mod then crashes with an NRE, which does not happen in the Portraiture folder code path.

Apologies if none of this is helpful, I just wanted to provide as much info as I possibly could to try to assist!

Looongting commented 3 weeks ago

Same issue, planning to give it a try with your approach