Skip to content

Steam Workshop

Workshop integration in GemShell is fully automatic for the common case: subscribe -> download -> mount -> available as gemshell://.... The methods on this page are for cases where you want fine-grained control or UI feedback.

How auto-mount actually works

  1. await gemshell.steam.init() succeeds
  2. GemShell calls GetSubscribedItems
  3. For every item that is already installed -> mount immediately
  4. For every item that is subscribed but not installed yet -> trigger a background download via DownloadItem
  5. A background poll (1 Hz) drains Steam's DownloadItemResult_t and ItemInstalled_t callbacks, mounts each newly finished item, and fires assets.onWorkshopChanged
  6. Same flow when the user subscribes to a new item while playing - no restart, no manual call required

This means a typical game does not need to touch this page at all. Just call steam.init() and use gemshell:// URLs as normal.

When you actually need this API

  • Show a "Downloading X mods..." UI while pending items are still on the way
  • Build an in-game mod manager listing subscribed items, their state, and their disk size
  • Force-update a single item

Methods

getNumSubscribedItems()

Number of Workshop items the current user is subscribed to for this app.

javascript
const count = await steam.getNumSubscribedItems();
console.log(`Subscribed to ${count} mods`);

getSubscribedItems()

List of subscribed Workshop file IDs (as strings - IDs are 64-bit).

javascript
const ids = await steam.getSubscribedItems();
// ['2891234567', '2999887766', ...]

getItemState(fileId)

Returns the EItemState bitmap from Steam. Use bitwise AND with the constants below to inspect.

BitConstantMeaning
1Subscribeduser is subscribed
4Installeddownloaded and ready on disk
8NeedsUpdateinstalled, creator pushed an update
16Downloadingcurrently downloading
32DownloadPendingdownload queued, not started yet
javascript
const state = await steam.getItemState(id);
const installed = (state & 4) !== 0;
const downloading = (state & 16) !== 0;

getItemInstallInfo(fileId)

Resolve where a Workshop item is installed on disk and how big it is. Returns an object with installed: false (and zero/empty fields) when the item has not been downloaded yet.

typescript
interface WorkshopItemInstallInfo {
  installed: boolean;     // true if downloaded and ready
  folder: string;         // absolute path, "" if not installed
  sizeOnDisk: number;     // bytes, 0 if not installed
  timestamp: number;      // unix seconds of last update, 0 if not installed
}
javascript
const info = await steam.getItemInstallInfo(id);
if (info.installed) {
  console.log(`${info.folder} (${info.sizeOnDisk} bytes)`);
}

downloadItem(fileId, highPriority?)

Trigger a download or update for a single item. Resolves true if Steam accepted the request; the actual completion is asynchronous and will arrive via assets.onWorkshopChanged.

You typically do not need this - GemShell already triggers downloads for all subscribed-but-not-installed items right after steam.init(). Use it for explicit "force update" buttons in a mod manager.

javascript
await steam.downloadItem(id);                // normal priority
await steam.downloadItem(id, true);          // high priority

High priority pitfall

Passing highPriority: true for many items at once can stall Steam's download pipeline. Use it only for a single user-initiated download.

Common patterns

Show a download progress indicator

javascript
const ids = await steam.getSubscribedItems();
const pending = [];
for (const id of ids) {
  const s = await steam.getItemState(id);
  if (!(s & 4)) pending.push(id); // not installed yet
}
if (pending.length) showToast(`Downloading ${pending.length} mods...`);

gemshell.assets.onWorkshopChanged((items) => {
  showToast(`${items.length} mods ready`);
});

List all installed mods on the title screen

javascript
const ids = await steam.getSubscribedItems();
const installed = [];
for (const id of ids) {
  const info = await steam.getItemInstallInfo(id);
  if (info.installed) installed.push({ id, ...info });
}
titleScreen.showSubtitle(`${installed.length} workshop mods active`);

Force-update one item

javascript
async function forceUpdate(id) {
  await steam.downloadItem(id, true);
  // wait for Steam to finish; assets.onWorkshopChanged fires when it is.
}

See also