Sandkit карта поверхности

Всё, до чего может дотянуться мод для Sandustry — извлечено из собственного мод-моста игры, а не переписано руками. Плюс то, до чего дотянуться нельзя: обычно именно эта половина и съедает выходные.

apiVersion 1 main 281 методов worker 88 методов расхождений с d.ts 0 пересобрать →

Как это собрано

Не по community-типам и не по памяти. Игра поставляет dist/js/external-mod-runtime.js и external-mod-worker-runtime.js — мосты, через которые реально проходит каждый вызов мода. Эти файлы и есть API.

  1. Извлечь оба рантайма из app.asar и разобрать каждую группу неймспейсов прямо из минифицированного кода, разрешая ссылки на переменные к ближайшему предшествующему определению.
  2. Записать для каждого метода число аргументов и функцию движка, в которую он делегирует — это третья колонка в таблицах справочника ниже.
  3. Сдиффить результат с sandkit.d.ts в обе стороны.
Результат: community-файл sandkit.d.ts точен. 281 методов main и 88 методов worker сходятся, фантомных записей нет ни в одну сторону. Единственный пробел — constants (constants.physicsnormal, skip, aggressiveSkip), которого в файле типов нет.

Весь пайплайн — три команды по твоей собственной установке, так что эту страницу можно пересобрать под любую сборку игры, а не верить ей как снимку.

Устройство мода

Четыре поверхности, объявляются в modinfo.json. Большинству модов хватает одной; те, что ощущаются как новый игровой контент, используют три.

entry main.js

Работает в потоке рендера. Регистрация, UI, энергия, дерево технологий, настройки, сохранение данных.

Компилируется через new Function("__sandkit", …) внутри асинхронной IIFE: await на верхнем уровне работает, а import и export бросают исключение — и энтри молча не запускается вообще.

workerEntry worker.js

Работает в каждом симуляционном потоке. Единственное место, которое видит движение отдельных частиц.

Обёртка та же, API заметно меньше: ни настроек, ни таймеров, ни полноценного UI.

patches.json строковый патчинг

До 256 патчей на мод по любому .js внутри игровой папки js/ — включая bundle.js и simulation-worker.js.

expectedMatchesобязательное поле, а патчи можно группировать так, что при промахе одного откатывается вся группа.

манифест

dependencies разрешается настоящей топологической сортировкой с детекцией циклов; loadOrder разрешает ничьи.

Благодаря этому мод-библиотека — штатно поддержанный паттерн: публикуешь её, другие моды указывают её id, порядок загрузки гарантирован.

Main против worker

Самое важное различие во всём этом API и то, которое решает, где вообще может жить твой код.

Энтри mainЭнтри worker
Видит движение элементанетда
Читает настройки модаданет
Рисует UIдатолько тосты
Регистрирует постройки, технологии, энергиюданет
Повторяющиеся таймерыtriggersнет
Говорит с другой сторонойshared buffersmain.emitEvent
Сообщений из main в worker не существует. Worker → main — обычное событие через main.emitEvent, и произвольный payload проходит без преобразований. В обратную сторону канал ровно один: SharedArrayBuffer. Энтри main вызывает shared.buffers.create на верхнем уровне, воркер — require по тому же ключу; ключи с обеих сторон неймспейсятся по id мода, а энтри main всегда грузятся первыми. Именно через этот байт воркер узнаёт, включён ли твой мод.

Что можно построить?

Читать надо с этой колонки. Именно с этим вопросом сюда и приходят.

поток mainсимуляционный workerнет в API
Я хочу…ВердиктКак
Добавить новую машинуможноstructures.register плюс sprites.loadFromMod. Размер рендера задаётся в пикселях, клетка — 4 px, поэтому спрайт 16×16 даёт машину 4×4 клетки. Если передать name и description обычными строками, ключи перевода зарегистрируются сами.
Чтобы она вырабатывала или тратила энергиюможноenergy.registerType(id, "conductor" | "storage"), дальше addAtCell и consume. Проводники отдают в сеть и сами ничего не хранят.
Отреагировать на отдельную частицуможноТолько в воркере. events.on("element:moved", …) с гвардом.
Добавить новый элемент или террейнможноelements.register и terrains.register. Оба раздают числовые id как max + 1 — отсюда дрейф, описанный ниже.
Добавить узел в дерево технологийможноtech.registerNode(id, def, { parentId }). Сам ставит узел в первый свободный слот под родителем; бросает исключение при дубликате id, отсутствующем родителе или заполненном ряде.
Добавить рецепты существующим машинамможноstructures.recipes.register покрывает planter box, шейкер, kinetic press, конденсатор, паровую сушилку, синтезатор, снеговик и плавильню.
Настроить машину в момент постройкиможноstructures.registerPlacementConfig. Значения попадают в structure.data; подписи пока требуют ключей перевода.
Открыть панель у уже стоящей машинынет APIВанильные панели Фильтра и Sound Box открываются захардкоженными проверками по id постройки, висящими на building-сессии, и ни одно событие не сообщает «игрок взаимодействовал с этой постройкой». Достижимо только патчингом.
Нарисовать свой HUDосторожноui.overlays.register или ui.inject. Слот global рисуется и поверх главного меню — гейти по scene.getActive().
Сохранять данные в сейвможноstorage.get и storage.set по id мода. storage.local — наоборот, привязка к машине.
Отменить или переписать вызов движкаможноhooks.intercept чтобы отменить, hooks.modify чтобы переписать аргументы. Доступно в обоих потоках.
Читать и писать файлы, открывать сокетынет APIНичто в этой поверхности не касается Node. Это и есть черта, которую переходит сторонний загрузчик и не переходит мод из Workshop.
Выполнить код до старта игрынет APIЭнтри выполняются при инициализации мира, один раз за процесс.

Жёсткие ограничения

Проверено по поставляемому коду, а не выведено из молчания. Именно эти вещи меняют архитектуру.

Энтри выполняются один раз за процесс

Рантайм держит множество загруженных id и на второй загрузке мира репортит alreadyLoaded. Всё, что ты пропустил из-за выключенной настройки, останется пропущенным до перезапуска игры — поэтому гейтить надо поведение, а не регистрацию.

Регистрация необратима

energy.registerType, structures.register, addProcessor и подписки на события нельзя отменить в рантайме, а addProcessor бросает исключение, если у постройки уже есть периодическая обработка.

Удаление мода оставляет постройки-сироты

Постройки модов сохраняются под своим строковым id. Удали мод — и в сейве останутся записи с типом, который никто не узнаёт; они откатятся к обычному блоку 4×4.

Числовые id элементов дрейфуют

Номера элементов и материй раздаются как max + 1 при регистрации, и закрепить свой номер мод не может никак. Добавь или убери тип — и все номера после него сдвинутся, тогда как сейв всё ещё хранит старые. Постройки от этого защищены: их id строковые, а числовая блок-сетка перестраивается из списка построек при загрузке.

Некоторым событиям воркера гвард обязателен

element:moved и terrain:update без него бросают исключение, и гвард должен нести ровно одно из elementType или terrainType. Симуляция вообще не эмитит эти события, пока нет обработчика на соответствующий тип.

Аварийный люк в движок не версионируется

sandkit.engine.api отдаёт внутренний движок и явно не покрывается apiVersion — может измениться в любом патче.

События и хуки

Id, найденные в поставляемом бандле (всего 45). Payload у нескольких штук перекладывается для модов в замороженную форму; всё, чего игра не узнаёт, проходит нетронутым — благодаря этому и работают собственные события из worker в main.

Жизненный цикл и мир

game:readygame:startedscene:started:gamemods:initializedframe:renderframe:updatetech:unlockedtech:mapUnlockedtutorial:stepChangedtutorial:completedearlyAccess:completestratacore:secured

Строительство и постройки

building:placebuilding:placedbuilding:removedbuilding:blockedbuilding:clearShape

Симуляция (worker)

element:movedelement:moveelement:updateelement:blockedelement:durationelement:createdAtelement:removedAtcell:processterrain:updateterrain:destroyed

Игрок, ввод и снаряды

player:movedplayer:movementplayer:collision:prepareplayer:position:commitinput:keydowninput:keyupinput:scrollinput:escapeprojectile:hitprojectile:fire:overStructureprojectile:fire:emitOnElementprojectile:travel:prepareprojectile:impact:prepare

Ресурсы и рендеринг

resource:collectedresource:collection:prepareresource:delivery:prepareworldItem:pickedUprender:pipes

Обведены те, которым нужен гвард — иначе подписка бросит исключение.

Хуки

hooks.intercept отменяет вызов движка до того, как он случится; hooks.modify переписывает его аргументы. Список id — литеральный белый список в бандле, то есть здесь он полный, а не выборочный. Часть id встречается и в списке событий: событие срабатывает постфактум и может только смотреть, хук выполняется первым и имеет право голоса.

