Jump to content

Modding:Modder Guide/APIs/Content Packs: Difference between revisions

From Stardew Valley Wiki
imported>Pathoschild
→Content pack API: + SMAPI 2.10 API
imported>Margotbean
rm underscores, shorten external link
 
(19 intermediate revisions by 8 users not shown)
Line 2: Line 2:


A '''content pack''' is a special type of mod that isn't run by SMAPI directly, but contains files your own mod can read.
A '''content pack''' is a special type of mod that isn't run by SMAPI directly, but contains files your own mod can read.
Note that a custom content pack format is not required to provide integration with content mods; the most common method is to provide a [[Modding:Modder Guide/APIs/Content#Add a new asset|custom game asset]] that other mods (including Content Patcher packs) can edit. The advantage of custom assets is that both other C# mods and Content Patcher packs can edit them via the content pipeline, with the latter benefiting from convenient features such as tokens, conditional loading and targeted edits, removing the need to implement similar features in your mod.
See the wiki page for [[Modding:Modder Guide/APIs/Content|loading and editing content]], as well as the external tutorial for [https://stardewmodding.wiki.gg/wiki/Tutorial:_Making_Framework_Mods making framework mods] for more info. The rest of this page details instructions for defining custom content packs formats.


__TOC__
__TOC__
==Content pack format==
==Content pack format==
A content pack is a folder containing a <tt>manifest.json</tt> file which specifies your mod in its <tt>ContentPackFor</tt> field (see [[../Manifest|manifest]]). The format beyond that is up to you to define. For example, {{nexus mod|1915|Content Patcher}} requires a <tt>content.json</tt> file, but that's not validated by SMAPI itself. Instead, SMAPI provides an API you can use to read any other file you need from the content pack.
A content pack is a folder containing a <samp>manifest.json</samp> file which specifies your mod in its <samp>ContentPackFor</samp> field (see [[../Manifest|manifest]]). The format beyond that is up to you to define. For example, {{nexus mod|1915|Content Patcher}} requires a <samp>content.json</samp> file, but that's not validated by SMAPI itself. Instead, SMAPI provides an API you can use to read any other file you need from the content pack.


See [[Modding:Content packs]] for more info about content packs.
See [[Modding:Content packs]] for more info about content packs.


==Content pack API==
==Content pack API==
You can get a list of content packs installed for your mod, and access the files within it:
===Get owned content packs===
<source lang="c#">
To get the content packs installed for your mod (including a <samp>Manifest</samp> field with the content pack's [[Modding:Modder Guide/APIs/Manifest|full manifest info]]):
foreach(IContentPack contentPack in this.Helper.GetContentPacks())
<syntaxhighlight lang="c#">
foreach(IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
{
{
   this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
   this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
}
</syntaxhighlight>


    // read a JSON file
Content packs are listed in load order, so they're already sorted for dependencies. For example, if content pack B requires A, they'll be listed in the order A → B.
    YourDataFile data = contentPack.ReadJsonFile<YourDataFile>("content.json");


    // load an asset or image
As a note, this can be done as early as ModEntry, although mods often choose to perform this step in the GameLoad or SaveLoaded event.
    Texture2D image = contentPack.LoadAsset<Texture2D>("image.png");
 
===Check if a file exists===
You can check if a file exists in the content pack folder using <samp>HasFile</samp>. You can specify a relative path like <samp>data/content.json</samp>.
 
<syntaxhighlight lang="c#">
if (!contentPack.HasFile("content.json"))
{
  // show 'required file missing' error
}
}
</source>
</syntaxhighlight>
 
It is often a good idea to alert the player (and modders who may be using your mod) if the file is missing on deployment.
 
===Read a JSON file===
You can read a JSON file from a content pack folder into [[Modding:Modder Guide/APIs/Data#Data model|a data model]] (<samp>YourDataModel</samp> in the example below) using <samp>ReadJsonFile</samp>. You can specify a relative path like <samp>data/content.json</samp>. This will return <samp>null</samp> if the file doesn't exist.
 
<syntaxhighlight lang="c#">
YourDataModel data = contentPack.ReadJsonFile<YourDataFile>("content.json");
</syntaxhighlight>


If you need to pass a content pack asset name to game code, you can use its <tt>GetActualAssetKey</tt> method:
===Write a JSON file===
<source lang="c#">
You can write a JSON file in a content pack folder using <samp>WriteJsonFile</samp>, using a [[Modding:Modder Guide/APIs/Data#Data model|data model]] (<samp>YourDataModel</samp> in the example below). You can specify a relative path like <samp>data/content.json</samp> (subdirectories will be created automatically if needed). This will create the file if it doesn't exist, or overwrite it if it does.
tilesheet.ImageSource = contentPack.GetActualAssetKey("image.png");
 
</source>
'''Note:''' this is best used for generated files. Overwriting the original files isn't recommended, since a bug in your mod which changes an original file might permanently break the content pack and require the player to reinstall it.
 
<syntaxhighlight lang="c#">
YourDataModel data = new YourDataModel();
contentPack.WriteJsonFile("content.json", data);
</syntaxhighlight>


{{SMAPI upcoming|2.10|
===Read content asset===
You can get a list of content packs installed for your mod, and access the files within it:
You can read [[Modding:Modder Guide/APIs/Content|a content asset]] from the content pack folder using <samp>LoadAsset</samp>. You can optionally specify a relative path to read from a subfolder.
<source lang="c#">
<syntaxhighlight lang="c#">
foreach(IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
Texture2D image = contentPack.ModContent.Load<Texture2D>("image.png");
{
</syntaxhighlight>
  this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");


    // read a JSON file
If you need to pass an asset name to game code, you can use the <samp>GetActualAssetKey</samp> method:
    YourDataFile data = contentPack.ReadJsonFile<YourDataFile>("content.json");
<syntaxhighlight lang="c#">
tilesheet.ImageSource = contentPack.GetActualAssetKey("image.png");
</syntaxhighlight>


    // load an asset or image
===Get translations===
    Texture2D image = contentPack.LoadAsset<Texture2D>("image.png");
You can read translations from the content pack's <samp>i18n</samp> folder. This is identical to the [[Modding:Modder Guide/APIs/Translation|translation API]], but accessed through <samp>contentPack.Translations</samp>:
}
<syntaxhighlight lang="c#">
</source>
string text = contentPack.Translation.Get("item-type.label");
</syntaxhighlight>


In specialised cases, you can create a fake content pack for a given directory path:
===Create a fake content pack===
<source lang="c#">
In specialised cases, you can create a temporary content pack for a given directory path:
<syntaxhighlight lang="c#">
// create with random manifest data
// create with random manifest data
IContentPack contentPack = this.Helper.ContentPack.CreateFake(
IContentPack contentPack = this.Helper.ContentPacks.CreateFake(
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
);
);


// create with given manifest fields
// create with given manifest fields
IContentPack contentPack = this.Helper.ContentPack.CreateFake(
IContentPack contentPack = this.Helper.ContentPacks.CreateTemporary(
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
   id: Guid.NewGuid().ToString("N"),
   id: Guid.NewGuid().ToString("N"),
Line 60: Line 90:
   version: new SemanticVersion(1, 0, 0)
   version: new SemanticVersion(1, 0, 0)
);
);
</source>
</syntaxhighlight>
}}


{{modding guide footer
[[ru:Модификации:Руководство мододела/API/Контент-паки]]
|prev = [[Modding:Modder Guide/APIs|SMAPI reference]]
[[zh:模组:制作指南/APIs/Content Packs]]
|next =
}}

Latest revision as of 05:16, 21 May 2026

← Modding:Index

A content pack is a special type of mod that isn't run by SMAPI directly, but contains files your own mod can read.

Note that a custom content pack format is not required to provide integration with content mods; the most common method is to provide a custom game asset that other mods (including Content Patcher packs) can edit. The advantage of custom assets is that both other C# mods and Content Patcher packs can edit them via the content pipeline, with the latter benefiting from convenient features such as tokens, conditional loading and targeted edits, removing the need to implement similar features in your mod.

See the wiki page for loading and editing content, as well as the external tutorial for making framework mods for more info. The rest of this page details instructions for defining custom content packs formats.

Content pack format

A content pack is a folder containing a manifest.json file which specifies your mod in its ContentPackFor field (see manifest). The format beyond that is up to you to define. For example, Content Patcher requires a content.json file, but that's not validated by SMAPI itself. Instead, SMAPI provides an API you can use to read any other file you need from the content pack.

See Modding:Content packs for more info about content packs.

Content pack API

Get owned content packs

To get the content packs installed for your mod (including a Manifest field with the content pack's full manifest info):

foreach(IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
{
   this.Monitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
}

Content packs are listed in load order, so they're already sorted for dependencies. For example, if content pack B requires A, they'll be listed in the order A → B.

As a note, this can be done as early as ModEntry, although mods often choose to perform this step in the GameLoad or SaveLoaded event.

Check if a file exists

You can check if a file exists in the content pack folder using HasFile. You can specify a relative path like data/content.json.

if (!contentPack.HasFile("content.json"))
{
   // show 'required file missing' error
}

It is often a good idea to alert the player (and modders who may be using your mod) if the file is missing on deployment.

Read a JSON file

You can read a JSON file from a content pack folder into a data model (YourDataModel in the example below) using ReadJsonFile. You can specify a relative path like data/content.json. This will return null if the file doesn't exist.

YourDataModel data = contentPack.ReadJsonFile<YourDataFile>("content.json");

Write a JSON file

You can write a JSON file in a content pack folder using WriteJsonFile, using a data model (YourDataModel in the example below). You can specify a relative path like data/content.json (subdirectories will be created automatically if needed). This will create the file if it doesn't exist, or overwrite it if it does.

Note: this is best used for generated files. Overwriting the original files isn't recommended, since a bug in your mod which changes an original file might permanently break the content pack and require the player to reinstall it.

YourDataModel data = new YourDataModel();
contentPack.WriteJsonFile("content.json", data);

Read content asset

You can read a content asset from the content pack folder using LoadAsset. You can optionally specify a relative path to read from a subfolder.

Texture2D image = contentPack.ModContent.Load<Texture2D>("image.png");

If you need to pass an asset name to game code, you can use the GetActualAssetKey method:

tilesheet.ImageSource = contentPack.GetActualAssetKey("image.png");

Get translations

You can read translations from the content pack's i18n folder. This is identical to the translation API, but accessed through contentPack.Translations:

string text = contentPack.Translation.Get("item-type.label");

Create a fake content pack

In specialised cases, you can create a temporary content pack for a given directory path:

// create with random manifest data
IContentPack contentPack = this.Helper.ContentPacks.CreateFake(
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
);

// create with given manifest fields
IContentPack contentPack = this.Helper.ContentPacks.CreateTemporary(
   directoryPath: Path.Combine(this.Helper.DirectoryPath, "content-pack"),
   id: Guid.NewGuid().ToString("N"),
   name: "temporary content pack",
   description: "...",
   author: "...",
   version: new SemanticVersion(1, 0, 0)
);