Jump to content

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

From Stardew Valley Wiki
imported>Pathoschild
→Get owned content packs: + note on order
imported>Margotbean
rm underscores, shorten external link
 
(9 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.
Line 11: Line 15:
==Content pack API==
==Content pack API==
===Get owned content packs===
===Get owned content packs===
To get the content packs installed for your mod (including a <tt>Manifest</tt> field with the content pack's [[Modding:Modder Guide/APIs/Manifest|full manifest info]]):
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]]):
<source lang="c#">
<syntaxhighlight lang="c#">
foreach(IContentPack contentPack in this.Helper.ContentPacks.GetOwned())
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}");
}
}
</source>
</syntaxhighlight>


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.
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===
===Check if a file exists===
You can check if a file exists in the content pack folder using <tt>HasFile</tt>. You can specify a relative path like <tt>data/content.json</tt>.
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>.


<source lang="c#">
<syntaxhighlight lang="c#">
if (!contentPack.HasFile("content.json"))
if (!contentPack.HasFile("content.json"))
{
{
   // show 'required file missing' error
   // 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===
===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]] (<tt>YourDataModel</tt> in the example below) using <tt>ReadJsonFile</tt>. You can specify a relative path like <tt>data/content.json</tt>. This will return <tt>null</tt> if the file doesn't exist.
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.


<source lang="c#">
<syntaxhighlight lang="c#">
YourDataModel data = contentPack.ReadJsonFile<YourDataFile>("content.json");
YourDataModel data = contentPack.ReadJsonFile<YourDataFile>("content.json");
</source>
</syntaxhighlight>


===Write a JSON file===
===Write a JSON file===
You can write a JSON file in a content pack folder using <tt>WriteJsonFile</tt>, using a [[Modding:Modder Guide/APIs/Data#Data model|data model]] (<tt>YourDataModel</tt> in the example below). You can specify a relative path like <tt>data/content.json</tt> (subdirectories will be created automatically if needed). This will create the file if it doesn't exist, or overwrite it if it does.
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.


'''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.
'''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.


<source lang="c#">
<syntaxhighlight lang="c#">
YourDataModel data = new YourDataModel();
YourDataModel data = new YourDataModel();
contentPack.WriteJsonFile("content.json", data);
contentPack.WriteJsonFile("content.json", data);
</source>
</syntaxhighlight>


===Read content asset===
===Read content asset===
You can read [[Modding:Modder Guide/APIs/Content|a content asset]] from the content pack folder using <tt>LoadAsset</tt>. You can optionally specify a relative path to read from a subfolder.
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#">
Texture2D image = contentPack.LoadAsset<Texture2D>("image.png");
Texture2D image = contentPack.ModContent.Load<Texture2D>("image.png");
</source>
</syntaxhighlight>


If you need to pass an asset name to game code, you can use the <tt>GetActualAssetKey</tt> method:
If you need to pass an asset name to game code, you can use the <samp>GetActualAssetKey</samp> method:
<source lang="c#">
<syntaxhighlight lang="c#">
tilesheet.ImageSource = contentPack.GetActualAssetKey("image.png");
tilesheet.ImageSource = contentPack.GetActualAssetKey("image.png");
</source>
</syntaxhighlight>


===Get translations===
===Get translations===
You can read translations from the content pack's <tt>i18n</tt> folder. This is identical to the [[Modding:Modder Guide/APIs/Translation|translation API]], but accessed through <tt>contentPack.Translations</tt>:
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>:
<source lang="c#">
<syntaxhighlight lang="c#">
string text = contentPack.Translation.Get("item-type.label");
string text = contentPack.Translation.Get("item-type.label");
</source>
</syntaxhighlight>


===Create a fake content pack===
===Create a fake content pack===
In specialised cases, you can create a temporary content pack for a given directory path:
In specialised cases, you can create a temporary content pack for a given directory path:
<source lang="c#">
<syntaxhighlight lang="c#">
// create with random manifest data
// create with random manifest data
IContentPack contentPack = this.Helper.ContentPacks.CreateFake(
IContentPack contentPack = this.Helper.ContentPacks.CreateFake(
Line 74: Line 82:


// create with given manifest fields
// create with given manifest fields
IContentPack contentPack = this.Helper.ContentPacks.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 82: Line 90:
   version: new SemanticVersion(1, 0, 0)
   version: new SemanticVersion(1, 0, 0)
);
);
</source>
</syntaxhighlight>
 
[[ru:Модификации:Руководство мододела/API/Контент-паки]]
[[zh:模组:制作指南/APIs/Content Packs]]

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)
);