Перехватчики — отменяют вызов (18)

action:interceptbuilding:clearShapebuilding:placefire:element:igniteinput:boost-downinput:descend-downinput:escapeinput:keydowninput:keyupinput:scrollinteractable:suppressHoverplacePoints:directionalArrows:isSuppressedplacePoints:isSuppressedplayer:position:commitprogression:purchaseprojectile:fire:overStructureprojectile:hitteleport:effect

Модификаторы — переписывают аргументы (15)

building:placement-limitexcavation:prepareflux-emanator:processingplayer:collision:prepareplayer:movementprogression:cost:prepareprojectile:impact:prepareprojectile:travel:preparerender:pipesresource:collection:prepareresource:delivery:preparestructures:moved:preparestructures:removed:preparetrigger:schedule:prepareweapon:reload:prepare

Обведённые id принимают гвард-опцию: обработчик подписывается только на свои типы структур, оружия или снарядов, вместо того чтобы фильтровать каждый вызов вручную:

хукгвард-опциясверяется с
building:placestructureTypesstructureId
weapon:reload:prepareweaponIdsweaponId
projectile:travel:prepareprojectileTypesprojectileType
projectile:impact:prepareprojectileTypesprojectileType
trigger:schedule:preparetriggerIdstriggerId
resource:collection:prepareresourceIdsresourceId
resource:delivery:prepareresourceIdsresourceId
Это механизм, закрывающий большинство «на это нет API». Перехват input:keydown лучше DOM-слушателя: он стоит в собственной цепочке ввода игры, по порядку, и его cancel() игра уважает. building:place может запретить постройку, которую мод считает недопустимой, — ни одно событие этого не умеет.

Патчинг игры

То, что большинство упускает: обычный мод из Workshop уже умеет переписывать бандл игры. Без загрузчика, без инсталлятора, не трогая app.asar.

Область

Любой .js внутри игровой папки js/. Абсолютные пути, сегменты .. и буквы дисков отклоняются.

Дисциплина

expectedMatches обязан быть положительным целым, и патч отклоняется, если реальное число совпадений другое — так обновление игры ломает мод громко.

Атомарность

Патчи с общим atomicGroup применяются вместе. Один промах откатывает всю группу, остальные помечаются пропущенными.

Движок сообщает результат по каждому патчуapplied, actualMatches и reason вроде atomic_group_rolled_back — и не показывает игроку ничего из этого. Вот эта дыра и ждёт своего мода.

Main API 281 методов

Отсортировано по размеру. Раскрой неймспейс, чтобы увидеть методы, число аргументов и функцию движка за каждым из них.

