API: Campaign - Drowbe/coffee-pub-blacksmith GitHub Wiki
Campaign API
Blacksmith exposes a normalized campaign API for other Coffee Pub modules so they do not need to read raw settings or resolve party actors themselves.
Access
const api = game.modules.get('coffee-pub-blacksmith')?.api;
const campaign = api?.campaign?.getCampaign?.();
Console Testing
const api = game.modules.get('coffee-pub-blacksmith')?.api;
console.log('Campaign API:', api?.campaign);
console.log('Full Campaign:', api?.campaign?.getCampaign?.());
console.log('Core:', api?.campaign?.getCore?.());
console.log('Geography:', api?.campaign?.getGeography?.());
console.log('Party:', api?.campaign?.getParty?.());
console.log('Rulebooks:', api?.campaign?.getRulebooks?.());
console.log('Journal Defaults:', api?.campaign?.getJournalDefaults?.());
console.log('Prompt Context:', api?.campaign?.getPromptContext?.());
Quick readable dump:
const campaign = game.modules.get('coffee-pub-blacksmith')?.api?.campaign?.getCampaign?.();
console.log(JSON.stringify(campaign, null, 2));
Methods
campaign.getCampaign()
Returns the full normalized campaign object:
{
core: {
name: string,
rulesVersion: string,
customRulebooks: string,
rulebooks: {
configuredCount: number,
compendiums: [
{
id: string,
label: string,
package: string,
type: string
}
]
}
},
geography: {
realm: string,
region: string,
site: string,
area: string
},
party: {
name: string,
configuredSize: number,
memberCount: number,
members: [
{
id: string,
uuid: string,
name: string,
img: string,
actorType: string,
level: number | null,
className: string | null,
classes: string[]
}
],
summary: {
averageLevel: number | null,
levels: number[],
classNames: string[]
}
},
journal: {
narrative: {
folder: string,
cardImage: string,
imagePath: string
},
encounter: {
folder: string,
cardImage: string,
imagePath: string
}
}
}
Data Semantics
core
name- Source setting:
Campaign Settings > Core > Campaign Name - The campaign name used as shared context for prompts and imports.
- This should be the user-facing campaign title, not a sourcebook or setting name.
- Good examples:
Shadows Over BlackstoneThe Ashen Crown Campaign
- Source setting:
rulesVersion- Source setting:
Campaign Settings > Core > Rules Version - The selected rules era for the campaign.
- Current values are:
2024for Modern Rules2014for Legacy Rules
- Consumers should treat this as a rules-behavior hint, not as a complete system identifier.
- This should reflect which D&D 5e rules revision the campaign is actually using, especially when other modules need to know whether 2014 or 2024 assumptions apply.
- Source setting:
customRulebooks- Source setting:
Campaign Settings > Core > Custom Rulebooks - Freeform supplemental rules text entered by the GM.
- Intended for books, supplements, houserule packets, or campaign documents not represented by selected compendium packs.
- This is best used for:
- unofficial supplements
- house rules packets
- campaign PDFs
- rulings that are not represented by a compendium selector
- This should be plain descriptive text, not a JSON blob or comma requirements list.
- Source setting:
rulebooks.configuredCount- Source setting:
Campaign Settings > Core > Number of Rulebooks - How many rulebook-compendium dropdowns the GM chose to expose in settings.
- This is configuration shape, not guaranteed content.
- Source setting:
rulebooks.compendiums- Source setting:
Campaign Settings > Core > Rulebook 1..N - The actual selected rulebook compendiums, resolved into metadata objects.
- These represent the structured rules corpus the campaign is expected to use.
- Consumers should prefer these over parsing
customRulebooks. - These should point at the compendiums that actually represent the campaign's active rules references.
- Typical examples:
Player's HandbookDungeon Master's GuideXanathar's Guide to EverythingTasha's Cauldron of Everything
- Source setting:
geography
realm- Source setting:
Campaign Settings > Geography > Realm - Broad world, plane, or major setting scope, such as
FaerunorEberron. - This should describe the highest-level campaign location context.
- Source setting:
region- Source setting:
Campaign Settings > Geography > Region - Large political or geographic area within the realm, such as a kingdom, coast, or territory.
- This should narrow the campaign context beneath the realm, but still remain broader than a single city or dungeon.
- Source setting:
site- Source setting:
Campaign Settings > Geography > Site - Specific place within the region, such as a city, keep, mine, temple, or dungeon.
- This should identify the main location the campaign or current arc centers on.
- Source setting:
area- Source setting:
Campaign Settings > Geography > Area - Localized sub-area within the site, such as a room, chamber, district, street, or encounter zone.
- This should be the most granular campaign-location hint you want prompts or imports to inherit by default.
- Source setting:
These fields are intended as campaign context. They should not be assumed to match the currently active Foundry scene.
party
name- Source setting:
Campaign Settings > Party > Party Name - The configured party name used as campaign context.
- This should be the table-facing party title if one exists.
- Good examples:
The GloamwalkersCompany of the Broken Pike
- Source setting:
configuredSize- Source setting:
Campaign Settings > Party > Party Size - The number of party-member dropdowns exposed in settings.
- This is the intended party size, even if some slots are still empty.
- This should reflect how many player-character slots you want Blacksmith to track, not how many NPC companions happen to be present this week.
- Source setting:
memberCount- The number of valid actor selections currently configured.
- Consumers should use this for actual resolved membership.
members- Source setting:
Campaign Settings > Party > Party Member 1..N - Resolved actor summaries in configured order.
- This is the main data other modules should consume instead of doing their own actor lookup from settings.
- These should generally be the party's player-character actors, or whatever set of actors you want other Coffee Pub modules to treat as the canonical party roster.
- Source setting:
members[].id- World actor id.
members[].uuid- Full actor UUID for durable linking.
members[].name- Actor display name.
members[].img- Actor image for lightweight display use.
members[].actorType- Foundry/system actor type, such as
character.
- Foundry/system actor type, such as
members[].level- Best-effort derived level.
- May be
nullif the system or actor data does not expose a clear level.
members[].className- Human-readable joined class label, if derivable.
members[].classes- Best-effort class list as individual strings.
summary.averageLevel- Average of resolved member levels when available.
- May be
nullif no levels can be derived.
summary.levels- Raw numeric levels used to compute the average.
summary.classNames- Unique class names present across resolved party members.
journal
journal.narrative.folder- Source setting:
Imports > Journal > Narrative > Narrative Folder - Default folder used for narrative journal generation/import.
- This should be the journal folder where generated narratives should land by default.
- Source setting:
journal.narrative.cardImage- Source setting:
Imports > Journal > Narrative > Card Image - Selected built-in narrative card image path or
customornone. - This should be one of:
- a built-in image selection
customnone
- Source setting:
journal.narrative.imagePath- Source setting:
Imports > Journal > Narrative > Custom Image - Custom narrative image path used when
cardImage === 'custom'. - This should be a valid Foundry asset path only when the card image mode is
custom.
- Source setting:
journal.encounter.folder- Source setting:
Imports > Journal > Encounter > Encounter Folder - Default folder used for encounter journal generation/import.
- This should be the journal folder where generated encounters should land by default.
- Source setting:
journal.encounter.cardImage- Source setting:
Imports > Journal > Encounter > Default Encounter Card Image - Selected built-in encounter card image path or
customornone. - This should be one of:
- a built-in image selection
customnone
- Source setting:
journal.encounter.imagePath- Source setting:
Imports > Journal > Encounter > Custom Image - Custom encounter image path used when
cardImage === 'custom'. - This should be a valid Foundry asset path only when the encounter card image mode is
custom.
- Source setting:
Settings Mapping
This section maps the normalized API fields back to the settings users actually configure. It is intended to help other module authors understand both where the data comes from and what kind of content the GM is expected to place there.
Campaign Settings > Core
Campaign Name->campaign.getCore().name- Expected content: the table-facing name of the active campaign.
- Use this as narrative context, not as a compendium or system identifier.
Rules Version->campaign.getCore().rulesVersion- Expected content: which D&D 5e rules revision the campaign is running under.
- Current supported values:
20242014
Number of Rulebooks->campaign.getCore().rulebooks.configuredCount- Expected content: how many rulebook selectors the GM wants available.
- This shapes the settings UI and indicates the intended breadth of structured rulebook selection.
Rulebook 1..N->campaign.getCore().rulebooks.compendiums- Expected content: selected rulebook compendium packs that represent the structured rules corpus for the campaign.
- Consumers should prefer these over parsing freeform text.
Custom Rulebooks->campaign.getCore().customRulebooks- Expected content: supplemental freeform rules references that are not represented by the selected compendium packs.
- Good uses include house rules, third-party books, campaign documents, or short notes about special rules in effect.
Campaign Settings > Geography
Realm->campaign.getGeography().realm- Expected content: world-, plane-, or setting-level location context.
Region->campaign.getGeography().region- Expected content: kingdom-, coast-, territory-, or province-level context.
Site->campaign.getGeography().site- Expected content: city, dungeon, keep, temple, mine, settlement, or similarly specific location.
Area->campaign.getGeography().area- Expected content: the most local default location context, such as a district, room, street, or zone.
Campaign Settings > Party
Party Name->campaign.getParty().name- Expected content: the canonical party name, if the group uses one.
Party Size->campaign.getParty().configuredSize- Expected content: how many party member slots should be tracked in settings.
Party Member 1..N->campaign.getParty().members- Expected content: the actor selections representing the campaign's actual party roster.
- These should usually be player characters rather than generic reference actors.
Imports > Journal > Narrative
Narrative Folder->campaign.getJournalDefaults().narrative.folder- Expected content: the default journal folder for generated/imported narrative entries.
Card Image->campaign.getJournalDefaults().narrative.cardImage- Expected content: a built-in image choice,
custom, ornone.
- Expected content: a built-in image choice,
Custom Image->campaign.getJournalDefaults().narrative.imagePath- Expected content: a valid asset path only when the selected card image mode is
custom.
- Expected content: a valid asset path only when the selected card image mode is
Imports > Journal > Encounter
Encounter Folder->campaign.getJournalDefaults().encounter.folder- Expected content: the default journal folder for generated/imported encounter entries.
Default Encounter Card Image->campaign.getJournalDefaults().encounter.cardImage- Expected content: a built-in image choice,
custom, ornone.
- Expected content: a built-in image choice,
Custom Image->campaign.getJournalDefaults().encounter.imagePath- Expected content: a valid asset path only when the selected encounter card image mode is
custom.
- Expected content: a valid asset path only when the selected encounter card image mode is
campaign.getCore()
Returns the core block only.
campaign.getGeography()
Returns the geography block only.
campaign.getParty()
Returns the normalized party block only.
campaign.getRulebooks()
Returns campaign.getCore().rulebooks.
campaign.getJournalDefaults()
Returns the journal block only.
campaign.getPromptContext()
Returns a flattened helper object for prompt/template replacement:
{
campaignName,
rulesVersion,
rulebooks,
partySize,
partyLevel,
partyMakeup,
realm,
region,
site,
area,
narrativeFolder,
narrativeCardImage,
narrativeImagePath,
encounterFolder,
encounterCardImage,
encounterImagePath
}
Prompt Context Semantics
campaignName- Prompt-ready campaign title.
rulesVersion- Prompt-ready rules era value (
2024or2014).
- Prompt-ready rules era value (
rulebooks- Flattened comma-delimited text built from selected rulebook compendium labels plus
customRulebooks.
- Flattened comma-delimited text built from selected rulebook compendium labels plus
partySize- Prompt-ready size.
- Uses resolved
memberCountfirst, then falls back toconfiguredSize.
partyLevel- Prompt-ready level string.
- Uses derived party average level when available, then falls back to the hidden legacy setting for backward compatibility.
partyMakeup- Prompt-ready party description.
- Uses selected party actors first, then falls back to the hidden legacy freeform makeup string.
realm,region,site,area- Prompt-ready geography values.
narrativeFolder,narrativeCardImage,narrativeImagePath- Narrative journal defaults flattened for prompt/template replacement.
encounterFolder,encounterCardImage,encounterImagePath- Encounter journal defaults flattened for prompt/template replacement.
Notes
- The API is read-only.
- Party members come from the configured party-member actor dropdowns in Blacksmith settings.
- Rulebooks are built from selected rulebook compendiums plus the freeform
Custom Rulebookssetting. - Modules should prefer this API over direct
game.settings.get('coffee-pub-blacksmith', ...)reads for campaign and party context. partyLevelandpartyMakeupstill include a legacy fallback path for existing worlds while the new party-member settings are adopted.