SMAPI - Stardew Modding API

SMAPI - Stardew Modding API

971k Downloads

Support content packs

Pathoschild opened this issue ยท 7 comments

commented

Implement a standardised content pack system for mods.

commented

Here's a proposed implementation to support mod content packs, per discussion on Discord and the forums.

Background

Several mods read content packs to extend the game (not related to mod packs). This is a way for modders to change the game without needing to write their own SMAPI mod or worry about the implementation. For example:

In all three cases, the latter is just a collection of files that the actual mod can read (i.e. content pack), not a mod in itself.

The problem

Each mod has its own content pack directory structure and conventions, and content packs need to be placed in the parent mod's folder. This causes a few issues:

  • Players often put content packs directly in Mods, which causes a confusing no manifest.json error when SMAPI tries to load them as mods.
  • Each mod has different instructions for installing content packs, which causes player confusion.
  • Mod managers can't automatically know whether something is a content pack, or which mod it's for.
  • Mod managers need to support content packs for each mod individually. For example, Json Assets and Seasonal Immersion don't have mods in the same directory structure. This also means that when a new mod supports content packs, players can't use mod managers to install them.

Proposed implementation

  1. Content packs will use the same manifest.json file as SMAPI mods, but replace the EntryDLL field with a ContentPackFor field:
    {
       "Name": "Eemie's Bees",
       "Author": "Eemie",
       "Version": "1.0.0",
       "Description": "Adds bees and bumblebees to your farm!",
       "UniqueID": "Eemie.Bees",
       "UpdateKeys": [ "Nexus:1259" ],
       "ContentPackFor": {
          "UniqueID": "spacechase0.CustomCritters",
          "MinimumVersion": "1.2.2"
       }
    }
    Each content pack will typically have other files or directories, in a format defined by the parent mod.
  2. The player will install content packs by dropping them into the Mods folder, just like SMAPI mods.
  3. SMAPI will read all content packs before initialising mods, showing friendly validation errors if needed (e.g. "Skipped Eemie's Bees because it needs the Custom Critters mod, which isn't installed").
  4. A mod can access all content packs added for it using a new SMAPI API:
    IContentPack[] contentPacks = helper.Mod.GetContentPacks();
    foreach (IContentPack pack in contentPacks)
    {
        CritterData data = pack.ReadJsonFile<CritterData>("critter.json");
        Texture2D texture = pack.LoadContent<Texture2D>("critter.png");
    }

Benefits

  • Players can install a content pack the same way as any other SMAPI mod, reducing confusion.
  • Mod managers can detect which mod a content pack needs.
  • Mod managers can install any content pack directly without needing custom support for each parent mod.
  • SMAPI can show more helpful errors if the parent mod is missing.
commented

I think this idea is great and would work fine as it is.

I would like to propose an extension of this idea, but I don't know if it's possible.
For bigger mods that want to use content packs as a dependency, they could have a manifest like this:

{
   "Name": "Animal Husbandry Mod",
   "Author": "Digus",
   "Version": "2.1.0",
   "Description": "Adds features related to animal husbandry.",
   "UniqueID": "DIGUS.ANIMALHUSBANDRYMOD",
   "EntryDll": "AnimalHusbandryMod.dll",
   "MinimumApiVersion": "2.0",
   "Dependencies": [
           {
		   "UniqueID": "Platonymous.Toolkit",
		   "MinimumVersion": "0.7.0"
	   }
	   , {
		   "UniqueID": "DIGUS.MailFrameworkMod",
		   "MinimumVersion": "1.1.0"
	   }
   ],
   "ContentPackFor": 
    [
          {
              "BaseDir": "contentPack/JsonAssets",
              "UniqueID": "spacechase0.JsonAssets",
              "MinimumVersion": "1.0"
          },
          {
              "BaseDir": "contentPack/CustomCrops",
              "UniqueID": "spacechase0.CustomCrops",
              "MinimumVersion": "1.1"
          },
    ]
   "UpdateKeys": [ "Nexus:1538" ]
}

BaseDir would be relative to the mod base folder.
The advantage of that implementation would be that all content packs required for a mod could be inside its own folder, so when people want to remove or temporally remove a mod, they would just need to handle with one folder.
For SMAPI would be almost the same. It would just need to look for the files inside the base folder, instead of where the manifest was placed.

commented

Json Assets at least will have the ability for SMAPI mods to register themselves as content packs in the near future (via an API).

commented

@Digus I see the value of letting a content pack support multiple mods at once, but it complicates things quite a bit. For example, how would dependency checks work? I guess ContentPackFor can be marked optional, but what if none of them are available? How would you distinguish between "content pack for one of these mods" vs "content pack for all of these mods in parallel"? How should SMAPI notify the user about the mods they need to install if none of them are available? What if two mods expect the same filename (e.g. content.json) with different formats, but the mod doesn't specify a BaseDir field?

I think it's much simpler in those cases to create separate content pack downloads for the separate mods. Similarly, a mod can't specify both EntryDll and ContentPackFor in the current implementation since that introduces some pretty thorny dependency edge cases.

commented

Done in develop for the upcoming SMAPI 2.5.

commented

Reopened to track support in mods that use content packs:

mod status
Advanced Location Loader โœ“ see PR #41 and PR #42.
Custom Farming Redux โ‘
Custom Furniture โ‘
CustomNPC โ‘
Json Assets โœ“ see PR #4 PR #5.
commented

Advanced Location Loader and Json Assets have beta versions which support content packs, which is fine to start with. I may submit PRs for the others after release, but I don't want to hold off the SMAPI 2.5 release this weekend.