structuresРегистрация машин, патчинг существующих, чтение и изменение построенного.31
методарг.вызов движка
recipes.register
processing.register2structures.processing.register
processing.isEnabledAt2structures.processing.isEnabledAt
processing.setEnabledAt3structures.processing.setEnabledAt
addProcessor2structures.addProcessor
register2structures.register
updateDefinition3structures.updateDefinition
addVariant3structures.addVariant
forEachOfType2structures.forEachOfType
registerPlacementConfig1structures.registerPlacementConfig
getAtCell2structures.getAtCell
getDefinitionByType1structures.getConfig
getUnlockedTypes0structures.getUnlockedTypes
getTypeFromId1structures.resolveTypeName
hasBuiltAtCell2structures.hasBuiltAtCell
isBlockedByPlayerAtCell2structures.isBlockedByPlayer
isLauncherAtCell2structures.isLauncherAt
isType2structures.isType
isTypeAtCell3structures.isTypeAt
isUnlockedByType1structures.isUnlocked
mapValueToSpritesheetIndexstructures.mapValueToSpritesheetIndex
setSpritesheetIndex2structures.setSpritesheetIndex
setSpritesheetIndexAtCell3structures.setSpritesheetIndexAt
setSpritesheetIndexByValue3structures.setSpritesheetIndexByValue
setSpritesheetIndexByValueAtCell4structures.setSpritesheetIndexByValueAt
update2structures.update
setData3structures.setData
buildAtCellWhenIdle4world.runWhenSimulationIdle, structures.build
removeAtCellWhenIdle3world.runWhenSimulationIdle, structures.removeAt
removeBetweenCellsWhenIdle5world.runWhenSimulationIdle, structures.removeBetween
removeAtCellsWhenIdle2world.runWhenSimulationIdle, structures.removeAtPositions
elementsРегистрация песка, жидкостей и газов; чтение и запись отдельных клеток.29
методарг.вызов движка
getRegisteredTypes0elements.getRegisteredTypes
register1elements.register
updateDefinition2elements.updateDefinition
addInteractionInfo2elements.addInteractionInfo
getTypeFromId1elements.getElementTypeFromId
getNameByType1elements.getName
getDefinitionByType1elements.getConfig
getTypeAtCell2elements.getTypeAtCell
getResolvedTypeAtCell2elements.getResolvedTypeAtCell
getResolvedTypeFromCellId1elements.getResolvedTypeFromCellId
getInfoAtCell2elements.getInfoAtCell
getMatterTypeAtCell2elements.getMatterTypeAtCell
isTypeAtCell3elements.isTypeAt
isFreeFallingAtCell2elements.getResolvedTypeAtCell, elements.isFreeFalling
findFreeCellInStructure3elements.findFreePositionInStructure
createAtCellWhenIdle4world.isCellEmpty, elements.createAt
replaceAtCellWhenIdle4world.getCellId, world.mutateCellWhenIdle, elements.replaceAt
removeAtCellWhenIdle3elements.getResolvedTypeAtCell, elements.removeAt
teleportBetweenCellsWhenIdle4world.getCellId, world.runWhenSimulationIdle, elements.moveAtSimulationIdle
getVelocityAtCell2elements.getResolvedTypeAtCell, elements.getVelocity
setVelocityAtCellWhenIdle3elements.setVelocity
addParticleVelocityAtCellWhenIdle4elements.addParticleVelocity
convertToParticleAtCellWhenIdle3elements.convertToParticle
convertFromParticleAtCellWhenIdle2elements.convertFromParticle
getDataFieldAtCell3elements.getResolvedTypeAtCell, elements.getDataField
setDataFieldAtCellWhenIdle4elements.getResolvedTypeAtCell, elements.setDataField
refreshColorAtCellWhenIdle2elements.refreshColorAt
setPhysicsAtCellWhenIdle3elements.getResolvedTypeAtCell, elements.setPhysics, world.reportActivityToChunk
setDurationAtCellWhenIdle4elements.getResolvedTypeAtCell, elements.setDuration
i18nКлючи перевода, смена локали, форматирование чисел.17
методарг.вызов движка
ti18n.t
registeri18n.register
getLocalei18n.getLocale
hasTranslationi18n.hasTranslation
setLocalei18n.setLocale
getLanguagesi18n.getLanguages
getAvailableLocalesi18n.getAvailableLocales
formatNumberi18n.formatNumber
keyi18n.key
getNamei18n.getName
getDescriptioni18n.getDescription
translatablei18n.translatable
setGlobali18n.setGlobal
getGlobali18n.getGlobal
clearGlobali18n.clearGlobal
getGlobalsi18n.getGlobals
formatKeyForDisplayi18n.formatKeyForDisplay
uiВнедрение React, слоты оверлеев, тосты, диалоги, фокус геймпада.14
методарг.вызов движка
update2ui.update
openPauseMenu0ui.openPauseMenu
showTooltip1ui.showTooltip
toast2ui.toast
alert2ui.alert
confirm2ui.confirm
prompt5ui.prompt
overlays.register3ui.overlays.register
overlays.unregister2ui.overlays.unregister
overlays.update1ui.overlays.update
inject2ui.overlays.register, ui.overlays.unregister
navigation.useFocusable
navigation.useFocusScope
navigation.controllerFocusClass
terrainsРегистрация террейна; чтение и повреждение слоя террейна.13
методарг.вызов движка
register1terrains.register
updateDefinition2terrains.updateDefinition
getTypeFromId1terrains.getTypeByName
getTypeAtCell2terrains.getTypeAtCell
getDataAtCell2terrains.getTerrainData
isAtCell2terrains.isAtCell
isTypeAtCell3terrains.isTypeAtCell
isCellIdTerrainterrains.isCellIdTerrain
createAtCellWhenIdle4world.isCellEmpty, terrains.createAt
replaceAtCellWhenIdle4world.getCellId, world.mutateCellWhenIdle, terrains.replaceAt
removeAtCellWhenIdle3world.getCellId, terrains.isCellIdTerrain, terrains.removeAt
damageAtCell3terrains.damageTerrain
setHpAtCellWhenIdle3terrains.isAtCell, terrains.setTerrainHP
worldId клеток, туман, раскопки, выпавшие предметы.13
методарг.вызов движка
getCellIdAtCell2world.getCellId
isCellEmptyAtCell2world.isCellEmpty
isTerrainAtCell2world.isTerrainAt
runWhenSimulationIdle1world.runWhenSimulationIdle
reportActivityAtCell2world.reportActivityToChunk
excavateAtCell5world.excavate
revealFogAtCell2world.revealFogAtCell
redrawAroundCellWhenIdle3world.mutateCellWhenIdle, world.redrawSurroundingCells
pickups.spawnAtWorld5world.pickups.spawn
pickups.destroy1world.pickups.destroy
pickups.pickUp1world.pickups.pickUp
pickups.getAll0world.pickups.getAll
pickups.getById1world.pickups.getById
playerПозиция, движение, инвентарь, разблокированные постройки.12
методарг.вызов движка
getWorldPosition0player.getPosition
setWorldPosition2player.setPosition
setVelocity2player.setVelocity
setMovementSpeedMultiplier1player.setMovementSpeedMultiplier
setMovementMode1player.setMovementMode
isOnGround0player.isOnGround
teleportToGround0player.teleportToGround
isCollidingWithCell2player.isCollidingWithCell
isWithinRadiusOfCell3player.isWithinRadius
isWorldPositionClear2player.isPositionClear
inventory.addFromId1player.inventory.add
buildings.unlockByType1player.buildings.add
inputПривязки клавиш, позиция мыши в клетках, состояние модификаторов.10
методарг.вызов движка
registerBinding3input.registerKeyBinding
getMouseCellPosition0input.getMouseCellPosition
getBoundKeys1input.getBoundKeys
getDisplayKey2input.getDisplayKey
triggerBinding1input.triggerBinding
pressBinding1input.pressBinding
releaseBinding1input.releaseBinding
resetMouseState0input.resetMouseState
isCtrlHeld0input.isCtrlHeld
isAltHeld0input.isAltHeld
projectilesРегистрация и спавн снарядов.7
методарг.вызов движка
register1projectiles.register
getDefinitionById1
createBlueprintFromId1projectiles.createBlueprint
getAll0projectiles.getAll
getById1projectiles.getAll
remove1projectiles.remove
spawnAtWorld4projectiles.spawn
soundПроигрывание звуков, слои, затухание по расстоянию.7
методарг.вызов движка
play2sound.play
playActive2sound.playActive
playLayers2sound.playLayers
calculateDistanceOptionsAtWorld3sound.calculateDistanceOptions
stopById1sound.stop
stopActive0sound.stopActive
stopAll0sound.stopAll
storageХранение данных мода — в сейве или локально на машине.7
методарг.вызов движка
ensure1storage.ensure
get2storage.get
set3storage.set
remove2storage.remove
local.getstorage.local.get
local.setstorage.local.set
local.removestorage.local.remove
authorizationМожно ли игроку строить, копать и применять инструменты в клетке.6
методарг.вызов движка
canBuildAtCell2authorization.canBuild
canGrabAtCell2authorization.canGrab
canUseTool2authorization.canUseTool
canUseToolAtCell3authorization.canUseToolAt
getZoneIdAtCell2authorization.getZoneIdAt
getPlayerZoneId0authorization.getPlayerZoneId
effectsЧастицы, временные источники света, лучи, волны искажения.6
методарг.вызов движка
createDistortionWaveAtWorld3effects.createDistortionWave
createEffectAtWorld4effects.createEffect
createLaserAtWorld5effects.createLaser
createLightAtWorld3effects.createLight
createParticlesAtWorld3effects.createParticles
removeLightById1effects.removeLight
energyВход в энергосеть, выработка и потребление энергии.6
методарг.вызов движка
registerType3energy.registerType
addAtCell4energy.add
consume2energy.consume
consumeExcludingNetworkAtCell3energy.consumeExcludingNetwork
getNetworkAtCell2energy.getNetwork
getNetworkFreeCapacityAtCell2energy.getNetworkFreeCapacity
itemsРегистрация предметов инвентаря и инструментов.6
методарг.вызов движка
register1items.register
updateDefinition2items.updateDefinition
getDefinitionById1
createFromId1items.create
getActive0items.getActive
isActiveById2items.isActive
lightsВременный свет для эффектов и постоянный свет в мире.6
методарг.вызов движка
vfx.createAtWorld
vfx.removeById
persistent.createAtWorld3lights.persistent.create
persistent.removeAtWorld2lights.persistent.removeAt
persistent.fadeAtWorld3lights.persistent.fadeAt
persistent.markDirty0lights.persistent.markDirty
techЧтение, правка и добавление узлов дерева технологий.6
методарг.вызов движка
getDefinitionByIdtech.getDefinition
updateDefinitiontech.updateDefinition
addDefinitiontech.addDefinition
registerNodetech.registerNode
isLockedById1tech.isLocked
setLockedById2tech.setLocked
collectorЦенность клеток в золоте и уведомление о подборе.5
методарг.вызов движка
getValueFromCellId1collector.getValueFromCellId
getValueByType1collector.getValueFromElementType
isCellIdCollectable1collector.isCellCollectable
isCellIdCollectableForSprite1collector.isCellCollectableForSprite
notifyPickupAtCell2collector.notifyPickup
spritesЗагрузка текстур, в том числе из папки самого мода.5
методарг.вызов движка
load3sprites.load
loadFromMod3sprites.load
getById1sprites.get
hideAllPlayerModSprites0sprites.hideAllPlayerModSprites
rotatePlayerModSprites1sprites.rotatePlayerModSprites
upgradesРегистрация категорий улучшений и уровней.5
методарг.вызов движка
registerCategory1upgrades.registerCategory
register1upgrades.register
updateDefinition3upgrades.updateDefinition
getLevelById2upgrades.getLevel
getAvailableLevelById2upgrades.getAvailableLevel
buildingПривязка к сетке при постройке, блокировка, выбор постройки.4
методарг.вызов движка
getSnappedPositionAtCell2building.getSnappedCellPosition
isBlockedAtCell2building.isBlockedByTerrainOrElements
cancelPlacement0building.cancelPlacement
selectStructure1building.selectStructure
renderingПозиции отрисовки, метрики сетки, контекст оверлея, шейдеры.4
методарг.вызов движка
getDrawPositionAtCell2rendering.getCellDrawPos
getGridMetrics0rendering.getGridMetrics
getOverlayViewportSize0rendering.getOverlayViewportSize
withOverlayContext1rendering.withOverlayContext
toolsРазмер и состояние захвата.4
методарг.вызов движка
grabber.setSize1tools.setGrabberSize
grabber.getSize0tools.getGrabberSize
grabber.isActive0tools.isGrabberActive
grabber.isLoaded0tools.isGrabberLoaded
utilsРасстояние, направление, угол, линия между точками.4
методарг.вызов движка
getDistanceutils.getDistance
getDirectionutils.getDirection
getAngleutils.getAngle
getCoordinatesBetweenPointsutils.getCoordinatesBetweenPoints
actionАктивное и выбранное действие и его произвольные данные.3
методарг.вызов движка
getActive0action.getActive
getSelected0action.getSelected
setCustomData1action.setCustomData
assetsURL ассетов и выбор провайдера.3
методарг.вызов движка
getUrl1(local) x.o
getSelectedProvider1(local) L.Ob
selectProvider2(local) L.jq
cameraФокус и слежение.3
методарг.вызов движка
snapToPlayer0camera.snapToPlayer
setFocusAtWorld2camera.setFocusAtWorld
releaseFocus1camera.releaseFocusToPlayer
mapsАктивная и доступные карты; запуск карты.3
методарг.вызов движка
getActive0maps.getActive
getAvailable0maps.getAvailable
start1maps.start
processingРецепты для грядки, шейкера и kinetic press.3
методарг.вызов движка
registerGrower1
registerShaker1
registerKineticPress1
settingsСобственные настройки мода и уведомления об их изменении.3
методарг.вызов движка
get1
getAll0(local) W.FG
onChange1
cooldownОбщие таймеры перезарядки.2
методарг.вызов движка
check2cooldown.check
isReady2cooldown.isReady
discoveriesЧто игрок уже открыл.2
методарг.вызов движка
addElementByType1discoveries.addElement
addTerrainByType1discoveries.addTerrain
eventsПодписка на игровые события и их отправка.2
методарг.вызов движка
on2events.on
emit2events.emit
fireГорит ли клетка и поджигание.2
методарг.вызов движка
canBurnElementAtCell2fire.canBurnElementAt
burnElementAtCellWhenIdle2fire.canBurnElementAt, fire.burnElementAt
gameConfigЧтение конфигурации игры.2
методарг.вызов движка
get1(local) D.nO
getAll0(local) D.dx
gridОбход клеток в прямоугольнике или круге.2
методарг.вызов движка
forEachCellInRect5grid.iterateRect
forEachCellInCircle4grid.iterateCircle
hooksПерехват (отмена) или изменение вызовов движка.2
методарг.вызов движка
intercept3hooks.intercept
modify3hooks.modify
patternsКруговые паттерны и раскопки по паттерну.2
методарг.вызов движка
createCirclepatterns.createCircle
excavateAtCell6patterns.excavate
randomЦелые и вещественные из сидированного генератора.2
методарг.вызов движка
intrandom.int
floatrandom.float
resourcesКоличество ресурсов.2
методарг.вызов движка
collectFluxiteAtCell2resources.collectFluxiteAtCell
updateEnergy2resources.updateEnergy
sharedSharedArrayBuffer — единственный канал из main в worker.2
методарг.вызов движка
buffers.create2workers.shared.create
buffers.get1workers.shared.get
structureBehaviorsПревращение постройки в конвейер или лаунчер.2
методарг.вызов движка
registerConveyorType2conveyors.registerType
registerLauncherType1launchers.registerType
timeМиллисекунды и счётчик тиков.2
методарг.вызов движка
getTimeMs0
getTick0
excavationРегистрация профилей раскопок.1
методарг.вызов движка
registerProfile2excavation.registerProfile
modsПровайдеры ассетов из других модов.1
методарг.вызов движка
getProviders1(local) L.KT
progressionЗавершение шагов прогрессии.1
методарг.вызов движка
complete1progression.complete
raycastЛуч сквозь мир.1
методарг.вызов движка
castFromWorld4raycast.cast
reactionsРегистрация реакций между элементами.1
методарг.вызов движка
registerContact1reactions.registerContact
sceneКакой экран активен. MainMenu 1, Intro 2, Deploy 3, Game 4.1
методарг.вызов движка
getActive0scene.getActive
scheduleОтложенные колбэки.1
методарг.вызов движка
nextTick1schedule.nextTick
signalsРегистрация постройки как цели сигнала.1
методарг.вызов движка
targets.register2signals.targets.register
triggersРегистрация повторяющегося таймера.1
методарг.вызов движка
register2triggers.register
workersПереключение post-update на симуляционных воркерах.1
методарг.вызов движка
setPostUpdateEnabled1workers.shared.create

