How Items & Blocks was built
Raw game files read
recipes/**/*.jsonitemtypes/**/*.json (only drops/tags/maxstacksize/class/behaviors read, not the full definition; for ItemStackRandomizer items, e.g. itemtypes/meta/stackrandomizer*.json, the per-variant `stacks` pool too)blocktypes/**/*.json (only drops/tags/maxstacksize/class/entityClass/behaviors/entityBehaviors read, not the full definition)entities/**/*.json (only death/harvestable drops read)worldgen/deposits/**/*.jsonworldgen/blockpatches/*.jsonworldgen/treengenproperties.jsonblocktypes/plant/fruittreebranch.jsonconfig/tradelists/*.jsonconfig/dialogue/*.jsonconfig/handbook/*.json (guide text) -- only the item/block codes its, and dialogue's, handbook:// links name are used here, so each gets a pageworldgen/schematics/**/*.json (ItemCodes + BlockCodes dictionaries, for "Found in structures")
Processing
Not a registry dump. An item/block only gets a page here if it's reachable from at
least one of: a recipe (input or output), a block/creature drop table, a worldgen spawn rule (ore
deposit, crop/flower patch, tree, fruit tree), a trader's buy/sell list, an NPC dialogue reward, or
a recipe ingredient's own tool-tag (e.g. tool-hammer). An item that exists in the raw
game files but satisfies none of those (pure creative-mode novelties, debug items, etc.) will not
appear.
apps/vs-wiki/src/ingest/crossref.ts builds the base index by walking every normalized recipe
(input/output codes) and every flattened loot entry (drop codes). Six later passes in
apps/vs-wiki/src/ingest/index.ts then widen it, each via the same
ensureSpawnTarget(domain, code, kind) synthesis -- "give this code a page even
though the recipe/loot walk alone never would have":
- ore/gem/rock deposits (
models/deposits.ts) -- a block with no recipe and no drop table still needs a page to answer "where do I find this" - crop/flower/mushroom spawn patches (
models/blockpatches.ts) - tree and fruit-tree spawn bands (
models/trees.ts) - block-drop-only blocks (break a block, get an item, with no recipe producing that block)
- tagged tools (
attachItemMetadataincrossref.ts-- only ~23 files in the whole game declare atagsarray at all) - trader-only and NPC-dialogue-reward-only items (nothing else references them, but a trade listing or a reward still deserves a page)
- anything matched by
vs-manifest.json'sincludeItemsglobs (includeManifestItemsincrossref.ts) -- a hand-picked list for things no rule reaches at all, like static translocators
Paintings, tapestries, and clothing are a deliberate, separate exception: they never join this index at all, since they're pure decor with no recipe/drop/worldgen tie -- they get their own dedicated catalogs instead (see their own source pages).
Descriptions and C# source links
Once the index is complete, attachDescriptionsAndCodeRefs in crossref.ts
gives every entry its itemdesc-/blockdesc- lang description, when the game
has one. It also records the C# names its own JSON definition points at: class,
entityClass, behaviors[].name and entityBehaviors[].name,
including their ...ByType variants. Each name is looked up in
apps/vs-wiki/src/ingest/csharpClassMap.json, a committed name-to-file mapping. It is generated by
hand with apps/vs-wiki/scripts/map-csharp-classes.ts from a local clone of
vssurvivalmod, by matching each
api.Register...Class("Name", typeof(Type)) call to the file declaring
Type. The C# source itself is never part of the build. Names implemented outside
vssurvivalmod (VSEssentials, the engine, mod DLLs) are listed without a link.
Random-stack placeholders
An ItemStackRandomizer item (stackrandomizer-ore, stackrandomizer-clutter-scribe,
…) is what a world-generated chest or vessel actually holds in a schematic; the game replaces it
with one random stack when the container is generated. extractStackRandomizerPools in
models/loot.ts reads each variant's stacks pool (glob-keyed
attributesByType, like every other ...ByType field). In
index.ts every pool owner is added to the item index with its results, each normalized to
a 0–1 chance by the pool's total weight (the same normalization ItemStackRandomizer.OnLoaded
does), and every result gets a reverse "Can be generated by" link. A stack's own attributes are kept,
because for the generic clutter block they are what decide which clutter it is. The
placeholders sit in a schematic's ItemCodes dictionary, so "Found in structures" also reads
that, not just BlockCodes. A placed randomizer can additionally carry its own
totalChance (a chance of producing nothing); that is per-instance data and isn't modelled.
Items linked from the handbook
Guide, dialogue and class text links to items with handbook://item-<code> or
block-<code> (optionally domain:code). Each such link is rewritten to its
/items/ page, and index.ts then makes sure every referenced item or block that really
exists has a page, even if no recipe, drop or spawn rule reaches it (muddy gravel, bony soil, pit kilns).
Pipeline code
apps/vs-wiki/src/ingest/crossref.tsapps/vs-wiki/src/ingest/csharpClassMap.jsonapps/vs-wiki/scripts/map-csharp-classes.tsapps/vs-wiki/src/ingest/models/loot.tsapps/vs-wiki/src/ingest/models/deposits.tsapps/vs-wiki/src/ingest/models/blockpatches.tsapps/vs-wiki/src/ingest/models/trees.tsapps/vs-wiki/src/ingest/models/trades.tsapps/vs-wiki/src/ingest/models/dialogue.ts