Skip to content

Reading a Save

Josh Dionne edited this page Sep 14, 2026 · 4 revisions

Generated from the thetowersdk repository. Edits made here are overwritten on the next push — change the source file instead.

Reading a Save

Function Returns
readLabsFromSaveRoot Research levels, what's maxed, the active queue
readWorkshopFromSaveRoot Upgrade levels, enhancements, saved presets
readModulesFromSaveRoot Owned modules, rarities, substats, equipped
readCardsFromSaveRoot Card levels, copies, mastery, equipped slots
readGuardiansFromSaveRoot Guardian levels and upgrades
readBotsFromSaveRoot Bot levels, Bot+ unlocks, synchronicity slots, medals spent
readUltimateWeaponsFromSaveRoot UW levels, unlocks, plus-levels, stones
readVaultFromSaveRoot Vault power tree progress
readRelicsFromSaveRoot Owned relics
readCollectedThemeNamesFromSaveRoot Unlocked themes
readLifetimeFromSaveRoot Lifetime totals
readDissonanceCycleWavesFromSaveRoot Best wave per tier this dissonance cycle
listImportableBattleRuns Run history

Plus perks, "killed by" and per-run battle report fields — see src/save/index.ts.

Check Before You Read

Extractors return null when a save has no data for that feature, rather than throwing, so older saves degrade instead of failing:

const labs = readLabsFromSaveRoot(parsedRoot)
if (!labs) return

if (labs.warnings.length) {
  // Values the extractor could not interpret. Usually means the save shape changed.
  console.warn(labs.warnings)
}

Run History And Battle Reports

Every completed run the game kept is available, with all of its stored fields:

import { listImportableBattleRuns, buildBattleReportStatFields } from 'thetowersdk/save'

const runs = listImportableBattleRuns(parsedRoot)

// The raw entry — tier, wave, duration, coins, cells, damage dealt and taken,
// per-source damage breakdowns, what killed you, and everything else the game
// recorded for that run.
console.log(Object.keys(runs[0]))

// Or the same run flattened into named stat fields.
const stats = buildBattleReportStatFields(runs[0])

listImportableBattleRuns hands back the decoded entries themselves, not a filtered view, so you are not limited to the fields this SDK happens to name. There are also helpers for duration formatting, date parsing and deduplication — see src/save/index.ts.

Reading Any Field In a Save

parsedRoot is the decoded file as a plain object, so every field the game stores is yours to read directly. The named extractors are a convenience layer over that same object — reach past them whenever you want a field they do not name.

Values are loosely typed and arrays arrive in several shapes, so use the readers rather than hand-parsing:

import { coerceSaveNumber, readSaveBoolean, readSaveIntList } from 'thetowersdk/save'

coerceSaveNumber(parsedRoot.someKey) // number | null
readSaveBoolean(parsedRoot.someFlag) // boolean
readSaveIntList(parsedRoot.someList) // number[]

Worked out a field that isn't covered? A PR adding an extractor is very welcome.


Clone this wiki locally