Worker API 88 методов

Вчетверо меньше, и это намеренно: этот поток существует, чтобы быстро трогать клетки.

elementsПрямое чтение и запись клеток — здесь и место работе с отдельными частицами.26
методарг.вызов движка
getTypeFromId1elements.getElementTypeFromId
getDefinitionByType1elements.getConfig
getTypeAtCell2elements.getTypeAtCell
getResolvedTypeAtCell2elements.getResolvedTypeAtCell
getResolvedTypeFromCellId1elements.getResolvedTypeFromCellId
getInfoAtCell2elements.getInfoAtCell
getMatterTypeAtCell2elements.getMatterTypeAtCell
isTypeAtCell3elements.isTypeAt
isFreeFallingAtCell2elements.getResolvedTypeAtCell, elements.isFreeFalling
createAtCell4world.isCellEmpty, elements.createAt
replaceAtCell4elements.replaceAt
removeAtCell3elements.getResolvedTypeAtCell, elements.removeAt
moveBetweenCells4elements.move
teleportBetweenCells4elements.teleport
swapCells4elements.swap
getVelocityAtCell2elements.getResolvedTypeAtCell, elements.getVelocity
setVelocityAtCell3elements.setVelocity
addParticleVelocityAtCell4elements.addParticleVelocity
convertToParticleAtCell3elements.convertToParticle
convertFromParticleAtCell2elements.convertFromParticle
getDataFieldAtCell3elements.getResolvedTypeAtCell, elements.getDataField
setDataFieldAtCell4elements.getResolvedTypeAtCell, elements.setDataField
refreshColorAtCell2elements.refreshColorAt
markMovementBlockedByElementIndex1elements.markMovementBlocked
setPhysicsAtCell3elements.getResolvedTypeAtCell, elements.setPhysics, world.reportActivityToChunk
setDurationAtCell4elements.getResolvedTypeAtCell, elements.setDuration
structuresПроверка, что построено в клетке, и чтение состояния обработки.14
методарг.вызов движка
processing.isEnabledAt2structures.processing.isEnabledAt
getAtCell2structures.getAtCell
getDefinitionByType1structures.getConfig
getTypeFromId1structures.resolveTypeName
hasBuiltAtCell2structures.hasBuiltAtCell
isType2structures.isType
isTypeAtCell3structures.isTypeAt
forEachOfType2structures.forEachOfType
update2structures.update
setData3structures.setData
setSpritesheetIndex2structures.setSpritesheetIndex
setSpritesheetIndexAtCell3structures.setSpritesheetIndexAt
setSpritesheetIndexByValue3structures.setSpritesheetIndexByValue
setSpritesheetIndexByValueAtCell4structures.setSpritesheetIndexByValueAt
terrainsЧтение, создание и повреждение террейна из симуляционного потока.11
методарг.вызов движка
getTypeFromId1terrains.getTypeByName
getTypeAtCell2terrains.getTypeAtCell
getDataAtCell2terrains.getTerrainData
isAtCell2terrains.isAtCell
isTypeAtCell3terrains.isTypeAtCell
isCellIdTerrainterrains.isCellIdTerrain
createAtCell4world.isCellEmpty, terrains.createAt
replaceAtCell4terrains.replaceAt
removeAtCell3world.getCellId, terrains.isCellIdTerrain, terrains.removeAt
damageAtCell3terrains.damageTerrain
setHpAtCell3terrains.setTerrainHP
collectorСобираемая ценность клетки.5
методарг.вызов движка
getValueFromCellId1collector.getValueFromCellId
getValueByType1collector.getValueFromElementType
isCellIdCollectable1collector.isCellCollectable
isCellIdCollectableForSprite1collector.isCellCollectableForSprite
notifyPickupAtCell2collector.notifyPickup
worldId клеток, пустота, отметка активности, раскопки.5
методарг.вызов движка
getCellIdAtCell2world.getCellId
isCellEmptyAtCell2world.isCellEmpty
isTerrainAtCell2world.isTerrainAt
reportActivityAtCell2world.reportActivityToChunk
excavateAtCell5world.excavate
utilsРасстояние, направление, угол, линия между точками.4
методарг.вызов движка
getDistanceutils.getDistance
getDirectionutils.getDirection
getAngleutils.getAngle
getCoordinatesBetweenPointsutils.getCoordinatesBetweenPoints
effectsЧастицы и свет, поднятые из воркера.3
методарг.вызов движка
createEffectAtWorld4effects.createEffect
createLightAtWorld3effects.createLight
createParticlesAtWorld3effects.createParticles
playerПозиция игрока и проверки близости.3
методарг.вызов движка
getWorldPosition0player.getPosition
isCollidingWithCell2player.isCollidingWithCell
isWithinRadiusOfCell3player.isWithinRadius
eventsПодписка на события симуляции. Некоторым нужен гвард.2
методарг.вызов движка
on3
emit3
fireГорит ли клетка и поджигание.2
методарг.вызов движка
canBurnElementAtCell2fire.canBurnElementAt
burnElementAtCell2fire.canBurnElementAt, fire.burnElementAt
hooksПерехват и изменение вызовов движка внутри симуляции.2
методарг.вызов движка
intercept3
modify3
patternsКруговые паттерны и раскопки по паттерну.2
методарг.вызов движка
createCirclepatterns.createCircle
excavateAtCell6patterns.excavate
randomЦелые и вещественные из сидированного генератора.2
методарг.вызов движка
intrandom.int
floatrandom.float
sharedЧтение буферов, созданных энтри main.2
методарг.вызов движка
buffers.require2workers.shared.get
buffers.get1workers.shared.get
workerИндекс этого потока и общее число потоков.2
методарг.вызов движка
getIndex0
getCount0
mainОтправка события в главный поток. Единственный выход отсюда.1
методарг.вызов движка
emitEvent2
mapsАктивная карта.1
методарг.вызов движка
getActive0maps.getActive
uiТосты. Это весь здешний UI.1
методарг.вызов движка
toast2ui.toast

Каталоги значений

Таблицы выше говорят, что мод может вызвать. Здесь — значения, которые стоит передавать: собраны из того же кода игры, поэтому перегенерируются вместе с ней.

Идентификаторы звуков (63)

Всё, что сама игра передаёт своему звуковому движку, — проигрывается через sound.play(id, options); затухание по расстоянию даёт calculateDistanceOptionsAtWorld, а rateLimitKey позволяет сотне машин звучать одним голосом.

