Skip to content

[Memhack] Skill Core Sync

DasKeifer edited this page Sep 29, 2026 · 1 revision

Memhack Skill Core Sync

memhack.skillCoreSync keeps CORE_TYPE_SKILL_BONUS cores correct across save load, mid-mission continue, mission start, and mission end.

The base game guards against multiple bonus cores on load, and skills are reapplied on load. Skill Core Sync handles that so mech hp/move cores, pilot innate power cores, and weapon power/upgrade cores stay consistent.

Most modders should not call this module directly. Setting cores through the normal memhack APIs (for example Pawn:SetHpCore / SetMoveCore, pilot power lists, or weapon core writes) is enough. Skill Core Sync runs automatically on the events below and restores / rebuilds as needed.

Overview

All sync work is gated: a pawn is only handled when needsSkillCoreSync finds any CORE_TYPE_SKILL_BONUS (2) across that pawn's hp core, move core, pilot power list, and weapon power/upgrade lists.

Subscribed automatically in skillCoreSync.init():

Event Behavior
modApi.events.onPostLoadGame Not in mission: apply cores from save. In mission (continue): ensure double suffixed _G weapon copies so vanilla load does not error, then delayed weapon rebuild from snapshot
modApi.events.onMissionStart Snapshot live cores for pawns that need sync into GAME.memhack.mission_core_snapshot
modApi.events.onMissionEnd Strip suffixed weapons to base ids, reapply snapshot cores, clear snapshot

Mission Snapshot

Stored at GAME.memhack.mission_core_snapshot.

On mission start, Skill Core Sync always writes a table (possibly empty) so a mid mission continue can detect an in mission save via isMissionSaveLoaded(). On mission end the snapshot is cleared.

Per pawn entry shape (only pawns that need sync are stored):

snap[pawnId] = {
    hpCore = int,       -- memhack.CORE_TYPE_*
    moveCore = int,     -- memhack.CORE_TYPE_*
    pilotPower = { ... },  -- CORE_TYPE_* list, or nil
    weapons = {
        [1] = { power = {...}, upgrade1 = {...}, upgrade2 = {...} },
        [2] = { power = {...}, upgrade1 = {...}, upgrade2 = {...} },
    },
}

Weapon list keys match LIST_SPECS: power, upgrade1, upgrade2 (from memedit getPowerList / getUpgradeListA / getUpgradeListB).

Table of Contents

needsSkillCoreSync

  • boolean memhack.skillCoreSync.needsSkillCoreSync(pawnSnap, tag, pawnId)
Argument name Type Description
pawnSnap table Per-pawn snapshot (hpCore, moveCore, pilotPower, weapons)
tag string or nil Optional debug label
pawnId int or nil Optional pawn id for logging

Returns true when the pawn has any memhack.CORE_TYPE_SKILL_BONUS cores across mech hp/move, pilot power, and weapon lists. Used to skip sync for pawns that have no skill-bonus cores.

getMissionSnapshot

  • table or nil memhack.skillCoreSync.getMissionSnapshot()

Returns GAME.memhack.mission_core_snapshot (initializes GAME.memhack if needed).

setMissionSnapshot

  • void memhack.skillCoreSync.setMissionSnapshot(snap)
Argument name Type Description
snap table Snapshot table keyed by pawn id 0-2

Writes GAME.memhack.mission_core_snapshot.

clearMissionSnapshot

  • void memhack.skillCoreSync.clearMissionSnapshot()

Sets GAME.memhack.mission_core_snapshot to nil.

isMissionSaveLoaded

  • boolean memhack.skillCoreSync.isMissionSaveLoaded()

Returns true when a mission snapshot exists. Used on post load to distinguish hangar/island load from mid mission continue.

Note: Board is not ready until the frame after onPostLoadGame when continuing (see mod_loader), so in mission rebuild is deferred with modApi:runLater.

replaceAllWeapons

  • table or nil memhack.skillCoreSync.replaceAllWeapons(pawn, entries, forceEnable)
Argument name Type Description
pawn BoardPawn Pawn to rebuild weapons on
entries table Ordered slot entries; see below
forceEnable boolean Passed to AddWeapon

Removes weapons from the first entry marked replace = true onward, then readds from that index so order is preserved. No op if no entry has replace.

Each entry:

Field Description
typeId Weapon type id for AddWeapon
cores Optional { power, upgrade1, upgrade2 } lists applied after add
replace If true, this slot (and all later slots) are removed and re-added

forceEnable and weapon cost

forceEnable is passed straight to pawn:AddWeapon(typeId, forceEnable):

  • In mission rebuild (rebuildPawnWeaponsInMission) uses forceEnable = true so PowerCost is zeroed for combat (avoids wrong class / extra cost issues while fighting).
  • Mission end strip (stripSuffixedWeaponsForPawn) uses forceEnable = false, then mission end reapplies cores from the snapshot afterward.

After add, if entry.cores is set, cores are written via memedit/memhack without growing weapon int vectors past their live size.

Lifecycle helpers

These are what the event handlers call. Useful if you need to understand or debug sync. Routine mods usually do not invoke them.

Function Role
onPostLoadGame In mission: double suffix _G copies + delayed rebuild. Not in mission: syncAllFromSave
onMissionStart snapshotAllPawnCores -> setMissionSnapshot
onMissionEnd stripAllSuffixedWeapons -> applyAllFromSnapshot -> clearMissionSnapshot
syncPawnFromSave / syncAllFromSave Apply mech/pilot/weapon cores from save data when gated
snapshotPawnCores / snapshotAllPawnCores Capture live cores for pawns that need sync
applyPawnSnapshot / applyAllFromSnapshot Restore snapshot cores on mission end
rebuildPawnWeaponsInMission / rebuildAllPawnWeaponsInMission Replace weapons when save ids are suffixed or live cores differ from snapshot

Clone this wiki locally