Skip to content

Releases: SkyeShade/HD2Runtime

HD2Runtime v0.40.1 — 0.31 Application Path by Default, No game.dll Executable Writes, Unlimited Custom Stratagems

Choose a tag to compare

@SkyeShade SkyeShade released this 19 Oct 11:31

HD2Runtime 0.40.1 — the 0.31 application path by default, no game.dll executable writes, any number of custom stratagems

Released 2026-10-19. 0.40.1 pairs with the HD2R Editor 1.0.1.

0.40.1 has three parts:

  • the 0.40.0 application optimizations are off by default, with a setting to turn them on;
  • nothing is written into game.dll's executable pages any more (the armor class tables and damage curve are read only);
  • the cap of 16 custom stratagems is gone. The CUSTOM STRATAGEMS panel shows at most 20 cards at once (five rows of
    four) and scrolls the rest with a scrollbar.

Each item says whether it was seen working in game ("live") or is covered only by the offline tests and the packaged
validation.

Faster application (0.40.0) is off by default (live, user report 2026-10-19)

Players reported the game failing to start, or closing at start, with 0.40.0, where 0.31.3 started. The cause is not
known. 0.40.1 goes back to the 0.31 application path by default, and keeps the 0.40.0 optimizations behind a setting:
F10 > Settings > Interface > Faster application (0.40.0), off by default and saved.

On, it turns on:

  • discovery walks shared per address space and profile, and the decoded entity map and component index caches;
  • the 2 MiB read slice (off: 1 MiB);
  • sleeping ensures, where the scheduler skips an ensure's tick until its next check is due;
  • the HD2R Editor's paused checks while its window is hidden;
  • the per-update write-gate budget;
  • the enemy capture's resource filter.

Off, back-to-back operations reuse one memory walk for 15 s, every watch ticks every frame, an Editor-owned ensure keeps verifying while the Editor is closed, and a burst of
operations is admitted in one update, as in 0.31. Both modes keep every ownership check, fingerprint, snapshot and
rollback. See runtime performance.

  • The HD2R Editor's Settings switch "Optimized application" set the same thing in 0.40.0 and turned it on at every
    start. Editor 1.0.1 saves the choice through the Runtime instead
    (hd2.diagnostics.save_application_optimizations) and no longer turns it on at start. Editor 1.0.0 still turns it
    on for its session.
    Update the Editor along with the Runtime.
  • hd2.diagnostics.application_optimizations(enabled) still changes it for the process only.
  • Measured offline (the same 150 editor-style weapon edits on the retained snapshot, in the current packaged
    harness): 0.31.3 settles in 47.3 s of simulated frames with 4 memory walks; 0.40.1 with the setting off does the
    same, frame for frame, with 0.4 s more CPU once at load and about 2 ms more per operation. The 0.40.0 switch's
    "off" had disabled every shared walk (150 walks, 711 s), which would have made applying slower than 0.31.3.
  • Live (user report, 2026-10-19): with the setting off, edits apply at 0.31.3's speed again. Whether it fixes the
    0.40.0 start-up crashes reported by players is not known yet.
  • Tests: off by default, a sleeping watch ticks every frame, a burst is not budgeted, a paused ensure keeps verifying;
    the F10 row saves the choice and sets the mode. The optimization tests turn it on explicitly.

Game.dll executable data is read only (offline only)

The armor class tables (armor value, speed, stamina per weight) and the armor damage curve sit in game.dll pages that
are executable at run time. Since 0.30.0 they were written as "reviewed executable data". A player reported GameGuard
closing the game right after a mod wrote them. 0.40.1 writes nothing into game.dll's executable pages:

  • armor_class.* and armor_damage_curve.* are editable = false with a readOnlyReason. Every change is refused
    before anything is read, with GAME_DLL_EXECUTABLE_DATA. They can still be read and described;
  • the same rule covers the melee and enemy director fields that sit in such a page: their write is refused with the
    same code;
  • a mod or preset that changes one of them logs the refusal; its other operations go ahead;
  • kit piece weights, armor perks and the local player's armor bonus and stamina factor are ordinary data and stay
    writable;
  • the HD2R Editor 1.0.1 shows the class and curve rows read only.
  • Tests: tests/test_executable_data_extent.py, tests/test_armor_stats.py; scripts/validate_armor_stats_snapshot.py
    on all seven retained snapshots (every class and curve change refused, the tables unchanged); the packaged
    ArmorStatProbe scenario (its Alt+F9 curve ensure is rejected, nothing written).