accepting_pianoammo_emptyartifact_shimmerbeadsblipboostboost_overlaybuildbuild4build_startbuild_start2clickcockingcoincollectcyber_clickdenydigdig_2dig_overlaydroidvoice_3eerie_memoryexplosionexplosion2explosion_overlayflamethrowerflamethrower2flamethrower_overlayfluxitefluxite_2fluxite_3force_field_wavesfreezefuture_sirengungun_overlayhummingimpactsjetjet_flybymachinerymachinery_ambiencemachinery_rhythmmachinery_rhythm_2machinery_rhythm_2_bmetallic_crashopenpistolresearchrobomech_servorocket_boosterrocket_explosionrocket_jetrocket_launchrumbleshakesinesprint_booststatic_transmissionsteam_gun_reloadsubtle_shootervacuumvaporize

Ambience-группы структур для поля ambienceGroup в render: clearingFrames, conveyors, launchers, shakers, steamTurbines.

Дефолты gameConfig (81)

То, что возвращает gameConfig.getAll(), пока его никто не переопределил, — включая флаги, которых нет ни в одном меню настроек. customMaps.showCustomMaps и mods.showSubscribedMods поставляются со значением false: целые фичи за одним булем. Поддерево procgen — ручки генератора карт, вплоть до seed.

gameConfigвсе дефолты, в порядке исходника81
ключдефолт
version"…"
fps60
lockFpsfalse
chunkSize40
cellSize4
gravity"…"
upflow"…"
snapGridCellSize4
startingResources0
debug.activefalse
debug.showUnderlyingCellsInStructurestrue
debug.drawChunksfalse
debug.drawChunkFade60
debug.drawRulersfalse
debug.showThreadLoadtrue
debug.controlstrue
debug.defaultBaseHue35
debug.brushSize3
debug.brushShape"circle"
debug.brushThrottle0
debug.highlightBrushtrue
debug.preventDuplicateCellsfalse
debug.doNotDrawStructuresfalse
debug.stopOnDebugCellUpdatefalse
debug.overrideLightSizefalse
debug.overrideTerrainShadowfalse
debug.lightSize700
debug.terrainShadowValue0.995
debug.flashlight.brightness2
debug.flashlight.size200
debug.flashlight.duration100
debug.flashlight.color"[…]"
debug.gameOfLife"…"
debug.countEventsfalse
debug.strictSafeguardsfalse
debug.showLightsfalse
debug.showProximityFadetrue
debug.showFiltersfalse
debug.showAuthorizationZonesfalse
debug.showProximityFadeSelectedOnlyfalse
debug.selectedLightIndex-1
debug.cellInspectorfalse
debug.badDisplaysfalse
debug.i18nDebug.mode"off"
debug.i18nDebug.pseudo.bracketstrue
debug.i18nDebug.pseudo.accentCharstrue
debug.i18nDebug.pseudo.padPercent0.3
debug.i18nDebug.randomScript.script"chinese"
debug.i18nDebug.randomScript.lengthMultiplier1
conveyorDefaultSpeed0.05
useMultithreadingtrue
useExperimentalRendererfalse
obstacleBreakpoint100
playerSize.width12
playerSize.height30
matrixCompression.padding100
blueprintEncoding"binary"
mods.showSubscribedModsfalse
customMaps.showCustomMapsfalse
procgen.useProcgenMaptrue
procgen.showGeneratedMapfalse
procgen.logPerformancetrue
procgen.logVerbosity1
procgen.params.width3840
procgen.params.height3840
procgen.params.scale0.005
procgen.params.threshold0.02
procgen.params.cellSize1
procgen.params.seed"…"
procgen.prefabPlacementBufferCells20
procgen.mossPatchMinDepthCells30
procgen.caveRegionLights.brightness1
procgen.caveRegionLights.size200
procgen.leftWall.enabledfalse
procgen.leftWall.startPosition0.2
procgen.leftWall.steepness0.01
procgen.leftWall.noiseAmount0.15
procgen.leftWall.entrance.enabledfalse
procgen.leftWall.entrance.width200
procgen.leftWall.entrance.height120
procgen.saveGeneratedMapfalse

window.electron (65)

Preload-мост Electron. Моды исполняются в том же renderer, поэтому всё это достижимо из мода: openDevTools(), экспорт и импорт сейвов, папка локальных модов, управление подписками Workshop.

window.electronpreload-мост, как он поставляется65
метод
window.electron.getPlatformSync()
window.electron.getIsSteamDeckSync()
window.electron.getPreferredSystemLanguagesSync()
window.electron.onAppSuspend(callback)
window.electron.onAppResume(callback)
window.electron.diagnostics()
window.electron.checkLicense()
window.electron.writeGameEvent(eventName, dimensions, measurements)
window.electron.platformPrimeAchievements(ids)
window.electron.platformShowReauthPrompt(reason)
window.electron.appQuit()
window.electron.openExternalBrowser(url)
window.electron.onXboxUserSignedOut(callback)
window.electron.onXboxLicenseLost(callback)
window.electron.onXboxUserSignedIn(callback)
window.electron.save(id, name, data)
window.electron.saveSerialized(id, name, dataJson, metadata)
window.electron.load(id)
window.electron.deleteSave(id)
window.electron.loadRaw(name)
window.electron.exportSave(id)
window.electron.importSave(bytes)
window.electron.getSaveFiles()
window.electron.getSaveFolder()
window.electron.localMods.getFolder()
window.electron.localMods.openFolder()
window.electron.localMods.list()
window.electron.localMods.upload(modId)
window.electron.getLastPlayedGameSync()
window.electron.saveLastPlayedGame(game)
window.electron.clearLastPlayedGame()
window.electron.saveExistsSync(id)
window.electron.getSettingsSync()
window.electron.saveSettings(settings)
window.electron.setFullscreen(shouldBeFullscreen)
window.electron.openDevTools()
window.electron.isFilePatchingActiveSync()
window.electron.platform.isInitialized()
window.electron.platform.getPlayerName()
window.electron.platform.getPlayerId()
window.electron.platform.getAppId()
window.electron.platform.unlockAchievement(achievementId)
window.electron.platform.isAchievementUnlocked(achievementId)
window.electron.platform.clearAchievement(achievementId)
window.electron.platform.cloudSave(fileName, data)
window.electron.platform.cloudLoad(fileName)
window.electron.platform.cloudFileExists(fileName)
window.electron.platform.cloudDelete(fileName)
window.electron.platform.cloudSync()
window.electron.platform.workshop.subscribe(itemId)
window.electron.platform.workshop.unsubscribe(itemId)
window.electron.platform.workshop.installInfo(itemId)
window.electron.platform.workshop.downloadInfo(itemId)
window.electron.platform.workshop.getState(itemId)
window.electron.platform.workshop.getSubscribedItems()
window.electron.platform.workshop.getItem(itemId)
window.electron.platform.workshop.download(itemId, highPriority)
window.electron.platform.workshop.getSandkitMods()
window.electron.platform.overlay.openUrl(url)
window.electron.log(level, scope, message)
window.electron.getSystemInfo()
window.electron.customMaps.save(id, name, data)
window.electron.customMaps.load(id)
window.electron.customMaps.list()
window.electron.customMaps.delete(id)
Ничто из этого не покрыто apiVersion. Та же категория, что sandkit.engine.api: настоящее, полезное и вольно меняться в любом патче. Оборачивайте каждый вызов, падайте мягко.

За пределами api

sandkit.api — не весь объект, который получает мод. Рядом лежат ещё три члена, и ни один из них не метод: поэтому их нет в таблицах выше, и поэтому же без них не нарисовать ни одной кнопки.

sandkit.enums (22 / 323)

Перечисления самой игры, переэкспортированные поимённо. Это те числа, которых API и ждёт: ui.update(enums.ComponentId.Hotbar), scene.getActive() === enums.Scene.MainMenu, сравнение состояния клавиши с enums.KeyState.Pressed. Написать литерал вместо этого можно — ровно до патча, который перенумерует.

