Skip to the content.

Worked example

← Back to index

A complete mod that adds eight help pages: one business type, three furniture pieces and three products, all cross-linked. This is the example mod used to test the library, so the code below is known to work rather than written for the page.

It documents a Bike Shop that does not exist — no items, no business type, no assets, just help pages. That keeps the example about the help API and nothing else.


The mod

#nullable enable
using System;
using System.Linq;
using System.Threading.Tasks;
using BAModAPI;
using BigAmbitions.Modding.Help;
using UnityEngine;

[assembly: RegisterModClass(typeof(BikeShopDocs.BikeShopDocsMod))]

namespace BikeShopDocs
{
    [ModEntryOnInitializationLoad]
    public class BikeShopDocsMod : IModBigAmbitions
    {
        private const string OwnerId = "BikeShopDocs";
        private const string BusinessSlug = "businesstypes-bikeshop";

        // Registered as a batch; sorted alphabetically among the base game's furniture pages.
        private static readonly HelpPage[] FurniturePages =
        {
            new("furniture-bikeshopbikerack",     "bikeshop:itemname_bikerack"),
            new("furniture-bikeshoprepairstand",  "bikeshop:itemname_repairstand"),
            new("furniture-bikeshoptoolwall",     "bikeshop:itemname_toolwall")
        };

        // Registered with Append, so these keep the order written here — cheapest first —
        // instead of being sorted by name.
        private static readonly HelpPage[] ProductPages =
        {
            new("products-bikeshopcitybike",      "bikeshop:itemname_citybike"),
            new("products-bikeshopmountainbike",  "bikeshop:itemname_mountainbike"),
            new("products-bikeshoprepairservice", "bikeshop:itemname_repairservice")
        };

        public string[] RelativeAssetBundlePaths => Array.Empty<string>();

        public Task OnLoadAsync(ModContext context)
        {
            if (!HelpApi.IsSupported)
            {
                context.Logger.Warn("Help API unsupported on this game version; pages skipped.");
                return Task.CompletedTask;
            }

            HelpApi.PagesApplied += OnPagesApplied;

            HelpApi.RegisterPage(OwnerId, HelpCategories.BusinessTypes,
                BusinessSlug, "bikeshop:businesstype_bikeshop");

            HelpApi.RegisterPages(OwnerId, HelpCategories.Furniture, FurniturePages);

            HelpApi.RegisterPages(OwnerId, HelpCategories.GoodsAndServices, ProductPages,
                HelpPageOrder.Append);

            context.Logger.Info($"Registered {HelpApi.SlugsFor(OwnerId).Count()} help page(s).");
            return Task.CompletedTask;
        }

        public Task OnUnloadAsync()
        {
            HelpApi.PagesApplied -= OnPagesApplied;
            HelpApi.UnregisterOwner(OwnerId);
            return Task.CompletedTask;
        }

        // Runs once the help window exists and pages have been merged in. Base-game pages are not
        // knowable before this point, so link checks belong here rather than in OnLoadAsync.
        private static void OnPagesApplied()
        {
            string[] targets = { "importers-contract", "businesstypes-headquarters" };

            var missing = targets.Where(slug => !HelpApi.PageExists(slug)).ToArray();
            if (missing.Length > 0)
                Debug.LogWarning($"[BikeShopDocs] Dead links: {string.Join(", ", missing)}.");
        }
    }
}

asmdef

{
  "name": "BikeShopDocs",
  "rootNamespace": "BikeShopDocs",
  "references": ["BAHelpApi"],
  "overrideReferences": true,
  "precompiledReferences": ["BigAmbitions.ModAPI.dll" /* plus any game DLLs you use */],
  "autoReferenced": false,
  "defineConstraints": ["BA_GAME_DLLS_IMPORTED"]
}

The text

Locales/en.json. Two keys per page — title, and body under help_<prefix>_content.

{
  "bikeshop:businesstype_bikeshop": "Bike Shop",
  "help_bikeshop:businesstype_bikeshop_content": "**Bike Shop** businesses operate out of retail buildings.\n\nCustomers browse the floor, buy a bicycle, and occasionally bring one back in for repair.\n\nThe business requires the following furniture to function:\n\n* [Bike Rack](furniture-bikeshopbikerack)\n* [Point of Sales](furniture-itemgrouppointofsale)\n\nProducts sold here:\n\n* [City Bike](products-bikeshopcitybike)\n* [Mountain Bike](products-bikeshopmountainbike)\n* [Repair Service](products-bikeshoprepairservice)",

  "bikeshop:itemname_bikerack": "Bike Rack",
  "help_bikeshop:itemname_bikerack_content": "**Bike Rack** displays bicycles for sale in a [Bike Shop](businesstypes-bikeshop).\n\n**Product Capacity:** 6 bicycles\n**Footprint:** 2.0m x 0.5m\n\nThe furniture can be purchased from the following locations:\n* [Ika Bohag](address:50 4s)\n* [Marquis Living](address:5 7a)",

  "bikeshop:itemname_citybike": "City Bike",
  "help_bikeshop:itemname_citybike_content": "**City Bike** is the everyday product of a [Bike Shop](businesstypes-bikeshop).\n\n**Wholesale price:** $180\n**Market price:** $420\n\nDisplayed on a [Bike Rack](furniture-bikeshopbikerack).\n\nCan be ordered from [Importers](importers-contract) in your [Headquarters](businesstypes-headquarters)."
}

What this produces

Log output on a healthy run:

[HelpApi] Help system found; pages can be applied.
[BikeShopDocs] Registered 7 help page(s).
[HelpApi] Applied 7 mod help page(s).

Patterns worth copying

Reuse an item’s name key as the page prefix. "bikeshop:itemname_bikerack" is presumably already the item’s display name, so the page title stays correct in every language with nothing to maintain twice.

Namespace your slugs. furniture-bikeshopbikerack, not furniture-bikerack. Slugs are global across every mod, and they are public API — other mods may link to yours.

Unregister on unload. HelpApi.UnregisterOwner(OwnerId) in OnUnloadAsync, so disabling your mod removes its pages cleanly.

Check links from PagesApplied, not OnLoadAsync. Mods load at the main menu, before the help window exists, so PageExists cannot report on base-game pages that early.


← Getting started · API reference →