Any number of custom stratagems (live, user report 2026-10-19)

  • hd2.custom_stratagem.register no longer refuses the 17th custom stratagem. The caps were in
    runtime/custom_stratagems.lua (MAX, LIMITS.definitions) and runtime/virtual_stratagems.lua (MAX).
  • The builder schema has no limits.definitions, and the project schema has no maxItems on stratagems.
    sdk/tools/custom_stratagem_project.py accepts any non-empty list. With an older schema that still has the limit,
    it still applies that limit.
  • The Runtime text budget is the bound now. Each custom stratagem takes 3 Runtime texts (name, cased name,
    description); an expendable takes 4.
    • The budget was 256 texts in a 64 KiB table, about 64 to 85 custom stratagems across all mods. It is now 4096 texts
      in a 1 MiB table.
    • The table format is unchanged (u32 offsets; the game's own tables hold up to 7300 ids each). The game finds an id
      by binary search.
    • The table is built in Runtime-owned memory, which is never freed. A session builds at most 16 tables, as before.
  • A text that does not fit is refused when it is defined. Before, a table over the byte limit failed only when it
    was written, as TEXT_BUDGET, and then no Runtime text showed at all. Now the registration that would cross the
    limit is refused at load time, with the error custom text budget reached.
  • Compatibility. A mod that registers more than 16 custom stratagems needs Runtime 0.40.1. On 0.40.0 its 17th
    registration fails at load.
  • Not changed:
    • The multiplayer protocol carries picked ids only (4 slots a player).
    • The registry hash covers every definition, as before.
  • Not measured with many definitions:
    • Aboard the ship, the per-second availability pass allocates a carrier for every registered definition.
    • Every definition's assets and deliveries are excluded from every carrier pool. Many definitions can therefore
      leave fewer free carriers, and more of them show as unavailable.
  • Tests:
    • forty custom stratagems register in order, each with its own virtual stratagem and panel entry;
    • the byte bound refuses a text at definition, and the table built from the accepted texts fits;
    • the 4096-text bound;
    • the schemas have no definitions limit.

The CUSTOM STRATAGEMS panel scrolls, at most 20 cards in view (live, user report 2026-10-19)

  • The native-style panel (the one drawn right of the native details panel) shows at most five rows of four, 20
    cards (six rows before).
    • More rows scroll with the mouse wheel over the panel, a click on the scrollbar track (a page), or the F6 focus,
      which scrolls to its card.
    • The native-style scrollbar is drawn right of the grid while there are more rows than fit.
    • The panel no longer refuses more than 240 entries.
  • The fallback panels scroll too:
    • the compact panel, used when the native-style panel does not fit (at most two rows of three);
    • the legacy panel (one row).
    • Before, they never scrolled, and entries past the last visible row could not be reached. They also refused more
      than 60 entries.
    • They now take the same wheel, track and focus input, and draw a scrollbar in the grid's right padding.
  • Tests:
    • thirty entries: five of eight rows in view, card 20 visible and card 21 not; the wheel, a page down on the track
      and the focus scroll it;
    • 100 entries in the compact panel: two rows in view, its scrollbar inside the panel, a page down;
    • 200 entries in the legacy panel.
  • Live (user report, 2026-10-19): the user tested the expansion with proof/CustomStratagemScrollTest (24 custom
    stratagems) and reported that everything worked. Which input scrolled (wheel, track or F6) and whether it was solo
    or multiplayer was not reported.

HD2Runtime v0.40.0 — Enemies and Spawning, Mission Timers and Freeze, Reload/Heat/Melee, Throwables, Armor Perks, MODS Keybinds

Choose a tag to compare

@SkyeShade SkyeShade released this 14 Oct 19:42

HD2Runtime 0.40.0: enemies and spawning, mission timers, reload/heat/melee, throwables, armor perks, MODS keybinds

0.40.0 is the largest release since 0.30.0. It follows 0.31.3 and absorbs the unreleased 0.32.0 line.

Each item says whether it was seen working in game ("live"). Otherwise it is covered by the offline tests and the
snapshot validators only. Fields that are not live-tested keep allow_unverified_effect. Multiplayer behaviour is
claimed only where it says so.

Enemies, spawning and destruction (offline)

  • Enemy and structure authoring covers 1,178 entity targets, including 429 structures:

    • creation scale, spawner queues and timing, HiveMind multipliers;
    • transport footprints, shields and jammers;
    • recovered damage-zone names;
    • typed attack chains, with existing names and attack ids preserved.

    See enemy controls.

  • Mission difficulty and spawning (hd2.enemies) is edited aboard the ship and affects the next mission:

    • difficulty budgets, all five spawn rosters, composition weights and counts, and breach schedules;
    • zero spawn weight is normal roster suppression, not a global blacklist;
    • spawn compositions are capped at 32 enemies in total after two crash dumps showed the native squad queue
      overflowing. Recipes report the capping, and old presets get the same aggregate check.
  • Demolition templates and destruction models: shared demolition forces are editable, and all 1,641 destruction
    models can be inspected.

  • Pick your bots/bugs/squids: spawn ownership is cooperative. Its spawn picks and the Runtime's pending values
    never fight.

Missions

  • Mission timer durations (hd2.mission) cover 162 mission definitions on 19 shared timer sources. The new
    duration is applied aboard the ship and used when the mission launches.
    • Live: the edited value reaches the mission.
    • The game's limit is 2500 s (41:40), live-proven. The host clamps its countdown every frame to the replicated
      timer field's range, so a longer value starts at 41:40 in the mission. The writer therefore refuses values above
      2500 s. The ship's mission selector shows the edited definition.
  • Freezing the mission timer (hd2.freeze_mission_timer, experimental). This is the game's own timer pause, the
    one Evacuate High-Value Assets missions spawn with.
    • The countdown stops: no ceiling, and it never reaches zero. Everything the game derives from the countdown waits
      with it. The next mission starts unpaused.
    • Host only. The host's freeze is published to the lobby (Runtime member-data key hd2mt), and the other
      Runtimes set their own countdown's pause the same way.
    • Live: solo freeze and resume. Multiplayer follow is offline only.
    • HVA timers and an expired timer are refused.
  • hd2.diagnostics.mission_timer() is one explicit read. It returns the active instance's timer source, its
    definition, any private record, the countdown, and the paused and expired flags.

Weapons and equipment (offline)

  • Reload controls on all 73 reloadable primary and secondary firearms. The Arbitrator, One-Two and Stoker
    underbarrels have their own reload duration (0 = the native ability timing).

  • Heat:

    • the Double-Edge Sickle: heat, wind-up, level projectile and self-damage, 89 controls;
    • the Variable's RPM slots and the Warrant's modes and burst count;
    • G/SH-39 shield recharge;
    • PLAS-39 charged burst, charge timings and its Single/Unsafe selector.

    See reload and heat controls.

  • Melee (hd2.melee): 112 weapon and gun-bash entries, covering hit-volume size and offsets, repeat-hit
    intervals, shared damage and stamina costs. See knife and melee authoring.

  • Throwables:

    • eleven launch/spin controls on all 23 throwables, including the K-2 knife's launch curve and speed override;
    • four status types and strengths on main explosions, knife hits, shrapnel and Pineapple bomblets;
    • arming delay for 22 explosives.

    See throwable statuses. Knife explosions remain unavailable.

  • Explosion-created arcs: the GL-52 De-Escalator and G-31 Arc expose range, velocity, spread, chain and split
    limits, arc damage and stun. The G-31 also gets four arc-hit status slots. See explosion arcs.

  • Projectile swaps:

    • the GL-28's backpack-fed projectile swap, shotgun donors included;
    • the G-109 Urchin's pulse payload override (small or charged Epoch plasma);
    • the W.A.S.P.'s hit projectile for both missile modes. The missile entity keeps its own flight.
  • Supply Pack: box capacity, starting boxes and refill, plus the shared stim refill amount.

  • Armor perks: the two equipped passives move onto the Helldiver. Armor perks is its own catalogue, with 75
    numeric controls across 31 perks.

  • Hoverpack: the landing-thrust labels are corrected; offsets and ids are unchanged.

Input: the game's own keybind page (live)

  • Native keybinds: hd2.input.bind(id, {key, on_press, native = {label, category}}) also registers the binding with
    Mod Bindings Menu (CowboyBingus), on the game's Controls page, MODS tab. Any key, mouse button or controller
    input bound there presses it.
  • One key, not two: while a keyboard or mouse input is set there, the binding's own key is ignored. Emptying it
    brings the key back immediately.
    • The Runtime reads the game's live binding table, read only and pinned, to know this.
    • A controller-only binding leaves the key working.
  • HD2Runtime's settings window (F10) and the HD2R Editor declare it. Labels follow the language. See
    events.

Custom stratagems and multiplayer

  • Carrier slots never move while the lobby is waiting for a member's value, for example after a mission. A move
    on that partial allocation was undone too late and left a slot desynced and locked. In one report, the host's
    Pelican Gatling was shown as a locked Orbital Napalm Barrage. Offline; reproduced and fixed by test.
  • Pelican variants: the Autocannon Pelican keeps its native burst AI. A transaction that returns ALREADY_DESIRED
    is accepted as success.

Runtime and performance

  • F10 Performance: Global and Runtime views with exclusive core/mod accounting, an on-demand tracked-memory graph,
    editor UI/work attribution, and a watchdog that names the external mod behind a slow frame.
  • Faster application: large presets apply faster. Discovery walks are shared between the weapon and enemy writers
    (a reported preset of 554 operations had taken 77 s). Settled ensures sleep between their periodic checks.
  • Mission cleanup fix: mission-scoped timers and subscriptions are now cleared when a mission ends even if no mod
    listens to mission_ended. Before, they stayed active.
  • SDK fix: the authoring stub declared hd2.passives.perk on a table it never created.
  • Translations: new texts in all 13 languages. The Korean F10 peak label avoids a glyph the game's font lacks.

Known

  • One tester reported a crash when opening F10. No cause was found and it has not recurred. The F10 panel keeps its
    sparse diagnostic breadcrumbs.
  • GalacticMenuHotkey (not HD2Runtime): its Galactic Map shortcut sits on Mod Bindings Menu's fixed slot 1, which
    inherits left click and A/Cross. On the war table every click re-opens the map. Rebind or disable that shortcut.
  • Not live-tested: everything not marked live above. That includes the multiplayer timer follow, the
    waiting-lobby carrier fix and most new fields.

HD2Runtime v0.31.3 — Custom Stratagems with Warbond Carriers, LAS-22 Shear, Exosuit and Bastion Ammunition, FX-12 Relay Recharge

Choose a tag to compare

@SkyeShade SkyeShade released this 12 Oct 03:55

HD2Runtime 0.31.3 — custom stratagems with warbond carriers, LAS-22 Shear, Exosuit and Bastion ammunition, FX-12 relay recharge

0.31.3 is a hotfix release built from player reports: picking a custom stratagem no longer fails on every click when
the lobby's carrier is a stratagem this account does not own (the warbond expendables), the LAS-22 Shear is in the
weapon stats, the EXO-55 Breakthrough's cannon has its ammunition fields, the Exosuit and TD-220 Bastion cannon
ammunition is documented (31 spare magazines is the network maximum; more shells through the magazine capacity), and the
FX-12 Shield Generator Relay's recharge rate and delays are editable. The docs now say that weapon.suppressed has no
audible effect in this game build.

Each item says whether it was seen working in game ("live") or is covered by the offline tests and the snapshot
validators only. Nothing in this release is live-tested, and nothing in it was tested in multiplayer. The new fields
need allow_unverified_effect.

Custom stratagems: never refused for a carrier the account does not own (offline only)

  • A player report (two logs, custom multiplayer): picking the EAT-23 Expendable EMS or the EAT-40 Expendable Gas in the
    custom panel was refused on every click: custom stratagem panel click: selecting eat23_ems (its carrier EAT-411 Leveller) into slot 0 -> stratagem selector REFUSED (nothing written): TOKEN_NOT_OWNED: EAT-411 Leveller is not owned, and the same with the EAT-700 Expendable Napalm, although the availability line had said
    EAT-700 Expendable Napalm cannot carry it: not owned earlier (solo) and then AVAILABLE ... (condensed: EAT-700 Expendable Napalm is also its beacon carrier and its pod) in the lobby.
  • Cause: with several players the lobby's carrier for a custom stratagem is ranked without ownership, so every machine
    computes the same one; a carrier this account does not own is refused locally (local_refused). That refusal was
    applied only to custom stratagems already in the loadout. The pick (custom_stratagems.probe_carrier) took the
    lobby's carrier from the ship preview or the availability view (the expendable's condensed carrier,
    avail.carrier, or the group view) without looking at ownership, and the availability step ignored the condensed
    verdict's "not owned here" flag. The selector's guard then refused the write, every click. In the first log the
    host owned the EAT-700 (its own EAT-40 held it), so the lobby gave the EAT-23 the EAT-411, which it does not own; in
    the second the player owned neither.
  • The guard stays: the saved loadout, the game's server and the other players read the slot, so a carrier or token the
    account does not own is never written (TOKEN_NOT_OWNED still refuses a direct write).
  • Now the pick writes only a carrier this account owns (custom_stratagems.pick_plan):
    • solo: the allocation ranks only owned carriers. An expendable whose carrier weapon's own stratagem is not owned
      takes a separate blue support carrier the account owns (the same custom stratagem: its carrier weapon is still the
      clone). A carrier from an older view that the account does not own is never written. With no owned carrier at
      all, the pick is refused with the reason and nothing is written;
    • custom multiplayer: when this account does not own the lobby's carrier, the pick takes the first carrier of the
      definition's own pool (its group or policy, in the allocator's rank) that this account owns and no other custom
      stratagem holds. This is checked by allocating the lobby again with this player's slot holding it. Every machine
      reads that slot as the id's pin (the r41 pins), so the lobby's carrier for it becomes that carrier everywhere and
      the carrier hashes agree. For an expendable, a slot holding a separate support carrier makes it a fallback one on
      every machine (expendable_pass; solo nothing changes). With no owned carrier, or when another player's slot
      already holds the id with a carrier this account does not own, it is UNAVAILABLE with the reason (the token
      would be refused at mission start the same way: never remapped);
    • the availability line says what the pick will write;
    • the panel says a refused pick once while it stays open, and the tile keeps its warning and reason. It never tries
      the write again on every click.
  • Not changed: the lobby's ranking (still without ownership), the carrier groups' members, the registry hash and the
    peer protocol.
  • Tests: tests/test_custom_stratagem_unowned_carrier.py covers both reports (the condensed EAT-700 not owned solo and
    in a lobby; the EAT-411 the lobby gives after another player's EAT-40; a group carrier not owned in a lobby; the
    refusal said once; the selector's guard on a direct write).
  • Needs a live test: two players with custom multiplayer, one account without the EAT-700 and EAT-411 (and with a
    blue support weapon such as the M-105 Stalwart unlocked). Pick the EAT-40 on that account: its slot should hold the
    support weapon (CARRIER-IN-SLOT PROBE ... its pick writes M-105 Stalwart), the other machine's CUSTOM MP CARRIERS should show the same carrier for it, and in the mission the beacon should deliver the EAT-40 clones from
    the EAT-700's pod. The fallback beacon carrier for an expendable has not been live-tested with several players.

LAS-22 Shear in the weapon stats (offline only)

  • Players asked for the LAS-22 Shear's stats: hd2.weapon('LAS-22 Shear') did not exist, and the editor did not list it.
  • Cause: the player weapon catalogue's 80 weapons come from a published-stat list that has no Shear. Runtime had
    captured its entity (laser_rifle_charge) only as the LAS-5 Scythe's second candidate, and 0.30.2 dropped it there
    as "another weapon" when it proved the Scythe's own entity.
  • Now the game's own armory names it. Armory item 7DE53646 (primary) holds that entity, and its name record composes
    "LAS-22 Shear". The same path gives each of the 80 catalogued weapons its catalogued entity. It is catalogued as a
    primary (Energy-Based) on its own records, with the Scythe's 64 fields (38 writable):
    • handling, spread, recoil and reticle;
    • heat capacity and heat per shot, behind allow_unverified_effect: no published values cross-check them;
    • its beam fire mode, rate and pulse;
    • the beam and damage row (shared with the Scythe);
    • armory traits and penetration label;
    • a beam swap through its own default muzzle (weapon:beam_source(), Laser. Charge Standard).
  • Its default heatsink overwrites heat per second, cooling, the heatsink counts and the firing-charge members when the
    weapon is built. Those stay read-only, and the reason gives the value the game uses: 25 heat/s, not the base 30, and a
    charge loss of 100/s, not the base 500. For the same reason the Scythe's overwritten heatsink count now says "to 4;
    the base value here is 6".
  • hd2.attack_output('LAS-22 Shear') is a beam donor (the Scythe's beam row, through the Shear's own package). Kill
    events name the Shear.
  • Not covered: the burst the game describes when the Shear fully overheats (no proven member). Nothing about the Shear
    is live-tested. Every writable field resolves on the reference snapshot with the catalogued value
    (tests/test_shear.py).
  • Editor: no change needed. It lists the Runtime's player weapons by slot, so the Shear appears under Primary with this
    Runtime.

Compatibility (the Scythe's beam and damage row)

  • The Scythe and the Shear fire the same beam and damage rows, so the Scythe's beam.length, beam.radius and
    damage.* fields (19) are now shared and need allow_shared. The game always shared them; Runtime did not know.
  • Mods that declare SDK 0.31.2 or older keep writing them without it. Each such write is a logged legacy operation
    (docs/legacy-sdk-compatibility.md, the allow_shared entries of schemas/legacy_acknowledgements.json). Mods built
    with the 0.31.3 SDK need allow_shared=true, as the SDK metadata says.

TD-220 Bastion cannon ammunition: the 31-magazine maximum confirmed (research, docs only)

  • A user asked whether the Bastion's main cannon can carry more than the 31 spare magazines Runtime allows since 0.31.2,
    suspecting a 10-bit network field.
  • Re-derived from the game code (research/docs/ammo-network-fields-F5FEE03DCFDB.md): every weapon's live ammunition
    uses the same fields, by its ammunition component, whatever carries it (player, support, vehicle mount, Exosuit arm,
    sentry). Spare magazines are 5 bits (0 to 31), rounds in the magazine 11 bits (0 to 2047), and a rounds feed's spare
    rounds 9 bits (0 to 511). The cannon's spare shells are spare magazines of one shell each, so 31 spare (32 shells) is
    the most it can carry; vanilla is 30 (31 shells). The 10-bit field (0 to 1023) is a deposit's: backpacks and a
    vehicle's own deposit, which the Bastion cannon does not reload from.
  • No maximum changed. docs/vehicle-weapons.md ("Ammunition limits") now explains this and how to get more shells:
    raise weapon.capacity (shells = capacity x (spare magazines + 1); capacity 2 gives up to 64).
  • Not live-tested.

Exosuit ammunition: the EXO-55 Breakthrough cannon's rounds (offline only)

  • A user reported that the EXO-55 Breakthrough's right gun has no magazine or ammo counts, nor do the EXO-49
    Emancipator and EXO-45 Patriot ("I bet all of them have their ammo counts missing").
  • Checked every Exosuit weapon arm. The magazine arms already had theirs since 0.30, on each arm's own record:
    weapon.capacity and the three magazine.* counts on both EXO-45 Patriot arms (rocket pod 14, minigun 1350),
    both EXO-49 Emancipator autocannons (100 each) and both EXO-51 Lumberer arms (flamethrower 500, cannon 25). Their
    magazine counts are 0 / 6 / 0 and no reload is known to use them, so weapon.capacity is the arm's whole supply (in
    the editor it sits in the Weapon section as "...
Read more

HD2Runtime v0.31.2 — No More Stutter, Four Statuses per Row, Ammunition Limits, the Game's Own Names and Support Weapon Payloads

Choose a tag to compare

@SkyeShade SkyeShade released this 11 Oct 23:49

HD2Runtime 0.31.2 — no more stutter, four statuses per row, ammunition limits, the game's own names and support weapon payloads

0.31.2 is a hotfix release built from player reports: custom stratagems no longer stutter every 5 seconds, beam
conversion values can be changed again and reverted, a damage row takes up to four statuses (the GL-15 Evictor's gas
and gas confusion), ammunition maxima follow the game's network limits (the TD-220 Bastion coax), the RL-77's bomblet
explosion is found under both rockets, the game's own names and custom stratagem texts work in Chinese and every other
game language, Acid Storm can be attached to weapons (asked for the TX-41 Sterilizer), the Sterilizer's hellpod is
editable, the LAS-99 Quasar's lockout after an overheat is editable, and support weapons take impact and expiry
payloads.

Each item says whether it was seen working in game ("live") or is covered by the offline tests and the snapshot
validators only. Two fixes are live, reported working in game on a development build (without a log): the custom
stratagem stutter and the beam conversion re-edit. Everything else is offline only, and its new fields need
allow_unverified_effect. Nothing in this release was tested in multiplayer.

Custom stratagems: no stutter every 5 seconds (live)

  • A player reported "a pulse, a quick stutter" with custom stratagem mods. The F10 Performance tab showed the custom
    stratagems at 0.65 ms on average with a peak of 53.8 ms: one long update about every 5 seconds.
  • Cause: aboard the ship, the Runtime checks the custom stratagems' carriers again every 5 seconds: the ship allocation
    and the custom panel's availability view (M.REVALIDATE_EVERY). Each check ran one carrier discovery per registered
    custom stratagem. Each discovery read every catalogued stratagem again: its row, its ownership, its look and its code,
    about 1,700 reads. Live, each read is one ReadProcessMemory. With many custom stratagems, one update made tens of
    thousands of reads.
  • Now (the same reads, made fewer times):
    • an allocation runs one discovery for all the definitions that ask the same one (the same token, exclusions and Eagle
      mode), not one per definition (runtime/carrier_allocator.lua);
    • what a discovery reads of each catalogued stratagem is read once per update and shared by every discovery in that
      update. It is read again when any Runtime write happens in that update (runtime/stratagem_slot_conversion.lua);
    • a stratagem type scan that finds nothing is read once per update, not once per id (runtime/stratagem_loadout.lua).
  • The results are unchanged: the same carriers, verdicts, availability and ordering, and the same multiplayer rules. No
    guard changed.
  • Offline, aboard the ship over a simulated minute (tests/test_custom_stratagem_performance.py), the worst update
    went:
    • with the three example custom stratagems: from 93,275 reads (about 120 ms) to 590 reads (about 3 ms);
    • with fifteen: from 465,467 reads (about 570 ms) to 590 reads.
      It no longer grows with the number of custom stratagems. The test fails if it does again.
  • Live: tested in game on a development build of this fix and reported working (no log or numbers sent). A mission
    and several players were not reported separately (schemas/live_evidence.json
    custom_stratagem_revalidation_stutter_0_31_2).

Beam conversion: a field changes again, and back (live)

  • A player report (HD2R Editor, APW-1): beam.fire_rate 300 -> 60 applied, then every later change was refused until
    a restart, the reset too: CONFLICT: the APW-1 Anti-Materiel Rifle's beam.fire_rate is 60, neither the expected 300 nor the requested 300 (another operation set it).
  • Cause: an option-bound ensure (the editor holds each field with one, its value bound to a script value) may move the
    value it applied itself on: every typed domain accepts those bytes (change.owned, core/ownership.lua). The beam
    conversion domain checked only expect and value, so the ensure's own 60 read as another operation's. Its restore
    (the ensure's enabled option off) failed the same way.
  • The beam conversion settings and per-weapon rows now accept the ensure's own previous value too
    (domains/beam_conversion_writes.lua). Another mod's operation, and a writer outside HD2Runtime, are still
    refused with CONFLICT.
  • A request naming beam.fire_rate alone no longer refits a pulse that was set explicitly: only the Trident's 0.15 s
    or the pulse fitted to the current rate is refitted. Before, the rate's and the pulse's ensures overwrote each other
    at every steady-state check.
  • Live: tested in game on a development build with the HD2R Editor on the APW-1: repeated edits and the revert were
    reported working (no log sent). Only this re-edit and revert behaviour is live. The gameplay effect of each beam value,
    other weapons, another mod's refusal and multiplayer are not: every beam conversion write still needs
    allow_component_swap and allow_unverified_effect (schemas/live_evidence.json
    beam_conversion_same_mod_reedit_0_31_2).
  • See docs/beam-conversion.md ("Rules", "The pulse length limits the rate").

Status slots 1 to 4 on every damage row (offline only)

  • Every DamageInfo row now offers all of its empty status slots, up to slot 4, each with its strength
    (damage.status_<k>_type / _strength, explosion.damage.status_<k>_*). Before, only the first empty slot was
    offered, so a row with no status could gain only one: the GL-15 Evictor's blast could not take both gas and
    gas_confusion. This applies to player, support and mounted weapons and to throwable explosions.
  • The slots stay packed from slot 1, now judged on the row as the whole write leaves it (core/status_slots.lua):
    slot k takes a status only when slots 1 to k-1 hold one, live (vanilla, or set by an earlier operation) or set by
    the same transaction or another operation of the same plan phase, in any order. Slot 2 alone on an empty row is
    refused (STATUS_SLOT_GAP), and so is clearing a slot while a later one holds a status. Each slot's own bytes are
    still checked against their exact reviewed value.
  • The new slots after a row's first empty one always need allow_unverified_effect, also on the live-proven
    projectile direct-hit rows: a second attached status on one row has not been live-tested.
  • See docs/status-effects.md ("API", "Guards").

Ammunition maxima: 2047 rounds, 31 spare magazines (offline only)

  • A player reported a TD-220 Bastion coax capacity of 2500 that showed about 2100 rounds for its owner and 500 for a
    friend. The live round count is an 11-bit network field (0 to 2047) and the spare-magazine count a 5-bit one (0 to
    31). The game clamps larger values at the next shot, so teammates see a different count.
  • weapon.capacity / magazine.capacity / attachment.magazine_capacity now take at most 2047. The magazine counts
    (starting_magazines, magazines_from_supply, spare_magazines, and the attachment ones) take at most 31. This
    covers player, support and mounted weapons and magazine attachments. Smaller existing maxima are kept. The refusal
    names the network field.
  • Older mods keep working. A mod that declares an SDK older than 0.31.2 had no maximum: its larger value is applied
    as the maximum and logged as a legacy operation. It is not refused. A mod that declares 0.31.2, or whose SDK cannot
    be read, is refused. See docs/legacy-sdk-compatibility.md ("Maxima added in 0.31.2").
  • The TD-220 Bastion coax and the Exosuit arms own no reload component. Their spare-magazine fields are flagged
    reloadComponent.present = false as expected to have no effect. They are not blocked, and this is not proven from
    game code.
  • See docs/vehicle-weapons.md ("Ammunition limits").

RL-77 bomblet explosion (offline only)

  • A player looked for the RL-77 Airburst's bomblet explosion (500 damage per bomblet) under its normal rocket. The
    bomblets explode as one row, both those of its normal rocket and those of its cluster round.
    The catalogue named that row only after the cluster round:
    support_weapon/rl77_airburst_rocket_launcher/function_expiry/shrapnel_expiry.
  • It now also has the owner-neutral alias support_weapon/rl77_airburst_rocket_launcher/bomblet. The old id keeps
    working. See docs/explosions.md ("Chains with several sources").
  • The support-weapon catalogue links the wiki branch "RL-77 P1 IE" to that explosion, and "EAT-700 P1 IE" to the
    EAT-700's napalm shrapnel explosion. The link is structural: the burst's shrapnel projectile and that projectile's
    impact explosion. Both are authored through hd2.explosion(name). See docs/support-weapon-api.md.
  • scripts/research_explosion_identities.py now records every named source of a chain explosion as an owner: the
    bomblet row lists both RL-77 bursts in sdk/ExplosionCatalogue.json (owners). Ids, sharing and packages do not
    change.

The game's own names in the game's language (offline only)

  • A translator reported that the object names a tool shows (the Runtime's keys, such as AR-23 Liberator) cannot be
    localized. The game has every one of these names in all 15 languages. hd2.text now reads them from the game, in
    the language it is set to:
    • hd2.text.name(kind, key) and target:display_name() return 'AR-23 解放者' and its parts. Kinds: weapons,
      support weapons, throwables, backpacks, vehicles, boosters and stratagems.
    • hd2.text.language() / hd2.text.available() say whether the texts can be read now;
    • hd2.text.game(id) reads one text by id.
  • Read-only: nothing is written and nothing needs an acknowledgement. A lookup that cannot answer returns nil, a code
    and a reason, and the caller shows the key: before the game registers its text (UNAVAILABLE), for another language
    than the game's (LANGUAGE_NOT_LOADED: only the current one is in memory) or on another build.
  • Na...
Read more

HD2Runtime v0.31.1 — Performance Graph, Every Language, Bug Holes, Grenade Statuses and More Weapon Damage

Choose a tag to compare

@SkyeShade SkyeShade released this 11 Oct 04:45

HD2Runtime 0.31.1 — performance graph, every language, bug holes and more weapon damage

0.31.1 is a small feature release. It adds a live performance graph and HD2Runtime's own text in every game language
to the F10 panel, an event for closed bug holes, and the damage rows the stats editor was missing for the Peacemaker,
the Redeemer, the missile launchers and the AC-8 flak. Each item says whether it was seen working in game ("live") or
is covered by the offline tests only. The new weapon fields need allow_unverified_effect.

F10: Performance tab (live)

  • The F10 panel now has two tabs, SETTINGS and PERFORMANCE. PERFORMANCE shows, live, how much time HD2Runtime and each
    mod take per frame:
    • the total, its share of the frame time, and the frame rate;
    • a stacked graph of the last 15 seconds;
    • the heaviest parts, each with its average and peak: every mod (MOD) and every part of the Runtime (HD2R: an
      event source, the custom stratagems, an overlay, ...).
  • It measures only while the tab is shown, and only time spent in HD2Runtime and its mods (not the game itself).
    Each event source's poll is now timed on its own, so it shows up in the graph and in the PERFORMANCE log lines.
    See docs/getting-started.md ("Performance") and docs/runtime-performance.md ("Live view").

F10: Interface size (offline only)

  • SETTINGS > INTERFACE sizes the panel and its text with - and +: 90, 100, 110, 125, 140 or 150 %, the HD2R
    Editor's sizes. It is saved, and kept to what fits the screen.

HD2Runtime's own text in every game language (offline only)

  • Everything HD2Runtime shows on screen is now in the game's language: the F10 panel, the notices, the alert cards,
    the custom stratagem panel and its details, the startup progress and the version label. The log stays English.
  • F10 has a Language row: Automatic (the default) follows the game's language; or pick any of the game's 15
    languages.
  • The translations were generated, not written by native speakers. Corrections are welcome, especially the game's own
    terms (stratagem, Quickplay, SOS).
  • hd2.ui.open_settings() / close_settings() / settings_open() open the panel from a mod (the HD2R Editor's
    Settings has a button), and hd2.ui.language() returns the language in use.

Bug holes: bughole_destroyed (live)

  • A new event fires once when a bug hole is closed, with:
    • the hole's kind (warrior, bile_titan, shrieker, ...) and whether it is a Bile Titan hole;
    • its entity, the destruction level and its position;
    • whether this machine owns it (the host).
  • It reads the game's own destruction state 4 times per second, and only while a mod subscribes. Who closed the hole
    is not known: the game does not record it.
  • Live (user report, without a log): closing bug holes fired the event. Clients, Bile Titan holes and the payload
    (kind, position) have not been confirmed in game yet. examples/projects/BugHoleEventTest logs and shows each one.
    See docs/events.md ("Bug holes").

Weapon damage the stats editor was missing (offline only)

  • P-2 Peacemaker and P-19 Redeemer: their round's damage and projectile fields. Their weapon record leaves the
    projectile to the ammunition row, so the fields come from that row.
  • FAF-14 Spear, MLS-4X Commando, StA-X3 W.A.S.P.: the missile's direct hit (damage.primary.*, for example the
    Spear's 4000).
  • AC-8 Autocannon flak, GR-8 Recoilless Rifle HE, RL-77 Airburst cluster: the programmable round's projectile and
    damage rows (support_weapon(name):attack('programmable')). The GR-8 row is also fired by the TD-110 and TD-220
    tank guns (allow_shared).

Statuses on grenades (offline only)

  • A throwable's explosion can now take a status the way a weapon explosion can (a player request: "the gas grenade
    has no space to add statuses"). Its used status slots can be swapped, and its first empty slot takes a new status
    and its strength: for example the G-4 Gas (Gas, Gas Confusion) gets a third status. Any of the 34 attachable statuses
    can be chosen. allow_shared and allow_unverified_effect are required. See docs/throwable-authoring.md.
  • Weather statuses such as Acid Storm stay unavailable on every weapon and grenade. Acid Storm's definition is a
    one-second marker with no damage; what the storm does comes from the weather system, which HD2Runtime has not
    mapped.

Compatibility

  • Mods built for 0.31.0 work unchanged.
  • The startup line reads HD2Runtime 0.31.1 initialized (API 1).
  • A mod that uses bughole_destroyed or hd2.ui.open_settings / hd2.ui.language needs min_version 0.31.1. The
    new weapon rows need 0.31.1 too: on 0.31.0 they are unknown fields.

HD2Runtime v0.31.0 — Beams, Wind-up, Missiles, Charges, Other Mods' Values and Every Game Language

Choose a tag to compare

@SkyeShade SkyeShade released this 11 Oct 00:06

HD2Runtime 0.31.0 — beams, wind-up, missiles, charges, other mods' values and every game language

0.31.0 is a feature release built from player reports and the stats editor's wish list. Each item says whether it was
seen working in game ("live", solo unless stated) or is covered by the offline tests only. Most new fields need
allow_unverified_effect: the Runtime proves where each value lives and that the game reads it, but its effect in
play is still awaiting confirmation in game. Expect hotfixes as reports come in.

Other mods' values

  • A value another mod changed refuses only itself (offline only). When a value differs from both the game's and
    every HD2Runtime write, it belongs to a mod outside HD2Runtime (a data-file mod or another program). That write is
    refused with CONFLICT ... owner: unknown mod, not HD2Runtime, and its result carries owner = 'unknown' and
    foreign = true. Every other write goes ahead. Each such value is logged once (FOREIGN VALUE) and listed by
    hd2.diagnostics.foreign_values(). A link another mod changed in a stratagem's attack chain refuses only the
    values below it. A conflict on bytes HD2Runtime does not track (an attachment delta row) is a plain CONFLICT,
    never blamed on an unknown mod.
  • Component tables another mod moved (offline only). Some mods point the game at their own copy of a component
    table, so writes to the game's table changed nothing (the LAS-12 Sai heat report). HD2Runtime now checks, read-only,
    that the game reads each component from the table it writes. A moved table refuses only that component
    (COMPONENT TABLE MOVED, owner unknown) and is logged once.
  • hd2.inspect{target, fields} (live: reads and ownership). Read-only. For up to 64 fields of a typed target it
    says who owns the live value: vanilla, runtime (and which mod), foreign (an unknown mod), changed,
    unavailable or invalid, with the value. A stats editor can show other mods' values read-only before writing
    anything. A weapon whose entity map row another mod rebuilt reads as changed, owner unknown. Detection of a real
    data-file mod's value has not been confirmed in game yet.

Text in every game language (fixes issue #8)

  • Mod windows draw Chinese, Japanese, Korean, Russian and Latin extras with the game's own fonts (live,
    2026-10-09: Simplified and Traditional Chinese, Japanese, Korean, Russian and Spanish each drew their own text).

    Characters no loaded font has still show ?. Text is now 1-512 bytes and wraps without splitting a character.
  • In any game language (offline only). The game loads only its selected language's font. Text that needs another
    language's font now loads that font package on demand. The Runtime's own panels (the custom stratagem details and
    tooltips, the alert card) use the same fonts.
  • hd2.ui.can_draw(text), hd2.ui.game_fonts() and hd2.ui.unsupported(text) (the characters no game font can ever
    draw, for translation tools). Greek cannot be drawn: no game font has it.

Status effects

  • Status effect stats (writes live; gameplay effect not yet confirmed). hd2.status_effect(id) edits a status
    definition itself: status.duration, and through :damage() the damage it deals while active (needs
    allow_unverified_effect). Every user of that status changes, so writes need allow_shared. hd2.status_effects()
    lists all 71 ids. The tick rate is not exposed.

Weapons

  • Wind-up (firing charge) on heat weapons (offline only). heat.firing_charge, heat.charge_gain_per_second,
    heat.charge_loss_per_second and heat.reset_charge_after_shot (the Sickles' 0.5 s wind-up, the Quasar's warm-up).
    Also on the AX/LAS-5 Rover gun and the A/LAS-98 Laser Sentry. heat.warmup now reads as the derived value, and
    "cooldown after overheat" says which fields to edit (the LAS-99 Quasar report).
  • Wind-up controls everywhere (offline only). windup.wind_up_seconds and windup.wind_down_seconds on the
    EXO-45 Patriot minigun and the TD-110 Maelstrom tank gun. windup.wind_down_seconds is described as what it is: a
    spin-down switch.
  • Beam pulse fields (offline only). beam.fire_mode, beam.fire_rate, beam.pulse_beams and beam.pulse_seconds
    on every beam weapon: a Trident-like LAS-5 Scythe is one transaction on its own record. The LAS-13 Trident's pulse
    length is labelled as what limits its fire rate (a pulse starts only after the previous one ended). The Rover gun's
    beam.fire_rate has the reviewed 1-6000 range.
  • Beam swaps (offline only). The LAS-5 Scythe, LAS-7 Dagger, LAS-13 Trident, LAS-98 Laser Cannon, 40-K Meltagun and
    A/LAS-98 Laser Sentry fire any catalogued beam through weapon:beam_source() and hd2.fields.attack.beam
    (allow_unverified_reference and allow_unverified_effect). A projectile weapon cannot fire a beam this way.
  • Beam conversion (experimental; solo, or a lobby where every member runs the same HD2Runtime with the identical
    conversion).
    hd2.weapon(name):beam_conversion() makes a projectile weapon fire the LAS-13 Trident's pulsed beam,
    with its own rate of fire (1-900 rpm), beams per pulse, pulse length and, optionally, its own damage, armor
    penetration and range. It needs allow_component_swap and allow_unverified_effect, and writes only while no
    instance of that weapon exists.
    • Add layout (42 weapons): the weapon keeps its projectile component and gains a beam. Allowed with other
      players only when every member posts the identical conversion; otherwise it is refused or restored.
    • Swap layout (24 weapons, such as the AR-23 Liberator): solo only, and restart the game after using it.
    • Refused (25): shotguns and launchers fed by rounds, the autocannon, the Maxigun and GL-28, and charge weapons.
      Melee, arc, spray and beam weapons are out of scope.
    • The swap layout's mechanism was seen working live, solo, in development builds (Liberator, Talon and Reprimand at
      their own rates). Neither layout has been played through this API yet, and nothing of it has been tested with
      other players. See docs/beam-conversion.md.
  • Missiles (offline only). missile.* and function_missile.*: the flight of the missile the StA-X3 W.A.S.P.,
    FAF-14 Spear, MLS-4X Commando, P-33 and P-92 spawn per shot (lifetime, speeds, acceleration, turn rates, guidance
    delay). No missile swap is offered.
  • Team-reload ammunition (offline only). The GR-8, RL-77, FAF-14 and StA-X3 can carry spares of their own
    (magazine.spare_magazines, starting_magazines, magazines_from_supply, 0-31), and the AC-8 rounds of its own
    (rounds.spare_rounds, starting_rounds, rounds_from_supply, 0-511; multiples of 5 recommended). The wielder
    reloads from them alone before the backpack is used. The five team-reload backpacks get deposit.capacity,
    start_amount and refill_amount.
  • Fire-mode selector on single-mode weapons (offline only). The 30 single-mode weapons with a free input (the
    R/40-K Hot-Shot among them) can get two or three modes, with weapon_function = 'fire_mode' bound in the same
    transaction. The selector reaches three modes (the docs said four).
  • CQC-20 Breaching Hammer blast (offline only). support_weapon(...):attack('ability'):explosion().

Vehicles and backpacks

  • Mounted spread (offline only). weapon.horizontal_spread / weapon.vertical_spread on the 17 projectile mounts
    (Exosuit guns, FRV guns, Bastion, Maelstrom and more).
  • EXO-55 Breakthrough shield arm (offline only). hd2.vehicle('EXO-55 Breakthrough Exosuit'):shield(): the arm's
    health, and its plate's health and armor.
  • Hover Pack height explained. There is no height value: the pack climbs only while its lift
    (hover.vertical_acceleration_low_speed) is above gravity (9.82; vanilla 9.8 only holds height), for
    hover.duration seconds of air time. The descriptions and names now say so. Nothing in the write path changed.

Stratagems

  • Charges before cooldown (offline only). stratagem.rearm_pool = 'eagle_rearm' puts a non-Eagle stratagem in the
    Eagle Rearm pool, the game's only charge mechanism: its uses become charges refilled together by Eagle Rearm, and
    it shares the Eagle cooldown. An unlimited pool member is refused.
  • Orbital targeting (offline only). The Orbital Railcannon Strike's orbital.search_radius, movement_speed,
    duration and fire_delay; the Orbital Laser's orbital.retarget_interval. The Railcannon's shot count and
    target priority are not editable.

Thanks

Bans, author of
True Lasgun Beam Overhaul, whose mod was the research lead
for the laser work in this release: the wind-up, the Trident's pulsed beam, beam swaps and the add layout of beam
conversion. HD2Runtime proves each member itself from the game's data; none of his code is used.

Compatibility

  • Mods built for 0.30.3 work unchanged. New 0.31.0 features need min_version 0.31.0.
  • The team-reload weapons' own magazine rows and the AC-8's own rounds rows now need allow_unverified_effect. Mods
    that declare an older SDK keep writing them without it, as logged legacy operations
    (docs/legacy-sdk-compatibility.md). Their values are bounded by the game's network fields (0-31 magazines, 0-511
    rounds).
  • fire_mode.modes accepts at most 3 modes (was 4: the fourth slot is never selected).
  • The startup line reads HD2Runtime 0.31.0 initialized (API 1).
  • Multiplayer: only beam conversion has multiplayer rules (above), and they are implemented and tested offline only.
    Nothing else new in 0.31.0 was tested with several players.

HD2Runtime v0.30.3 — Bug Fixes and Unlimited Custom Stratagem Uses

Choose a tag to compare

@SkyeShade SkyeShade released this 09 Oct 02:26

HD2Runtime 0.30.3 — bug fixes and unlimited custom stratagem uses

0.30.3 fixes two problems players reported with 0.30.2, and lets the stats editor give custom stratagems unlimited
uses. There are no new fields.

A false "Another mod changed the stratagem data" card

In a busy game (many mods, a slow update), the custom stratagem check before a launch failed to read the stratagem
table. It reported that failure as "Another mod changed the stratagem data", then showed WILL FAIL as the mission
loaded, although the custom stratagems worked. The read now completes however busy the update is. Only a real change
to the table's shape shows the card. Any other failure shows nothing, is logged once and is tried again later.

One odd entity no longer blocks every mod's writes

Every typed write reads the game's entity map. When one row of it was not as reviewed (seen live: the LAS-12 Sai's,
probably changed by another mod), every typed write of every mod was refused with invalid/ambiguous bounded pointer,
including stat editor changes, entity plans and weapon mods that had nothing to do with that entity. Now only writes
to that one entity are refused, with the same reason. Every other write goes ahead, and the log names the row once
per session (docs/diagnostics.md, "Stray entity map rows"). The checks themselves are unchanged.

Unlimited uses for custom stratagems (for the stats editor)

hd2.custom_stratagem.tune(id, {uses = 0}) or {uses = -1} makes a custom stratagem's uses unlimited on this
machine, the same as registering it with no uses. register and custom stratagem projects accept 0 and -1 too.
describe(id) reports unlimited_uses, and limits.unlimited_uses = {0, -1}. An Eagle's uses stay per rearm and
cannot be tuned.

Compatibility

  • Mods built for 0.30.2 work unchanged. min_version stays as it was for every feature.
  • Unlimited uses (0 / -1) need 0.30.3: on 0.30.2, tune returns nil and the reason, and nothing changes.
  • The startup line reads HD2Runtime 0.30.3 initialized (API 1).
  • Both problems were diagnosed from a player's log. The fixes are covered by the offline tests and are not live-tested yet.

HD2Runtime v0.30.2 — Settings Panel, Clearer Custom Stratagem Problems, Seven Weapons Unlocked

Choose a tag to compare

@SkyeShade SkyeShade released this 09 Oct 01:13

HD2Runtime 0.30.2 — settings panel, clearer custom stratagem problems, seven weapons unlocked

0.30.2 is a patch release built from player reports and the stats editor's wish list. Each item says whether it was
seen working in game ("live", solo unless stated) or is covered by the offline tests only.

In game

  • Settings panel (F10, live). F10 opens a small HD2Runtime settings window in the HD2R Editor's look. Turn off the
    startup notice, the custom stratagem alert cards, the version label (bottom left) or the startup progress panel (top
    right). Changes apply at once and are saved for later sessions; the log keeps every line either way. F10 is the
    Runtime's own key: a mod that binds plain F10 is left unbound and logs the conflict.
  • Startup notice (live). The Public lobby warnings of 0.30.1 are now one notice when you first board the ship:
    public lobbies can cause issues or crashes due to mods, and Friends Only / Invite Only is safest. It says where the
    settings panel is. Nothing is read from or changed in the lobby.
  • Custom stratagem alert card (look live). Before a launch, HD2Runtime predicts what would make your selected custom
    stratagems fail and shows it on a card at the top right with how to fix it: a player without HD2Runtime or with other
    custom stratagem mods, a custom stratagem with no free carrier, a carrier slot that still has to switch, or another
    mod that changed the stratagem data. The card also shows when custom stratagems are DISABLED in the lobby, and when a
    custom stratagem keeps its vanilla name because the game's text list is full. It is shown again every minute while a
    problem stands, once more as the mission loads, and replaced by a short READY card once it is fixed.

Custom stratagems

  • Carriers go to your picks first (live). Before, every installed custom stratagem was given a carrier whether it
    was picked or not. With more custom stratagems of one kind installed than carriers owned (for example four Pelicans
    and two barrages, five orbitals), random tiles were dimmed and a pick could even be refused at launch. Now the picked
    ones get their carriers first. The others are dimmed only when picking them would really leave them without one.
  • No false "another mod changed the stratagem data" (live). The check read the table while the Runtime's own
    presentation of a picked custom stratagem was applied, and blamed another mod for it. It now reads the table once per
    session, at a moment nothing of the Runtime is applied, and logs its reason.
  • A full text registry no longer stops custom stratagems (growth live). The game keeps its texts in a registry of
    fixed size. When other mods fill it, HD2Runtime grows it the way the game does. If that is not possible, the custom
    stratagem keeps its vanilla name and description but still gets its icon and code. The log describes what holds the
    registry.

Weapons and fields

  • Seven weapons unlocked. The GP-31 Grenade Pistol, P-72 Crisper, LAS-5 Scythe, LAS-7 Dagger, CQC-42 Machete,
    CQC-73 Entrenchment Tool and SMG-37 Defender were refused because each matched two weapons in the game data. Each is
    now resolved to its proven weapon (equipped snapshots, underbarrel hosts, a call-in rack). Live: the Dagger's heat
    capacity, the Scythe's heat per second, the GP-31's starting and spare rounds, the P-72's capacity and the Defender's
    fire rate. The melee tools were not tried. The GP-31 and the Dagger now read their own values (the Dagger's old
    2000 heat capacity came from the wrong weapon). The Scythe's heat capacity and heatsinks stay read-only: its default
    Laser Heatsink overwrites them when the weapon is built.
  • Status effects on player-weapon explosions (offline only). For example, a Purifier charged shot that only adds a
    status, with no bigger blast.
  • 23 more attachable status effects (offline only; the experimental ones need allow_unverified_effect).
  • Sentry and emplacement projectile swaps (offline only): seven hosts through
    hd2.stratagem(name):attack('primary'):projectile_source(). The A/MG-43 and A/G-16 stay read-only: their magazines
    name each round.
  • Backpack-fed ammunition rows (AC-8, GR-8, FAF-14, RL-77, StA-X3) carry noEffect.reason in the SDK: the backpack
    holds the ammunition, so a write there does nothing. Writes are still accepted.

Mouse wheel and GameGuard

  • The mouse wheel hook stays on by default. The runtime ZIP has a pick-one install choice in the mod managers: "Mouse
    wheel hook on", or "Mouse wheel hook off (may fix GameGuard crashes)". With the hook off, mod windows scroll over game
    menus, or with their scrollbars and Page Up / Page Down.
  • hd2.input.wheel_status() reports the choice and a message a mod can show.

Diagnostics

  • An entity map error names the row and resource it is about.
  • A conflict that no HD2Runtime write explains now says it came from another program writing game memory, or from a
    mod whose own data files change that value.
  • The shared-records index logs what its first build cost.

Compatibility

  • Mods built for 0.30.1 work unchanged. New 0.30.2 features need min_version 0.30.2, and so do writes on the seven
    unlocked weapons.
  • Two sound names were renamed, and the old names still work: primary/smg37/seaf (now seaf/3) and
    secondary/gp31/alt (now other/wep_grenadier_rifle/1).
  • The attack output SMG-37 Defender (projectile 150) is retired. Projectile 150 is the SEAF SMG's round, not the
    Defender's. The name is refused with that reason.
  • The startup line reads HD2Runtime 0.30.2 initialized (API 1).
  • Multiplayer: nothing new in 0.30.2 was tested with several players. The carrier change gives every player the same
    answer by design.

HD2Runtime v0.30.1 — Public Play Re-enabled by Default

Choose a tag to compare

@SkyeShade SkyeShade released this 08 Oct 15:16

HD2Runtime 0.30.1 — Public play re-enabled by default

0.30.1 changes one thing: HD2Runtime no longer blocks Public matchmaking. In 0.30.0 the Runtime switched a Public
lobby privacy setting to Friends Only and cancelled Quickplay. Now it only warns.

Matchmaking safety: warnings only

  • Public privacy is allowed. When this machine's lobby privacy is Public, or a lobby it hosts advertises Public, the
    Runtime writes one log line and shows the safety notice (top right): Lobby privacy is Public: strangers can join.
    It warns again only after the lobby has been non-Public and then becomes Public again.
  • Quickplay is allowed. Each Quickplay run gets one log line and one notice: Quickplay joins public games with
    strangers.
  • SOS Beacon: warned about as before.
  • Nothing is changed or called. The game's privacy setter and Quickplay stop are no longer called, so the native
    call adapter is never created. Friends Only, Invite Only, Friends and Clan, offline and singleplayer get no warning,
    as before.
  • If the game build's pins do not match, one log line says the warnings are unavailable. No notice is shown, because
    nothing is blocked either way.

The startup log says MATCHMAKING SAFETY ACTIVE (warnings only). The 0.30.0 enforcement code is unchanged and still
tested; it is off by default (ENFORCE=false in runtime/matchmaking_safety.lua).

What this means in play: players without HD2Runtime, or with other mods, can join a Public lobby. Mods change the
game only on the machine that runs them, and host-decided systems (for example enemy spawns) follow the host. Custom
stratagems keep their 0.30.0 multiplayer rules: a lobby whose custom-stratagem registries do not match disables them
and locks the custom slots. Use Friends Only or Invite Only to play only with compatible Runtime users.

Compatibility

  • No API, field, schema or SDK content change. Mods built for 0.30.0 work unchanged, and min_version stays 0.30.0
    for anything new in 0.30.0.
  • The startup line reads HD2Runtime 0.30.1 initialized (API 1). The SDK metadata reports 0.30.1.
  • Not live-tested yet. The warnings use the same reads as 0.30.0's live-tested matchmaking safety, but nothing is
    called now. They are covered by the offline tests (tests/test_matchmaking_safety.py, WarningsOnlyTests).

HD2Runtime v0.30.0 — Custom Stratagems

Choose a tag to compare

@SkyeShade SkyeShade released this 08 Oct 09:40

HD2Runtime 0.30.0 — Custom Stratagems

0.30.0 adds custom stratagems: mods register new stratagems with their own name, icon, code and payload. The
Runtime handles selection, carrier allocation, presentation, the beacon, every guarded write and every restore. The
release also adds weapon variants for every support weapon, armor stats and passives, Helldiver-wide fields, the
explosion and sound catalogues, the game's own HUD icons in mod overlays, and services for UI and editor mods.

What is live-tested is listed per capability in docs/live-evidence.md (schemas/live_evidence.json). Everything
else is validated offline, and its writes need allow_unverified_effect until a live test passes. The development
log of the 0.30.0 test builds (r1 to r59) is docs/releases/0.30.0-dev.md.

Compatibility

  • Mods built for 0.28.x keep working. No field that SDK 0.28.1 published as editable lost editability: 14,972
    fields then, 17,101 now, across the player weapon, support weapon, backpack and vehicle catalogs.
  • One new acknowledgement, handled as legacy. The PLAS-45 Epoch's 30 partial-charge projectile, damage and
    explosion fields now need allow_unverified_effect, because only its partial charge fires that row. A mod that
    declares SDK 0.28.x or older is accepted without it, as a logged legacy operation, as in 0.28.1
    (schemas/legacy_acknowledgements.json, docs/legacy-sdk-compatibility.md). The 0.28.0 entries (146 fields) are
    unchanged.
  • Versions. The startup line reads HD2Runtime 0.30.0 initialized (API 1). A mod that uses anything new in 0.30.0
    declares "min_version": "0.30.0". Mods built against the 0.30.0-dev test builds ("0.30.0-dev") load too.
  • ModBuilder and other SDK tools. The SDK publishes the new catalogues and schemas:
    • CustomStratagemSchema.json and schemas/custom_stratagems.project.schema.json;
    • ArmorStatsCapabilities.json and ArmorPassiveCatalog.json;
    • HudIconSprites.json, ModelBaseCapabilities.json and the sound and explosion catalogues;
    • the new field families in the existing capability files.

Custom stratagems

hd2.custom_stratagem.register({...}) (docs/custom-stratagem-api.md). A builder can write the same thing as data
(custom_stratagems.json, compiled by hd2.py custom-stratagem compile; docs/custom-stratagem-builder.md).

  • Selection. A Runtime-owned panel beside the native loadout grid, in the native card look, with the game's FS
    Sinclair font, a details overlay (the code in arrows, call-in time, uses, cooldown), scrolling, and several instances
    of one definition.
  • The carrier is the stratagem. A selected custom stratagem sits in a loadout slot as its carrier, a vanilla
    stratagem the player does not use that mission. Carriers are picked from dynamic pools, reserved for the lobby and
    blocked in the native picker while held. Carriers are never account items, and loadouts are never restricted.
  • Presentation. Runtime-owned text and icons: the name, cased name, description, icon and call-in code in the
    HUD, the pickup prompt, the map and the panels. Everything is restored byte for byte aboard the ship.
  • Payload families:
    • support pods (any support weapon or backpack, with per-launcher impact conversion, for example the Gas EAT);
    • expendable clones (an EAT-17 clone on an unused EAT-700 or EAT-411 type);
    • weapon variants;
    • orbital bombardment patterns and shell redirects;
    • Pelican close air support with native or custom guns;
    • Eagle rocket pods;
    • sentries;
    • the Shredder Silo;
    • script delivery.
  • Uses, cooldowns and traits per definition, and teammates' custom stratagems shown on the teammate HUD.
  • Weapon variants for every support weapon. delivery={family='weapon'} changes a support weapon's own type for
    one mission: its name and icon, its round (another output of its own compatibility class), and optionally a
    Runtime-owned model (hd2.resources.model).
    • Coverage: 34 of 35 support weapon types are hosts, and 32 register. The TX-41 Sterilizer's and the MS-11 Solo
      Silo's pods are not reviewed pickup racks; the SG-88 Break-Action has no stratagem of its own.
    • Hosts that world loot or another pod also brings need allow_shared.
  • Synced assets. A peer on the same Runtime loads the packages another player's mod needs (the hd2as channel).

Live-tested (solo host unless stated):

  • the panel, selection, virtual slots and their reconstruction;
  • carrier conversion and presentation (custom text and icon, calldown codes, the slot overlay);
  • the bombardment pattern and shell redirect;
  • the expendable clone, its availability and payload;
  • weapon variants:
    • the Maxigun with the Talon round and a debug model;
    • the AC-8 with the EAT-700's napalm round;
    • the GR-8 with the EAT-411's round;
    • the MG-206 with the APW-1's round;
    • the LAS-98 renamed.

Partial: the native-style panel; the carrier in the slot (two players, r43); the expendable delivery; the Pelican's
native gun; the Shredder Silo. See docs/live-evidence.md.

Several players: EXPERIMENTAL. Custom stratagems run in an experimental multiplayer scope. Every compatible Runtime
converts its own copy from the synced definition over the lobby channel (hd2rt/1). A mismatched registry fails
closed: custom stratagems are disabled lobby-wide and custom slots are locked. Live with two players:

  • the Gas EAT (r3);
  • four example mods with the carrier in the slot (r43).

The rest is not proven with several players. Custom projectiles are solo / host-only; see "Not in 0.30.0".

Armor and the Helldiver

  • Armor passives (docs/armor-passives.md): every passive of the game's 32 is named. The 411 armor kits are
    listed, 378 of them by name. A table says which passive effects follow a swap. Effect packages load before the
    write and sync to peers.
    • hd2.player_passives.set({armor, second}) overrides the local player's armor passive, solo.
    • Live-proven armor swaps: SCOUT, ENGINEERING KIT, SERVO-ASSISTED, MED-KIT.
  • Armor stats (docs/armor-stats.md, not live-tested): hd2.armor_stats.
    • Per kit: a kit's piece weights.
    • Per player, solo: the local player's armor bonus and stamina factor.
    • Every Helldiver on this machine: the per-weight class tables (armor value, speed, stamina) and the damage curve.
    • The class tables and the curve live in game.dll pages mapped PAGE_EXECUTE_READWRITE. They are written as
      reviewed executable data: exact 4-byte extents a domain registers after its own proofs, never re-protected,
      the only such exception (the user's decision). Whether an anti-cheat scan reacts to that is not known.
  • Type-wide Helldiver fields (hd2.helldiver(), not live-tested): movement speeds, stamina, and each body zone's
    damage multiplier, durable share, damage to main health and health. These change every Helldiver this machine
    simulates, so every write needs allow_shared.

Weapons, stratagems and the world

All of these are offline-proven unless docs/live-evidence.md says otherwise:

  • muzzle, optics and underbarrel attachment stat modifiers (132 fields);
  • the orbital bombardment pattern (salvos, shells, delays, scatter), stratagem.call_in_time, Eagle attack fields,
    and sentry and turret fields;
  • PLAS-45 Epoch and RS-422 Railgun charge-level explosions;
  • 32 more projectile donors (Eagle payloads, orbital shells, mortars, emplacements);
  • hd2.projectiles.homing, and hd2.projectiles.modify_shots (per-shot stat changes on fired rounds), both solo;
  • enemy spawn weights (hd2.enemies.spawn_weight);
  • the explosion catalogue: 241 of 422 explosions named, editable, usable as payloads and requestable;
  • vehicle tuning.

Services for mods

  • hd2.ui.overlay screen overlays, with Runtime fonts (FS Sinclair) and the game's own stratagem and booster HUD
    icons (hd2.resources.game_icon).
  • Sounds: hd2.sounds (all 10,030 Wwise events catalogued) and playback controls.
  • Input:
    • keys and chords;
    • the mouse wheel (experimental);
    • hd2.input.block (experimental).
  • hd2.on_frame, a per-mod store, hd2.build() and ensure recovery.
  • Editor services:
    • following choices;
    • every mod's options;
    • tuning custom stratagems.
  • Diagnostics and performance:
    • per-mod CPU time ("which mod is slow");
    • a startup progress display;
    • faster initial discovery;
    • quieter logs: per-call traces and the read-only "Ongoing" HUD-timer probe (one line a second per call) run only
      with hd2.custom_stratagem.verbose(true).
  • A version label aboard the ship.
  • Proton and Wine: copy-on-write data pages are accepted as read contexts (GitHub issues #3 and #6; not live-tested on
    Linux).
  • Building examples and mods from the downloads works from inside the extracted SDK (GitHub issue #2).

Not in 0.30.0

  • Custom projectiles in multiplayer. These are solo / host-only, and other players never see them:

    • Runtime-owned custom projectile rows;
    • projectile replacement;
    • the Pelican gun's custom rounds;
    • per-shot modification.

    They refuse NOT_SOLO or stay host-only with several players. The multiplayer design (each machine converting its
    own copy of a shot) moves to the next version. This was the user's decision of 2026-10-08.

  • Full weapon clones beyond the EAT class. scripts/research_clone_classes.py reviewed every donor / carrier pair.
    Only EAT pairs are eligible; the others differ in their magazine contract, AI equipment type or backpack link, or
    have unreviewed members. A variant of the weapon itself is the supported customisation.

  • Composition with other writers. A weapon variant refuses (NOT_NATIVE, nothing written) when another writer
    changed its records. The log names the changed words. Live: a third-party HMG buff mod.

Validation

All of it ran from the release-candidate artifacts built at 893d31f (build/release-candidate-0.30.0/).

  • **Unit suit...
Read more