enums.CellType31
члензначение
Empty0
Element1
Dirt2
SporeSoil3
Fog4
FogJetpackBlock5
FogWater6
FreezingIceSoil7
Divider8
Grass9
Moss10
GoldSoil11
Petal12
FogLava13
Fluxite14
Block15
SlidingBlock16
SlidingBlockLeft17
SlidingBlockRight18
ConveyorLeft19
ConveyorRight20
ShakerLeft21
ShakerRight22
Stone23
VelocitySoaker24
Ice25
Grower26
NascentWater27
SandiumSoil28
Obsidian29
Crackstone30
enums.ElementType20
члензначение
Sand1
Particle2
Water3
WetSand4
Sandium5
Residue6
Gold7
Gloom8
Shake9
Steam10
Fire11
FreezingIce12
Flame13
BurntResidue14
Seed15
WetSeed16
Seedling17
Petalium18
Lava19
Basalt20
enums.MatterType8
члензначение
Solid1
Liquid2
Particle3
Gas4
Static5
Slushy6
Wisp7
Powder8
enums.StructureType27
члензначение
ConveyorLeft1
ConveyorRight2
ShakerLeft3
ShakerRight4
LauncherUp5
LauncherLeft6
LauncherRight7
SplitterLeft8
SplitterRight9
Dropper10
Foundation11
FoundationAngledLeft12
FoundationTriangleLeftDel13
FoundationAngledRight14
FoundationTriangleRightDel15
Collector16
FilterLeft17
FilterRight18
SlidingFoundation19
VelocitySoaker20
Grower21
SoundBox22
Pipe23
Pump24
LiquidVent25
Light26
FluxEmanator27
enums.ItemType4
члензначение
Weapon1
Tool2
Consumable3
Mod4
enums.ItemId16
члензначение
Shovel1
Grabber2
Demolisher3
GrapplingHook4
Vacuum5
Gun6
Copier7
RocketLauncher8
Digger9
Shotgun10
Teleporter11
Flamethrower12
PipeRemover13
Hauler14
Cryoblaster15
MegaShotgun16
enums.ProjectileType6
члензначение
Bullet1
Rocket2
GrapplingHook3
Fire4
Digger5
Mod6
enums.ActionType4
члензначение
Weapon1
Building2
Tool3
Mod4
enums.ActionState3
члензначение
Start1
Active2
End3
enums.AbilityType4
члензначение
Dig1
Shoot2
Spray3
Laser4
enums.ReloadType3
члензначение
Clip1
Single2
OverTime3
enums.ComponentId28
члензначение
Hotbar1
SoundBoxConfig2
Root4
Menu5
Management6
FilterConfig7
Resources8
TechTree9
Tutorial10
Loader11
Options12
ShortcutHelper13
Upgrades14
Tooltip15
Notifications16
Objectives17
DroneAdminList18
HotbarOverlays19
IntroScreen20
StoryNotifications21
FactoryProgress22
Dialogs23
GlobalOverlays24
Lexicon25
ModsScreen26
CustomMapsScreen27
CinematicPanel28
Feedback29
enums.KeyBinding27
члензначение
OpenBuildMenu"OpenBuildMenu"
GrapplingHook"GrapplingHook"
Escape"Escape"
OpenTechTree"OpenTechTree"
OpenInventory"OpenInventory"
ReverseBuildDirection"ReverseBuildDirection"
Marquee"Marquee"
Pause"Pause"
Copy"Copy"
Paste"Paste"
Flip"Flip"
Delete"Delete"
PauseCamera"PauseCamera"
OpenUpgrades"OpenUpgrades"
BuildMode"BuildMode"
Demolish"Demolish"
Hover"Hover"
Ruler"Ruler"
Left"Left"
Right"Right"
Boost"Boost"
Descend"Descend"
SprintBoost"SprintBoost"
OverrideReplaceStructures"OverrideReplaceStructures"
QuickSave"QuickSave"
QuickLoad"QuickLoad"
ToggleGameHud"ToggleGameHud"
enums.KeyState5
члензначение
Up1
Down2
Pressed3
Released4
All5
enums.BuildMode2
члензначение
Linear1
Rectangular2
enums.BuildingClearance4
члензначение
Available1
FullyBlocked2
PartiallyBlocked3
CanBeReplaced4
enums.AuthorizationType6
члензначение
NoJetpack1
NoGrab2
NoBuild3
NoTool4
NoExcavation5
NoToolExceptFlamethrower6
enums.DroneType2
члензначение
Digger1
Hauler2
enums.WorldItemType4
члензначение
Artifact1
GlyphKey2
Stratacore3
Orb4
enums.Scene4
члензначение
MainMenu1
Intro2
Deploy3
Game4
enums.Tech110
члензначение
Shaker1
Conveyors2
Guns13
Filters14
Flamethrower5
Gun6
KineticPress7
Guns28
Drones19
Upgrading210
Filters211
Upgrading312
Upgrading413
Upgrading514
Upgrading615
Upgrading716
Upgrading817
Upgrading918
Upgrading1019
PlanterBox20
Thermo21
Rocket22
Pipes23
StaticLights24
Drones225
Smelter26
Tools427
Guns328
Pipes229
ConveyorsMk230
Lights231
Refining632
Refining733
Guns434
Guns535
Tools536
Tools637
Filters338
Filters439
Pipes340
Pipes441
Logistics342
Logistics443
Lights344
Lights445
Drones346
Drones447
Alien48
Electricity49
AlienCore50
Emanators151
AlienPlasmaConduits52
AlienQuantumMatrix53
AlienPlasmaCore54
AlienVoidEngine55
FlareGun56
Sweeper57
Utilities358
Cryoblaster59
Vacuum60
Utilities661
Utilities762
Filters63
AdvancedFilters64
Infrastructure365
Decorations166
Decorations267
Decorations368
Blocks169
Drill70
SteamTurbine71
Electricity372
Electricity473
Logic174
Logic275
Logic376
Logic477
Various178
Various279
Various380
Locator81
QuantumPortal82
VoidRift83
Blink84
Recall85
ImplosionGun86
Refining887
Tools788
Diggers89
Haulers90
Map91
ColoringTool92
SignalGate93
GrapplingHook94
GlassFoundation95
PrecisionTools96
SignalDevices97
SignalControls98
LogicGates99
RetroConsole100
WallTool101
Corraller102
PlainFoundation103
ClearingFrame104
Heatmap105
MiningLaser106
GoldBattery107
Hover108
SprintBoost109
CritterFence110
enums.TechStatus5
члензначение
Available0
Visible1
Researched2
Unknown3
Hidden4

sandkit.react (18.3.1)

Замороженная копия React самой игры. Компоненты мода рендерятся внутри её дерева, поэтому хуки работают как обычно — но брать их надо отсюда: вторая копия React в одном дереве работать не будет.

ChildrenComponentFragmentProfilerPureComponentStrictModeSuspensecloneElementcreateContextcreateElementcreateFactorycreateRefforwardRefisValidElementlazymemostartTransitionuseCallbackuseContextuseDebugValueuseDeferredValueuseEffectuseIduseImperativeHandleuseInsertionEffectuseLayoutEffectuseMemouseReduceruseRefuseStateuseSyncExternalStoreuseTransitionversion
Публичная поверхность этого React присутствует целиком, включая хуки. ui.inject и ui.overlays.register принимают собранные им компоненты; JSX в entry недоступен, так что это react.createElement руками или маленький помощник h().

sandkit.state (424 / 1362)

Живое состояние игры, тот же объект, что и sandkit.engine.state. Сюда идут, когда в API нет геттера: буфер энергии, открытые окна, счётчики ресурсов. О его форме в поставляемом коде нет ничего, поэтому таблица снята с запущенной игры — только имена, типы и размеры, без значений.

На странице — три уровня. Дамп снят до 4 и содержит 1362 путей целиком: остальное в data/state.json. Ветки, ключи которых — id, а не структура (какие моды установлены, какие технологии в сейве), оставлены узлом без детей: обход описывал бы одну машину, а не игру — state.sandkit (1038), state.session.lexicon.entriesById (337), state.store.mods (120), state.store.player.tech (71), state.shared.mods (19), state.session.settings.externalModSettings (14).

state.environmentсборка и платформа4
путьтипразмер
state.environmentobject2
state.environment.contextnumber
state.environment.multithreadingobject1
state.environment.multithreading.simulationobject16
state.sandkitсам слой модов — отражает то, что установлено у снявшего дамп1
путьтипразмер
state.sandkitobject7
state.sessionтолько этот запуск: ввод, окна, камера, рендеринг, настройки193
путьтипразмер
state.sessionobject51
state.session.actionobject3
state.session.action.customDatanull
state.session.action.pointobject2
state.session.action.stateobject3
state.session.actionLockedboolean
state.session.ambienceobject5
state.session.ambience.clearingFramesobject2
state.session.ambience.conveyorsobject2
state.session.ambience.launchersobject2
state.session.ambience.shakersobject2
state.session.ambience.steamTurbinesobject2
state.session.animationsobject1
state.session.animations.playerobject3
state.session.buildingobject6
state.session.building.activeStructureTypenull
state.session.building.amountOfTilesnumber
state.session.building.ignoreAngleLockboolean
state.session.building.lockedAnglenull
state.session.building.placingboolean
state.session.building.startobject2
state.session.buttonsobject1
state.session.buttons.pressedboolean
state.session.cacheobject2
state.session.cache.pipesobject4
state.session.cache.structuresobject4
state.session.cameraobject2
state.session.camera.xnumber
state.session.camera.ynumber
state.session.cheatobject1
state.session.cheat.bypassCostsboolean
state.session.cinematicundefined
state.session.colorsobject1
state.session.colors.schemeobject2
state.session.constructionobject3
state.session.construction.demolisherActiveboolean
state.session.construction.marqueeActiveboolean
state.session.construction.rulerActiveboolean
state.session.debugobject1
state.session.debug.brushobject4
state.session.effectsarray0
state.session.explosionsarray0
state.session.externalModsobject6
state.session.externalMods.diagnosticsarray of object3
state.session.externalMods.missingSavedModsarray of string3
state.session.externalMods.orderedModsarray of object14
state.session.externalMods.statusesarray of object14
state.session.externalMods.workerEntriesarray of object1
state.session.externalMods.workerResultsarray of object8
state.session.factoryProcessRatesFloat64Array4
state.session.inputobject9
state.session.input.actionobject2
state.session.input.bindingStatesobject0
state.session.input.currentLastKeystring
state.session.input.currentLastKeyCodestring
state.session.input.deckCursorobject5
state.session.input.deckLastManagementTabstring
state.session.input.keysobject57
state.session.input.modestring
state.session.input.mouseobject10
state.session.lerpCameraboolean
state.session.lexiconobject3
state.session.lexicon.compiledboolean
state.session.lexicon.entriesarray of object337
state.session.lexicon.entriesByIdobject337
state.session.lightZonesarray of array150
state.session.lightsarray of null100
state.session.mainSensorCacheobject1
state.session.mainSensorCache.cacheobject1
state.session.modsobject1
state.session.mods.signalsobject13
state.session.monitorobject1
state.session.monitor.threadsarray of object8
state.session.movementSpeedMultipliernumber
state.session.musicobject2
state.session.music.ambientobject1
state.session.music.engineobject30
state.session.nextTickCallbacksarray0
state.session.notificationsobject2
state.session.notifications.storyarray0
state.session.notifications.toaststring
state.session.overrideCameraboolean
state.session.pausedboolean
state.session.platformstring
state.session.prefabWorldItemCacheobject1
state.session.prefabWorldItemCache.cacheobject10
state.session.reconModeboolean
state.session.renderingobject24
state.session.rendering.backgroundChannelobject2
state.session.rendering.canvasobject0
state.session.rendering.channelobject2
state.session.rendering.foregroundChannelobject2
state.session.rendering.foregroundOffscreenCanvasobject0
state.session.rendering.foregroundOffscreenContextobject0
state.session.rendering.imagesobject102
state.session.rendering.obstacleCanvasobject0
state.session.rendering.obstacleChannelobject2
state.session.rendering.obstacleContextobject0
state.session.rendering.obstacleOffscreenCanvasobject0
state.session.rendering.obstacleOffscreenContextobject0
state.session.rendering.offscreenCanvasobject0
state.session.rendering.offscreenContextobject0
state.session.rendering.offscreenOutlineCanvasobject0
state.session.rendering.offscreenOutlineContextobject0
state.session.rendering.overlayCanvasobject0
state.session.rendering.overlayContextobject0
state.session.rendering.pixiobject43
state.session.rendering.worldCanvasobject0
state.session.rendering.worldChannelobject2
state.session.rendering.worldContextobject0
state.session.rendering.worldOffscreenCanvasobject0
state.session.rendering.worldOffscreenContextobject0
state.session.resolutionobject2
state.session.resolution.heightnumber
state.session.resolution.widthnumber
state.session.runtimestring
state.session.savingboolean
state.session.scalenumber
state.session.settingsobject23
state.session.settings.autosaveIntervalnumber
state.session.settings.cursorScalenumber
state.session.settings.disableBackgroundShaderboolean
state.session.settings.disableShadowsboolean
state.session.settings.externalModSettingsobject14
state.session.settings.focusLossobject3
state.session.settings.frameRateCapnumber
state.session.settings.hardModeboolean
state.session.settings.hotbarCountnumber
state.session.settings.hybridSchedulingboolean
state.session.settings.keyBindingsobject66
state.session.settings.localestring
state.session.settings.lockHotbarboolean
state.session.settings.lockSkyColorboolean
state.session.settings.pipesModeViewboolean
state.session.settings.schedulingModenumber
state.session.settings.settingsVersionnumber
state.session.settings.showFpsboolean
state.session.settings.soundobject3
state.session.settings.uiScalenumber
state.session.settings.upgradesHideMaxboolean
state.session.settings.videoZoomnumber
state.session.settings.windowModestring
state.session.soundBoxobject1
state.session.soundBox.selectedNoteobject2
state.session.soundEngineobject8
state.session.soundEngine.audioContextobject0
state.session.soundEngine.gateobject1
state.session.soundEngine.globalVolumenumber
state.session.soundEngine.limiterobject0
state.session.soundEngine.masterGainobject0
state.session.soundEngine.mutedboolean
state.session.soundEngine.outputLimiterobject0
state.session.soundEngine.sfxobject106
state.session.sprintBoostobject2
state.session.sprintBoost.meternumber
state.session.sprintBoost.rechargingboolean
state.session.teleportZoneCacheobject1
state.session.teleportZoneCache.cacheobject270
state.session.timestepobject2
state.session.timestep.frameDurationnumber
state.session.timestep.lastTimenumber
state.session.triggersarray of object26
state.session.uiobject9
state.session.ui.dialogsarray0
state.session.ui.discoveryPopupsarray0
state.session.ui.hudHiddenboolean
state.session.ui.introScreenobject1
state.session.ui.listenersobject24
state.session.ui.nextListenerIdnumber
state.session.ui.overlaysobject2
state.session.ui.tooltipobject2
state.session.ui.visibleboolean
state.session.viewobject4
state.session.view.maxZoomnumber
state.session.view.minZoomnumber
state.session.view.zoomnumber
state.session.view.zoomDirtyboolean
state.session.visualParticlesarray of object94
state.session.windowsobject13
state.session.windows.blueprintsobject1
state.session.windows.buildingobject3
state.session.windows.conservatoryobject1
state.session.windows.customMapsScreenobject1
state.session.windows.feedbackobject1
state.session.windows.inventoryobject1
state.session.windows.lexiconobject1
state.session.windows.loaderobject1
state.session.windows.menuobject1
state.session.windows.modsScreenobject1
state.session.windows.optionsobject1
state.session.windows.techTreeobject2
state.session.windows.upgradesobject1
state.session.zoomLevelnumber
state.sharedSharedArrayBuffer-ы, в которые пишут потоки симуляции83
путьтипразмер
state.sharedobject33
state.shared.actionStateUint8Array3
state.shared.authorizationobject3
state.shared.authorization.dataUint8Array14745600
state.shared.authorization.heightnumber
state.shared.authorization.widthnumber
state.shared.collectorGoldCountUint8Array921600
state.shared.conveyorBeltsAnimationIndexUint8Array8
state.shared.debugobject1
state.shared.debug.cellPosUint16Array2
state.shared.energyUint32Array1
state.shared.energyBatteryDirtyUint8Array921600
state.shared.energyChangeUint32Array4
state.shared.goldUint32Array1
state.shared.goldChangeUint32Array4
state.shared.hybridSchedulingUint8Array1
state.shared.listenerPosFloat32Array2
state.shared.managerPerformanceFloat32Array23
state.shared.mapDataobject3
state.shared.mapData.dataUint8Array58982400
state.shared.mapData.heightnumber
state.shared.mapData.widthnumber
state.shared.modsobject19
state.shared.mouseobject1
state.shared.mouse.worldPositionUint16Array2
state.shared.mutationSyncInt32Array1
state.shared.naturalAmbienceFloat32Array8
state.shared.playerPosFloat32Array2
state.shared.productionPointsUint32Array1
state.shared.reservoirUint16Array1
state.shared.schedulingModeUint8Array1
state.shared.shadowMapobject3
state.shared.shadowMap.dataUint8Array14745600
state.shared.shadowMap.heightnumber
state.shared.shadowMap.widthnumber
state.shared.simobject20
state.shared.sim.cellIdsUint32Array14745600
state.shared.sim.chunkHeightnumber
state.shared.sim.chunkShouldUpdateUint8Array9216
state.shared.sim.chunkShouldUpdateNextUint8Array9216
state.shared.sim.chunkSizenumber
state.shared.sim.chunkWidthnumber
state.shared.sim.damagedGroundobject2
state.shared.sim.elementCapacitynumber
state.shared.sim.elementDataobject25
state.shared.sim.elementSlabsExhaustedUint32Array1
state.shared.sim.freeDamagedIdCountUint32Array1
state.shared.sim.freeDamagedIdsUint32Array999000
state.shared.sim.heightnumber
state.shared.sim.idStatsUint32Array420
state.shared.sim.liveElementCountUint32Array1
state.shared.sim.nextDamagedIdUint32Array1
state.shared.sim.nextElementSlabUint32Array1
state.shared.sim.overflowPoolUint32Array100001
state.shared.sim.terrainTypeUint8Array1001
state.shared.sim.widthnumber
state.shared.wallDataobject4
state.shared.wallData.dataUint8Array14745600
state.shared.wallData.heightnumber
state.shared.wallData.paletteDataUint8Array1020
state.shared.wallData.widthnumber
state.shared.waterPresenceZonesUint8Array14400
state.shared.waterPresenceZonesHeightnumber
state.shared.waterPresenceZonesWidthnumber
state.shared.workQueueobject14
state.shared.workQueue.chunkCountnumber
state.shared.workQueue.chunkDoneUint8Array9216
state.shared.workQueue.chunkHeightnumber
state.shared.workQueue.chunkWidthnumber
state.shared.workQueue.columnCostsFloat32Array768
state.shared.workQueue.columnDoneUint8Array96
state.shared.workQueue.countersUint32Array4
state.shared.workQueue.effectiveModeUint8Array1
state.shared.workQueue.evenTasksUint32Array9216
state.shared.workQueue.hotColumnsUint8Array96
state.shared.workQueue.hotRemainingInt32Array96
state.shared.workQueue.oddTasksUint32Array9216
state.shared.workQueue.taskCountsUint32Array2
state.shared.workQueue.workerCountnumber
state.shared.workerCompletionFloat32Array16
state.shared.workerDetailEnabledUint8Array1
state.shared.workerDetailPerformanceFloat32Array104
state.shared.workerPerformanceFloat32Array32
state.storeсохраняется с миром: ресурсы, структуры, прогресс143
путьтипразмер
state.storeobject34
state.store.achievementsobject14
state.store.achievements.ANCIENT_TECHNOLOGYboolean
state.store.achievements.AURA_EXTRACTORboolean
state.store.achievements.CONSERVATORY_CURATORboolean
state.store.achievements.CRITTER_CATCHERboolean
state.store.achievements.FINAL_SCHEMATICboolean
state.store.achievements.FIRST_BLOOMboolean
state.store.achievements.FIRST_SPARKboolean
state.store.achievements.FLUX_IT_UPboolean
state.store.achievements.FULL_CIRCLEboolean
state.store.achievements.GOLD_IN_THE_BINboolean
state.store.achievements.PROMOTION_PROTOCOLboolean
state.store.achievements.QUARTERMASTERboolean
state.store.achievements.STRATACORE_SECUREDboolean
state.store.achievements.VOID_TOUCHEDboolean
state.store.conservatoryobject1
state.store.conservatory.ticketsnumber
state.store.createdVersionstring
state.store.creaturesobject5
state.store.creatures.eyesobject2
state.store.creatures.lumlingobject2
state.store.creatures.resinWeaverobject2
state.store.creatures.shineletobject2
state.store.creatures.voidgrazerobject2
state.store.discoveriesobject2
state.store.discoveries.elementsarray of number45
state.store.discoveries.terrainsarray of number21
state.store.dronesarray of object1
state.store.factoryLevelCapnull
state.store.gloomobject1
state.store.gloom.emitterPositionsarray0
state.store.hintsobject6
state.store.hints.angleLockShownboolean
state.store.hints.conservatoryIntroSeenboolean
state.store.hints.freezingIceSoilFireboolean
state.store.hints.hoverIntroToastSeenboolean
state.store.hints.nonDestructibleboolean
state.store.hints.upgradesIntroSeenboolean
state.store.integrityobject2
state.store.integrity.cheatsUsedboolean
state.store.integrity.modsUsedboolean
state.store.lockedTechsobject2
state.store.lockedTechs.aurixiteCrystallizerboolean
state.store.lockedTechs.voidOrbboolean
state.store.machineryEngineobject1
state.store.machineryEngine.runLaunchersboolean
state.store.metaobject8
state.store.meta.autosaveSlotnumber
state.store.meta.elementCapacitynumber
state.store.meta.nextIdobject3
state.store.meta.seedstring
state.store.meta.ticknumber
state.store.meta.timenumber
state.store.meta.worldIdstring
state.store.meta.worldNamestring
state.store.modsobject34
state.store.objectivesobject1
state.store.objectives.activearray0
state.store.optionsobject6
state.store.options.buildModenumber
state.store.options.buildModeIndicesobject5
state.store.options.defaultFilterobject2
state.store.options.sandkitPlacementConfigobject1
state.store.options.shortcutHelperVisibleboolean
state.store.options.techTreePanobject2
state.store.ownerundefined
state.store.pipesarray of object413
state.store.playerobject17
state.store.player.actionobject2
state.store.player.buildingsarray of number61
state.store.player.cooldownsobject3
state.store.player.grapplingHookboolean
state.store.player.heightnumber
state.store.player.hotbarobject3
state.store.player.inventoryarray of object32
state.store.player.isHoveringboolean
state.store.player.onGroundboolean
state.store.player.speedCapOverdriveobject2
state.store.player.techobject71
state.store.player.thresholdobject2
state.store.player.velocityobject2
state.store.player.weaponsMetaobject1
state.store.player.widthnumber
state.store.player.xnumber
state.store.player.ynumber
state.store.productionPointsnumber
state.store.progressionobject2
state.store.progression.dungeonsobject1
state.store.progression.upgradesUnlockedboolean
state.store.projectilesarray0
state.store.pumpsCachearray of object51
state.store.queuearray0
state.store.resourcesobject4
state.store.resources.artifactsobject2
state.store.resources.energynumber
state.store.resources.fluxitenumber
state.store.resources.goldnumber
state.store.sceneobject3
state.store.scene.activenumber
state.store.scene.startnumber
state.store.scene.triggersarray of object3
state.store.stratacoresarray of string1
state.store.structuresarray of object35956
state.store.tutorialobject4
state.store.tutorial.activeboolean
state.store.tutorial.currentStepnumber
state.store.tutorial.dataobject0
state.store.tutorial.transitioningToNextStepboolean
state.store.upgradesobject16
state.store.upgrades.cryoblasterobject1
state.store.upgrades.diggerobject4
state.store.upgrades.drillobject1
state.store.upgrades.flamethrowerobject2
state.store.upgrades.grabberobject3
state.store.upgrades.gunobject5
state.store.upgrades.haulerobject2
state.store.upgrades.implosionGunobject1
state.store.upgrades.jetpackobject2
state.store.upgrades.laserobject3
state.store.upgrades.locatorobject1
state.store.upgrades.rocketLauncherobject4
state.store.upgrades.shovelobject3
state.store.upgrades.sweeperobject3
state.store.upgrades.thrusterobject1
state.store.upgrades.vacuumobject2
state.store.versionstring
state.store.viabilityobject3
state.store.viability.goldSpentnumber
state.store.viability.levelnumber
state.store.viability.peakEnergynumber
state.store.worldobject10
state.store.world.deferredChunkReportsarray0
state.store.world.fixturesarray of object70
state.store.world.groundHorizonarray of number3840
state.store.world.horizonarray of number3840
state.store.world.lightsarray of object561
state.store.world.matrixTraverseDirectionnumber
state.store.world.sensorsarray of object1
state.store.world.sizeobject2
state.store.world.teleportZonesarray of object306
state.store.world.updatedElementIndicesarray0
state.store.worldItemsarray of object1
Не покрыто apiVersion и нестабильно даже внутри одной версии. Это описание одного мира на одной сборке. Читаешь — патч сделает мод неправильным; пишешь — патч сделает неправильным сейв. Каждое обращение в обёртке, каждое чтение с проверкой.

Грабли

Собрано дорогой ценой на восьми модах.

Энтри — это скрипты, а не модули

import или export бросает Unexpected token 'export', и энтри молча не запускается. В интерфейсе об этом не сказано нигде.

Гейтинг по сценам пиши как hide-list

Внедрённый UI сидит в слоте оверлеев global, рисуется поверх главного меню и остаётся смонтированным после выхода из мира. Прячь на тех сценах, которые ты уверенно опознал как меню: неверная догадка в show-list гасит твой UI вообще везде.

Никогда не оборачивай регистрацию в тихий хелпер

Молчаливый try/catch вокруг energy.registerType способен скрыть полный отказ. Регистрацию нельзя повторить, поэтому падать она должна громко.

Проверяй до запуска игры

workshop-mods.js и local-mod-publisher.js достаются из app.asar и вызываются напрямую: loadCandidate для манифеста и энтри, validatePreview для картинки и та же обёртка new Function для синтаксиса. Ловит всё, кроме поведения в рантайме, и не требует перезапуска.

Колбэки эффектов зависят от точки входа

energy.addAtCell читает onPathCharged, но никогда не вызывает onSourceAdded — тот срабатывает только из batch-API, которого модам не дают. Зато возвращает объём, который сеть реально приняла, и вот на него эффекты и надо вешать.

Мод виден в настройках, только если у него есть настройки

Нет непустой configSchema — нет строки на экране модов. А выключить мод без отписки игра штатно не умеет, так что поле enabled стоит сделать общей договорённостью.