Skip to content

Releases: scubamount/sco-core

sco-core SDK 2.3.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 07:11
Immutable release. Only release title and notes can be modified.

See the SDK 2.3.0 release notes and the
SDK 2.3.0 scope record.

SDK 2.3.0 packages the entries below without changing frozen plugin ABI 1.1
(include/sco_api.h and tests/abi_v1.c are byte-identical to 2.2.0). Core, legacy,
core-source and host-source-sc use 2.3.0. The candidate adds the game service tables
game.asop 1.0 and game.contracts 1.0 and grows game.loadout to 1.1, so under the
game-pack policy (a release that adds or grows a game service raises the
minor) the game pack and the optional game-sc overlay move to 0.6.0
(SCO_GAME_PACK_VERSION, was 0.5.0; sco-sdk-game-sc-0.6.0.zip). Nothing below has run in the
game: evidence is macOS local builds and synthetic fixtures. Linux, native Windows, GPU and
real-game acceptance are unproven. The new game capabilities (game.asop.claim_timeout,
game.asop.shard_persisted, game.contracts.stream_radius, game.loadout.weapons,
game.pak.all_files) default OFF, and no production adapter turns them on.

  • game.loadout 1.1: weapon and multitool slots 8-21 (vocabulary only), game.loadout.weapons OFF (docs, contracts). include/sc_loadout.h adds fourteen slot names after SC_LOADOUT_SLOT_VISOR: SC_LOADOUT_SLOT_PRIMARY (8) and SC_LOADOUT_SLOT_SIDEARM (9) for the weapons themselves; SC_LOADOUT_SLOT_PRIMARY_OPTIC, _PRIMARY_BARREL, _PRIMARY_UNDERBARREL (10-12) and SC_LOADOUT_SLOT_SIDEARM_OPTIC, _SIDEARM_BARREL, _SIDEARM_UNDERBARREL (13-15) for firearm attachments; SC_LOADOUT_SLOT_PRIMARY_TOOL_MODULE, _PRIMARY_TOOL_CANISTER, _PRIMARY_TOOL_BATTERY (16-18) and SC_LOADOUT_SLOT_SIDEARM_TOOL_MODULE, _SIDEARM_TOOL_CANISTER, _SIDEARM_TOOL_BATTERY (19-21) for multitool parts. The records are unchanged (sc_loadout_item and sc_loadout_v1 keep their layout and sizes); a slot number just encodes its parent weapon. Like the body slots these are logical slots, not engine port names, and a batch is still processed in input order, so a consumer sends slot 8 or 9 before the attachment slots it targets. There is no removal: item_class stays 1 to 95 bytes. The version follows the game.world 1.1 precedent: SC_LOADOUT_VERSION_1_0 and SC_LOADOUT_VERSION_1_1 are added, SC_LOADOUT_SERVICE_VERSION stays 1.0 while 1.1 is published, so a 1.0 query is still answered. The new capability game.loadout.weapons defaults OFF (evidence level synthetic_only): slots 8-21 report SC_LOADOUT_UNSUPPORTED when the installed backend does not declare weapon support and stay SC_LOADOUT_UNAVAILABLE while the capability is off, with no engine call either way; a 1.0 host reports SC_LOADOUT_UNSUPPORTED for them. There is still no production engine backend: src/game/services/spatial.cpp is untouched, so the service starts without one and every slot, body or weapon, reports SC_LOADOUT_UNAVAILABLE in game. Pins tests/abi_game_loadout.c; provider tests use a synthetic backend. Headless tests only: nothing has run in the game.
  • sco.ui.surfaces 1.0: renderer-neutral panel placement (sco_api.h unchanged), a host-owned service (docs, contracts). A plugin shows one of its sco.widgets panels as a 2D HUD rectangle (SCO_SURFACE_HUD_2D), a camera-facing 3D billboard (SCO_SURFACE_BILLBOARD_3D) or a world-anchored 3D quad (SCO_SURFACE_QUAD_3D): register_surface, update_surface_pose, unregister_surface, last_error over size-prefixed sco_surface_desc / sco_surface_pose (position, normal, up, size in metres, max distance, an occlusion-raycast flag, the panel id). The host validates every field (finite numbers, unit and perpendicular vectors, bounded sizes, distances and coordinates, 32 surfaces per plugin and 256 in all, panels under the plugin's own id), stores surfaces per plugin and withdraws them on unload or crash through sco.ui's release hook (no new hook slot). Products read the registry through sco/surfaces.h (Surfaces(), Revision(), CheckPose) and project it themselves; docs/ui.md documents the billboard and quad frames and the panel-to-pixel homography. C++ wrapper scosdk/ui_surfaces.hpp; C# and Lua are unsupported. Pins tests/abi_ui_surfaces.c, host tests tests/test_surfaces.cpp; both ship in core-source, the headers in core. Headless tests only: nothing has run in the game.
  • sco::game::pak Scope::AllFiles (design plan PR 10), OFF by default: persistent swaps of
    the four pinned ICryPak slots (open 0x148, read 0x160, seek 0x1D0, close 0x1E0) serve every
    mounted path on every thread, through a sharded map of served handles. Enable refuses it unless
    the product sets the new Options::allFilesProbed, which no sco-core caller does. The new
    capability game.pak.all_files is registered OFF pending in-game confirmation. Tell, size and
    eof slots have no row, so they are never swapped; QueryHandle and ServedHandles report the
    virtual position, size and eof of a served handle. Disable drains: open served handles keep
    their virtual file, and the slots go back when the last one closes. The mount check is guarded
    like Options::onLoad (try/catch, and SEH on MSVC). Scope::DataCoreLoad behaves as before.
  • files/ replacement mounts (sco/vfs.h): vfs::ReplaceMount (a whole-file Transform,
    refusing absolute, drive and ./.. game paths, inert at open when the file is missing or over
    maxBytes) and vfs::FileMounts (a data pack's files/ folder, symlinks skipped). The plugin
    content index doesn't list files/ yet. Nothing here has run in the game: the evidence is
    synthetic tests (test_pak_files) over a fake ICryPak vtable.
  • Game services: game.asop 1.0 (insurance claim timeout and IsShardPersisted reads), default OFF.
    include/sc_asop.h: sc_asop_v1 (32 bytes, size-prefixed, version 1.0, pinned by
    tests/abi_game_asop.c): claim_timeout, shard_persisted, last_error. Capabilities
    game.asop.claim_timeout and game.asop.shard_persisted are held OFF (evidence level
    off_pending_probe) until an in-game run confirms them; while off every call answers
    SCO_UNAVAILABLE without touching the game. Both functions only read rows that already exist
    in src/game/asop_sigs.cpp and that docs/game/asop.md documents (insurance.config at
    kInsuranceTimeout, asop.shard_persisted); no row, hook, patch or write was added.
    src/game/services/asop_service.cpp is the portable policy behind an AsopProvider seam;
    src/game/services/asop_engine.cpp (Windows game pack) reads the rows under SEH. The vehicle
    list, deliver, retrieve and claim rows stay unwrapped because the repository documents no
    plugin-callable meaning for them (docs/game/asop-service.md). Tests: tests/test_asop.cpp
    (synthetic provider) and abi_game_asop as C11, C++20 and -fshort-enums. Catalogue records
    (sdk/contracts/sc_asop_v1.json) and docs/contracts.md rows added; C++, C# and Lua routes
    unsupported. Registry entry, docs/game/status.md rows and sdk/native_index.json regenerated.
    Nothing here has run in a game session.

  • Game services: game.contracts 1.0 (mission stream radius read), default OFF.
    include/sc_contracts.h: sc_contracts_v1 (24 bytes, size-prefixed, version 1.0, pinned by
    tests/abi_game_contracts.c): stream_radius, last_error. Capability
    game.contracts.stream_radius is held OFF (evidence level off_pending_probe) until an in-game
    run confirms it; while off the call answers SCO_UNAVAILABLE without touching the game. The
    function only reads the contracts.mission_settings row that already exists in
    src/game/contracts_sigs.cpp and that docs/game/contracts.md documents (the float at
    kStreamRadius); no row, hook, patch or write was added. The service name game.contracts was
    unused; the host-internal contracts.* capabilities and game.missions are separate.
    src/game/services/contracts_service.cpp is the portable policy behind a ContractsProvider seam;
    src/game/services/contracts_engine.cpp (Windows game pack) reads the row under SEH. The other
    contracts rows stay unwrapped (docs/game/contracts-service.md). Tests: tests/test_contracts.cpp
    (synthetic provider) and abi_game_contracts as C11, C++20 and -fshort-enums. Catalogue records
    (sdk/contracts/sc_contracts_v1.json) and docs/contracts.md rows added; C++, C# and Lua routes
    unsupported. Registry entry, docs/game/status.md rows and sdk/native_index.json regenerated.
    Nothing here has run in a game session.

sco-core SDK 2.2.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 20:01
Immutable release. Only release title and notes can be modified.

See the SDK 2.2.0 release notes and the
SDK 2.2.0 scope decision.

SDK 2.2.0 packages the entries below without changing frozen plugin ABI 1.1
(include/sco_api.h and tests/abi_v1.c are byte-identical to 2.1.0). Core, legacy,
core-source and host-source-sc use 2.2.0. The maintainer kept the three new game service tables
in the candidate, so under the game-pack policy (a release that adds or grows
a game service raises the minor) the game pack and the optional game-sc overlay move to 0.5.0
(SCO_GAME_PACK_VERSION, was 0.4.0; sco-sdk-game-sc-0.5.0.zip). Nothing below
has run in the game: evidence is macOS local builds and synthetic fixtures. Linux, native
Windows, GPU and real-game acceptance are unproven. The new game capabilities
(game.hangar.lift, game.hangar.atc_cancel, game.reputation.checks,
game.world.free_camera_flag) default OFF, and no production adapter turns them on.

  • sco.widgets 1.1 (additive): the table grows from 24 to 48 bytes with tail members
    update_nodes (atomic subtree replace/insert), remove_nodes (refuses to empty a panel) and
    capabilities (runtime limits by fixed index). Opt-in sco_widget_node_1_1 (severity,
    tooltip, paged LIST/TABLE windows) and sco_widget_event_1_1 (row; new SCO_WIDGET_EVENT_PAGE)
    are selected by their size field; panels without a 1.1 node keep byte-identical 1.0 events.
    The ImGui adapter draws severity, tooltips and Previous/Next paging, and rebuilds a shared
    render snapshot only when a panel changes. 1.0 pins are unchanged except the table size.
    sco-plugin-check remains a 1.0 stand-in; the C++, C# and Lua wrappers expose 1.0 only.
    Headless ImGui-shim fixtures only; GPU rendering not verified.
  • C++ scosdk::PanelBuilder (include/scosdk/menu_builder.hpp): header-only C++20
    declarative Row/Column panels for sco.widgets 1.0 with typed bindings, preorder ids,
    host-equivalent ValidateWidgetNodes and callback dispatch that tolerates a callback
    destroying its own tree. Compared with the real host on 27 node arrays; ASan clean.
  • C# Sco.Sdk.PanelBuilder: fluent Column/Row/Button/Toggle/Slider builder over
    sco.widgets 1.0 with explicit stable ids, frozen build snapshots and typed dispatch.
    Not compiled locally (no .NET SDK on the preparing host); the hosted
    sdk/csharp-host-sim job is its first build.
  • Lua sco.panel_builder: embedded module installed in every plugin sandbox (new(),
    column/row, toggle/slider/button, build() returning node snapshots plus a
    dispatcher). Runs inside the existing instruction and memory budgets; no require,
    filesystem or bytecode.
  • POSIX diagnostics transport recovery: an owner that died without cleanup no longer
    blocks every later session. The mapping is published atomically and held under flock; a
    stale entry is reclaimed only by the holder of its lock after identity re-checks, peers refuse
    a dead owner's mapping, and peer leases are removed on release. Fails closed on the remaining
    crash windows. macOS only; Linux unverified.
  • Game status registry (repository only): sdk/status_registry.json generates the service
    table in docs/game/status.md; tools/status_registry.py --check runs in test.yml. No
    evidence level was raised.
  • Documentation gate: the public documentation set must name the function, table or test
    instead of citing source by line number. A scheduled, read-only live-site job in
    docs-site.yml checks that the deployed docs site is fresh against main.
  • Game tables (game-sc headers, host-source-sc implementation): game.hangar 1.0
    (include/sc_hangar.h: lift open/close request for a landing area, ATC request cancel),
    game.reputation 1.0 (include/sc_reputation.h: read-only state of the reputation check
    sites) and game.world 1.1 (include/sc_world.h grows 32 to 40 bytes with the read-only
    free_camera_flag tail member). ABI pins in tests/abi_game_hangar.c,
    tests/abi_game_reputation.c and tests/abi_game_world.c; host-sim contract tests
    hangar, reputation and world_free_cam. Windows game-pack adapters are not built or run
    locally; no wrapper language exposes these tables yet.
  • Plugin scaffolder (sdk/tools/sco-new-plugin.py, shipped as tools/sco-new-plugin.py in
    core and core-source):
    writes a buildable C or C++20 native plugin with optional
    --with-menu panel and optional service lookups (logged when missing, never required), and
    its CMake check target runs sco-plugin-check. It refuses to overwrite files or write
    through symbolic links. sdk/test_new_plugin.py builds the generated projects on macOS; it
    is not wired into CI yet and MSVC builds are unverified.
  • Engine-native index (repository, site and MCP only, in no SDK zip): sdk/native_index.json
    lists every signature row by id, subsystem, symbolic hash and promotion tier, generated by
    tools/native_index.py and checked in test.yml. The docs site renders it at /natives/
    inside four new library hubs, with a downloadable copy of the same JSON. Rows name readiness
    only: no patterns, masks, offsets or addresses. Publication follows the
    2026-10-14 native-index decision.
  • Discovery MCP server, opt-in tools (repository only): tools/sco-core-mcp offers four
    tools behind --extended-tools; the default six tools and the documented launcher are
    unchanged. list_engine_natives and get_engine_native read sdk/native_index.json and
    refuse a malformed index whole. validate_manifest_and_widgets ports the sco-plugin-check
    manifest rules and checks sco.widgets node arrays. generate_plugin_scaffold returns the
    files sco-new-plugin.py would write as text and writes nothing; it runs the granted
    checkout's scaffolder in the server's own process, so grant only a reviewed checkout.
    Service evidence now prefers sdk/status_registry.json and never reports gameplay
    verification.
  • Docs site: pages are grouped into four library hubs (start and SDK profiles, language
    SDKs and cookbooks, native and service reference, host integration and AI agents) with no
    route moved. Page titles no longer show code backticks.
  • Getting started: docs/getting-started.md downloads, verifies and builds against the
    2.2.0 core archive; the game extension is sco-sdk-game-sc-0.5.0.zip.

sco-core SDK 2.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 22:42
Immutable release. Only release title and notes can be modified.

SDK 2.1.0 packages the engineering entries below without changing frozen plugin ABI 1.1.
The additive game contracts raise the separate game-sc package coordinate from 0.3.0 to
0.4.0; core, legacy, core-source and host-source-sc use 2.1.0. The optional game-sc overlay
binds the exact core archive digest. All five profiles are selected for candidate generation;
publication still requires approval of the final bytes and a maintainer signature. Product
export remains excluded.
The SDK2.1 scope decision
records maintainer scope review, not final signed-byte publication approval.

Native Windows CI fixtures are no-game engineering evidence, not engine or gameplay
acceptance. Preserve each entry's historical verification limits: real-game, anti-cheat,
official-network, private-LAN/firewall and renderer acceptance are not established by this
release preparation. Default-off and fail-closed capability controls remain unchanged.

  • Renderer-neutral text inputs gain SCO_WIDGET_PASSWORD display masking for explicit G13 credentials; only text inputs accept the flag. This is not encrypted storage or a guarantee against host-memory disclosure.

  • G13 private-session broker (R1): owner-approved default-on SessionControlV1
    with strict loopback/no-startup-socket defaults, explicit numeric private bind
    and exact peer allowlist, 12-byte minimum passphrase, bounded ingress/requests,
    fail-closed offline/EAC admission and credential-free lifecycle audit. Add
    public game.private_session 1.0 Host/Join/Leave/state requests for the external
    multiplayer plugin; sockets and policy remain host-only. Host kit publishes
    before plugin load, checks admission before queued work, and stops on admission
    loss/unload/quit using the existing net release dispatcher. Synthetic backend
    and C layout proof only; Windows/MSVC/private-LAN/game NOT VERIFIED. G2 unchanged.

  • Runtime MCP step 2 — host IPC/auth gate (local fixture): default-off host-private mapping, secure per-session credentials/peer lease, mutual directional HMAC and six copied-metadata reads; hostile real-transport and literal-vector fixtures. No sockets, network-key reuse, public ABI change or product/MCP enablement. Protected OS audit/product policy remains step 3; not run in game.

  • C# sco.widgets 1.0 (#142): pinned interop, bounded copied trees, typed rooted callbacks, atomic failures/reentrant updates and archive example/tests; frozen ABI unchanged. Windows NativeAOT/GPU/game not verified locally.

  • Lua sco.widgets 1.0 (#143): sandboxed bounded declarative panels for all eight
    widget kinds and ROW/COLUMN, typed copied events, registry-rooted callbacks until
    successful replacement/removal or unload, atomic failures and reentrant updates.
    Complete member-extent/null guards, shared instruction/memory budgets and real
    neutral-host lifecycle fixtures; archive-contained widgets_lua example.
    Frozen ABI unchanged; GPU rendering/gameplay not verified.

  • G17 diagnostics publishers (#141): add default-off Star Citizen minimal
    metadata snapshots and a host-owned, selected-owner sco.diagnostics.publisher
    1.0 ingress for fixed advisory plugin health. Sources require explicit opt-in
    and positive host offline admission; copy into the existing immutable host
    diagnostics path without plugin callbacks, scanner execution or side channels.
    Extra source fields stay internal: runtime JSON v1 is unchanged and arbitrary
    plugin fields/gameplay data are not accepted. Optional SDK example ships
    disabled; synthetic module, ABI and truncated-tail fixtures added. Frozen
    sco_api unchanged. Windows/MSVC, endpoint security and gameplay not verified.

  • G14 content access (#135): audit confirms the private content index and
    command registry lacked a public list/script read route. Add kernel-neutral
    sco.content 1.0 with bounded copied startup records/bytes, link-safe reads,
    whole-pack refusal, dependency propagation, and guarded C++ access. Packs are
    prepared before consumer code loads; code-provider dependencies are explicitly
    refused. Public C example, synthetic module/layout tests, catalogue, packaging
    and provenance added. Frozen sco_api unchanged; no allowlist expansion.
    Not run in game; C#/Lua and product step-2C migration remain downstream.

  • Offline host DataCore timing (G1): initialize/index before early engine
    loading, bounded CryPak transform, preserve LOADED across app Start and drain
    producers before teardown. Synthetic early-load/late-refusal fixture passes;
    Windows transport and legacy builtin migration remain unverified.

  • Offline host quit adapter (G1): required validated CSystem quit hook by
    default, synchronous stop before both engine quit paths, original argument
    passthrough, repeated-stop/task-cancellation fixtures and explicit external
    quit integration. No product fast-shutdown field reads; actual Windows detour
    and game shutdown not verified.

  • Offline host tick adapter (G1): game-thread cadence/wrap handling, first-pass
    tick, fresh admission checks even on throttled passes, shutdown/cancellation on
    lost offline evidence, and no feature fallback after a plugin fault. OS message
    and renderer integration remain in the shell; synthetic fixtures only.

  • Offline host composition, admission/resolve/start (G1): add game-only
    sco_game_host C++ host-source target. Unknown/online/EAC/unblocked-network/wrong
    target evidence refuses before any signature resolution or publication; startup
    revalidates admission, owns row resolution and starts the existing app kit.
    Synthetic lifecycle/thread fixtures only; no online-to-offline conversion,
    plugin patch service or frozen ABI change. Legacy offline mutations and product
    migration remain separate; not run in game.

  • G16 Star Citizen host-source candidate kit: host-source-sc packages the neutral kernel plus complete tracked game implementation, DataCore, private headers, vendored dependencies and synthetic test inputs in a standalone source layout. Existing SPDX SBOM, provenance and checksum generation is retained; an extracted-archive regression builds the G1 host adapter targets with SCO_GAME_SC=ON, runs five synthetic host fixtures and checks core-source game exclusions. All six private adapter files are included. Linux and MSVC SDK CI now run this extracted-kit check, and the release candidate includes this fifth profile. Frozen plugin ABI and human signing/publication gates remain unchanged; gameplay validation is still owed.

  • Legacy wrapper admission: reject incomplete or null callable members in matching C++, C# and Lua routes, and require cleanup callbacks before creating owned cursors, channels, patches or UI registrations. Public fake-provider regressions run against extracted SDK headers; managed game fixtures cover partial and null callbacks. No game execution or frozen ABI change.

  • G2 relocation foundation: size-prefixed game.relocation request/cancel/status and tested owner-scoped streaming completion state machinery. Production mutation remains unavailable until host safety/session admission, system classification and validated transport are grounded; not Windows/game verified.

  • G3 game.spatial 1.0: new size-prefixed native C/raw C++ full-pose conversion
    plus bounded copied zone records, exact observed-name lookup and epoch-pinned
    pages. At most 256 observed IDs/64 records per page; complete rigid ancestry only,
    no global scanner or raw pointers. teleport.spatial 1.0 and sco_api 1.1 stay
    unchanged. Root ancestry is exposed, but system classification remains explicitly
    unknown rather than guessed. C#/Lua unsupported; portable synthetic/ABI fixtures,
    not verified on Windows or in game.

  • G4 (#125) owned prefab spawning: independent game.prefabs 1.0 validates
    canonical content-relative paths and bounded owned quotas, ports the existing
    object-container attribute writer, and records pending prefab ownership in the
    existing entities ledger for move/despawn/retained undo and ordinary unload.
    Owner-approved R1 default removes the hard-disable for game.entities.prefabs;
    canonical 511-byte paths, finite normalized poses, shared 1,024/per-owner 128
    quotas and existing readiness/cleanup/fault refusals are unchanged. C/C++
    routes and synthetic/ABI/catalogue/package evidence only: Windows/MSVC,
    native SEH and streamed spawn/removal behavior are NOT VERIFIED; not run
    in game. Frozen ABI unchanged; no arbitrary delete, content exports or private
    product fallback. G5/G9 behavior is unchanged.

  • G5 (#126): game.world.control 1.0 adds owner-validated bounded filtered
    rays and exclusive reversible free-camera leases, with native C/C++ routes,
    synthetic restoration/ownership/fault fixtures and ABI/catalogue/package pins.
    game.world 1.0 and frozen sco_api remain unchanged. New production
    capabilities are OFF: no verified offline engine adapter, no guessed offsets.
    Ordinary unload/stop restoration is policy-tested; Windows/game not verified.

  • G9 retained-build and owned-seat removal: new game-only game.owned 1.0
    table keeps explicitly retained game.entities placements owned for undo/clear
    while loaded and removes them on ordinary unload; no across-reload persistence.
    Actors-owned NPC and expected-seat-occupant removal are separate authorities;
    foreign/player occupants and arbitrary deletion remain forbidden. Bounded
    owner-scoped receipts report removal initiation only, never alive=0 completion.
    C/C++ direct route, C#/Lua explicitly unsupported; synthetic fixtures only,
    not run in game. Frozen base and existing service layouts remain unchanged.

  • G6 typed offline player loadout (game.loadout 1.0): bounded 16-slot C/C++
    synchronous apply, copied input validation and explicit partial/unsupported/missing
    slot r...

Read more

sco-core SDK 2.0.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 17:04
Immutable release. Only release title and notes can be modified.
cd9a686

The plugin ABI remains 1.1, unchanged. The SDK major version reflects breaking packaging/profile and release-process changes: separate core and game extension archives, an independently buildable core-source kit, and build-once promotion requiring a signed, hash-bound maintainer approval.

The prepared sdk-v1.2.0 was never published; its entries are folded into this release below.

  • Windows extracted-SDK verification: the archive-test job checks out the packaging verifier and its complete manifest inputs, rather than only the shell runner. The verifier reads evaluated MSBuild toolchain include paths so Windows SDK/CRT headers are recognized without relying on the shell's INCLUDE. Builds remain confined to extracted SDK headers, with compiler-resolved checkout leakage refused.

  • Extracted SDK storage and public-header proof: storage resolves host-owned directory aliases before SQLite opens the database, fixing macOS temporary-root failures without permitting database-file symlinks. External C/C++ examples now compile with exact compiler-resolved installed public-header membership checks; hidden checkout and unshipped nested dependencies are refused. Packaging also refuses recognized private-key and GitHub credential shapes before writing an archive. No plugin ABI change.

  • Optional ImGui coupling is host-specific, not the frozen C ABI: document the exact source/configuration match and public-header hashes, drawing-plugin rebuild requirements and absence of cross-version raw-context compatibility; non-drawing plugins do not require ImGui.

  • Native trust and Lua reload limits: native plugins are trusted in-process code, not a sandbox or a native-fault recovery guarantee; supported cached-table, worker and shutdown usage is explicit. Real-loader Lua tests cover repeated reload resource/callback cleanup, transaction rollback, persistent data, preserved budgets and optional read-only game-adapter boundaries. No runtime or ABI change.

  • Real-host SDK conformance: independent native C consumers execute inspector, owned-NPC and actor-death contract fixtures through the neutral loader and host API; negative cases cover service absence/version/partial tails, ownership, wrong-thread raw calls, queued-work cancellation, and restart-required native provider refusal/fault retention. Engine responses are synthetic, not gameplay or native-process recovery certification.

  • SDK discovery acceptance: conventional Copilot/IDE integration docs include an explicit read-only tool allowlist; static language views and real-browser search/keyboard checks cover the reference site, with deterministic cold-Pagefind readiness before shortcut focus checks, and local snapshot tooling binds catalogue/examples to exact source and archive inputs without approval, signing or deployment.

  • Language-route evidence: catalogue mappings require language-specific tests; C/C++ and Lua actor/entity fixtures reject partial/null methods, C# wrappers clear failed-reopen state, and docs distinguish Windows x64 NativeAOT/host evidence from synthetic game-contract tests and unsupported routes. The C ABI is unchanged.

  • Strict neutral source SDK and macOS ARM64 development builds: the core-source archive excludes game ABI headers, layout pins, examples and game-only test fragments, while retaining generic scanner/hook/host coverage. Packaging tests build and run every neutral CTest from an empty extraction and resolve external example includes to exact shipped public headers. VFS snapshots work on C++20 libraries without atomic shared-pointer specialization; ARM64 detours remain explicitly unsupported. The plugin ABI is unchanged.

  • Local SDK discovery: tools/sco-core-mcp/ adds a stdlib, read-only MCP stdio server with six catalogue tools, bounded example reads and source provenance; development aid only, with no SDK execution or game access.

  • Static SDK documentation: a catalogue-backed site with local search builds as a read-only CI artifact for pull requests; trusted main pushes and manual dispatches deploy the validated site to GitHub Pages; project-authored site sources and dependency licence metadata are recorded, and the site is excluded from every SDK package profile.

  • Release promotion refusal coverage: candidate, mandatory-check and draft round-trip logic now lives in testable stdlib tooling; signed negative tests cover the release refusal matrix and reject checkout-local signer policies.

  • Machine-readable SDK contracts: sdk/contracts/ records all 117 table methods and three native entrypoints, with compiler-validated signatures/extents, language evidence and explicit unspecified semantics; tools/sdk_catalogue.py builds a deterministic versioned JSON catalogue, and CI rejects inventory, documentation and support-claim drift.

  • Signed release manifests: tools/release_verify.py binds publication approval to exact payload hashes, source and recursive dependency commits, builder identity and a maintainer SSH signature; negative tests cover tampering and fail-closed refusals.

  • Faulted native providers are restart-required, not recovered. Attributed faults withdraw lookup and host scheduling; handed-out providers retain their state and mapped code without unload or resource release hooks. Logs, plugin reports and reload refusal tell the player to restart the game. Off-thread faults outside a host guard remain uncontained; cached tables and native process integrity are not guaranteed. No plugin ABI change.

  • Service-table unload admission is atomic across lifecycle paths: a single loader gate blocks new queries before teardown, protects built-in provider state, retains backing state after a queried failed load, and reserves the entire dependent reload cascade before any member changes. Command, UI and host API reload routes share this gate; the plugin ABI is unchanged.

  • SDK releases build once and promote verified bytes: a manual candidate workflow packages all four SDK profiles with SBOMs and provenance; tag publication requires a signed, hash-bound approval, downloads exact artifact IDs, and re-verifies a complete draft before making it public.

  • Direct native unload now respects service-table lifetime, matching UnloadOne, app reload and sco.reload: UnloadNative refuses a native whose table was handed out before its unload export or owner release runs. Shutdown still tears it down while keeping its module mapped. The lifetime audit inventories built-in tables, accessors and lifecycle paths, and separates administrative refusal from fault/withdrawal/shutdown behavior. TestServices proves refusal through both public unload routes and retained shutdown pinning; sco_api.h and all table layouts are unchanged.

  • Service contracts and a kernel source SDK. The contract catalogue inventories the 117 public table methods and three plugin entrypoints, with buffer/tail rules, ownership, thread/reentrancy, failures, capability absence and cleanup; unestablished guarantees are explicitly unspecified. sdk/package.py --profile core-source produces an independently buildable kernel source kit, without game implementation, and sdk/test-zip.sh builds it from an empty extraction with SCO_GAME_SC=OFF. The kernel-only CI dependency gate now consumes the generated CMake target graph, compile commands, compiler depfiles and object/link inputs, with negative tests; symbol scans remain supplementary. The frozen 1.1 header is included and hash-checked for offline source builds. No ABI or gameplay behavior change.

  • Discovery refuses a plugin folder whose id belongs to a built-in, and says why (sco_api.h unchanged; plugins). A folder — native, Lua or data pack — whose id is one of the host's built-ins (opts.builtins, filled by sco::app::Start from Platform::builtins) is refused at discovery, before the api and entry checks and before any plugin code runs, with refused: id 'teleport' belongs to a built-in plugin: the log line and the plugin's reason (so status and sco-plugin-check show it) both name the id, instead of the old unclear refused teleport: host passed no api or owner that a data pack never got at all. The conflict is checked before entry 'x' not found, so a folder that may not load never has its entry opened. A disabled folder is not loaded, so it stays disabled and appends the same reason to disabled file. Ids are [a-z0-9_] on both sides, so the match is exact and case needs no folding. requires resolution is unchanged: a built-in still provides by its id. Tests: tests/test_plugins.cpp TestDiscover (native, Lua, data, disabled, missing-entry, a non-conflicting id still ready, the status line and the log) and tests/test_app.cpp TestBuiltinIdConflict (the same through sco::app::Start, with the built-in itself still loaded and working).

  • The plugin ABI 1.1 is frozen, with a golden and an old-binary test (sco_api.h unchanged; no behavior change). tools/abi_snapshot.py compiles a probe against include/sco_api.h and compares its sizeof / _Alignof / offsetof / enum / macro output — the 128-byte sco_api table with every field offset and the function pointer order, every public struct, every result code, both version macros, the reserved padding — with the new tests/abi/sco_api-v1.1.golden, and checks that the header as released at tag sdk-v1.1.0 still hashes to the sha256 the golden records. The pin is the semantic surface, not the bytes: sco_api.h's comments have changed since that release (its licence note), its declarations have not. The tool has no auto-update mode: a difference prints the diff and fails, and a deliberate 1.x addition hand-edits the golden in the same PR — which is what catches a PR that edits tests/abi_v1.c and the header together. The second half is `tests/fixtures/plugi...

Read more

sco-core SDK 1.1.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 23:22
5e3d463

The first SDK release. The plugin ABI is version 1.1 and stable from here on: version 1 only grows at the end of structs, so plugins built with this SDK keep loading in later 1.x hosts.

  • One ABI, five ways to write a plugin: C against sco_api.h, C++20 with scosdk/, C# with Sco.Sdk (published with NativeAOT, no .NET needed by players), sandboxed Lua 5.4, and data packs with no code.
  • Host services, each with its own pinned header: sco.storage (per-plugin key-value and SQL over SQLite, crash-safe), sco.ui (menu tabs, overlays, badges, hotkeys bound to commands), sco.datacore 1.1 (DataCore overrides, new instances and new records, applied at the game's data load or saved for the next launch). Plugins provide services and raw handlers to each other.
  • Data mods that survive game patches: .toml packs address DataCore records and fields by name; sco-dcb lints them and checks them against a game build.
  • Host side for products: the host kit, built-in plugins, crash containment, the detour engine, 64-bit engine math and the zone tree, virtual game files (sco::vfs, sco::game::pak), and the signature tables with sco-sigcheck.
  • SDK zip sco-sdk-1.1.0.zip: headers, template, seven examples (hello, cpp_hello, cs_hello, greeter, notebook, travel_pack, quantum_pack), the CMake helper and sco-plugin-check, each example built and checked from the zip on Linux and Windows in CI.

Every change since the first commit, newest first:

  • teleport.to_camera survives Star Citizen 4.10.196 (the 2026-10-09 patch, StarCitizen.exe 4.10.196.36804): the row failed with "layout changed at +0x17a" because the four camera fields the handler loads at +0x17A..+0x1BD moved by 8 bytes (0x6D3C -> 0x6D44, ...); the code around them was unchanged. Those checks now pin the instructions (vmovss/vmovups/vmovsd from [rax+disp32]) and wildcard the field offset, which nothing reads. sco-sigcheck: 8/8 OK on both 4.10.193.11644 and 4.10.196.36804 (the three dependent teleport.* rows resolve again).
  • C# SDK layer (sdk/csharp/Sco.Sdk, docs; sco_api.h unchanged): a .NET 8 library with no package references over sco_api.h 1.1, sco_storage.h, sco_ui.h and sco_datacore.h: blittable [StructLayout(Sequential)] structs with delegate* unmanaged[Cdecl] function pointers, and wrappers mirroring scosdk/: Plugin with OnLoad / OnUnload, logging, CommandBuilder / Args / Reply, Subscribe handles (one host subscription per event, handlers multiplexed), RunOnGameThread, Invoke / InvokeAsync, Provide / Query / ServiceRef<T>.Covers with the size check, RegisterRaw / InvokeRaw with the size handshake, Storage, DataCore / DataCorePatch and Ui. Callbacks are [UnmanagedCallersOnly] trampolines whose ctx is an id into a registry swept at unload (never a GCHandle); command strings live in a native arena until unload; no exception crosses into native code (logged; SCO_FAILED and <name> failed: <message> for commands). Plugins are published with NativeAOT (PublishAot, NativeLib=Shared) into one self-contained DLL with the three exports. New example sdk/examples/cs_hello (cs_hello.wave <name>, cs_hello.ticks, the cs_hello.greeter service, game.ready and tick). Test Sco.Sdk.Tests: every SIZE / AT / PIN line of tests/abi_*.c checked against the C# structs (and, given the C files, the copy must equal them line for line), plus the wrappers against a stand-in host table (exceptions, multiplexing, tasks, the raw handshake, a late call after unload). The SDK zip ships csharp/, cs_hello and docs/sdk-csharp.md; sdk/test-zip.sh with SCO_SDK_CSHARP=1 runs the test and publishes and checks cs_hello (the sdk workflow: linux-x64 and win-x64), and the new job csharp-host-sim loads cs_hello through sco-host-sim on Windows. sc-offline needs no change.
  • New records in data packs and sco.datacore 1.1 (design decision 3, "AddRecord in v1"; sco_api.h unchanged). The pack format gains [[record]] (struct, name, clone = a record of the same struct; optional id shared with [[instance]] ids, guid, file, set), run through Patch::AddRecord with R1's rules; later operations name the new record by name, GUID or "@id" (its root). Without guid the GUID is derived from the plugin id and the record name (PackRecordGuid), so it is the same at every launch; without file the path is libs/foundry/records/sco/<plugin id>/<name>.xml. lint checks the required keys, a clone that is a record (no field), the file path rule, and a name or GUID added twice by one file; the rest is refused at the load like the patcher's other rules. The service's add_record now queues a [[record]] (before the load it applies at it; after it, it is saved in pending/<plugin id>.toml and applies from the next launch) and returns an id usable like an added instance's. The table and its layout are unchanged; the version becomes 1.1 (SCO_DATACORE_VERSION_1_1) so a caller that needs records can query for it and a 1.0 host (which answers add_record with SCO_UNAVAILABLE) is told at the query. scosdk/datacore.hpp: AddRecord(type, name, cloneRecord, guid, filePath) returns a DataCoreInstance (was a sco_result), plus DataCore::AddRecordSupported(). sco-lua: p:add_record(type, name, clone_record [, guid [, file]]) returns the record's root as an instance. sco-dcb diff turns a record only in b into a [[record]] cloned from the closest record of a of the same struct, then sets what differs (new records first). Tests: golden fixtures (good_record.toml and the refusals: no struct, no clone, clone with a field, name or GUID added twice, zero GUID, file path prefix and extension, an id shared with an instance), test_datacore_pack (applied values, default GUID and path, every load-time refusal, two packs adding one name, atomic = false), test_datacore_service (add_record before the load through scosdk; after it saved and applied at the next simulated launch with its derived GUID), test_lua, tests/dcb_pack.cmake (lint, check, show and a diff round trip of tests/fixtures/datacore/new_record), abi_datacore (the 1.1 constant). For sc-offline: nothing to change; plugins that add records need a host with sco.datacore 1.1.
  • sco-lua: sco.store, storage for Lua plugins over the host service sco.storage 1.0 (sco_api.h and sco_storage.h unchanged; Lua reference). get (a string, or nil when there is no such key), put, delete (true / false), keys(prefix, after, limit) (a list, at most 1000 per call, paged with after), begin / commit / rollback, exec(sql, params) (rows changed) and sql(sql, params) (rows as { column = value } tables, at most 1000, more is too_many) or sql(sql, params, fn) (fn(row) per row until it returns false). Parameters: integers, numbers, strings, booleans, nil with n. Errors are nil, err, message (the service's last_error); a host without the service (an older one, or no data folder) keeps sco.store and answers nil, "unavailable"; sco.store.available() tells. Each call and each row or key read counts 100 steps against the step budget; sql holds its cursor in a to-be-closed slot, so it is closed on return and when an error unwinds through it (a script error in fn, the budget running out, no memory). Nothing names a file. lua-check.lua gains an in-memory sco.store (no SQL); the SDK gains the example examples/notebook (notes in a transaction), checked by lua-check and installed in sdk/test-zip.sh. Tests: test_lua (round trip, two scripts isolated, SQL with parameters and types, the row cap, an error mid-iteration 70 times with no cursor left open, the budget running out inside a row function, a reload keeping committed data, no service and a sco_api 1.0 host, the notebook example). For sc-offline: Lua plugins get storage once pf.dataRoot is set.
  • The sco.datacore service 1.0 (include/sco_datacore.h, plain C, ids never pointers, pinned by tests/abi_datacore.c; host side sco/datacore_service.h, library sco_datacore_service; sco_api.h unchanged), plan PR 6 of the DataCore design (docs). A host-owned service, published only when the product sets sco::app::Platform::dataCore (off by default; sc-offline turns it on in design plan PR 8). state (SCO_DC_OPEN / SCO_DC_LOADED), begin, set, add_instance, set_pointer, append, add_record (answers SCO_UNAVAILABLE: saved patches use the pack format, which has no record operation yet), values including SCO_DC_REF for reference fields, commit, discard, report. Before the DataCore load a committed patch is queued for it; after it (decision 9) commit saves the patch as <dataRoot>/datacore/pending/<plugin id>.toml (temporary file plus rename) and reports SCO_DC_QUEUED "applies at the next launch"; the next load applies it right after the plugin's own data pack, and skips (and logs) the saved patch of a plugin no longer installed or enabled. service::Load applies data packs, saved patches and queued patches in plugin order with per-patch atomicity (SCO_DC_NON_ATOMIC), fills each patch's report and posts the event datacore.applied (sco_dc_applied). sco-lua gains sco.datacore (begin, state; patch methods set, add_instance, set_pointer, append, add_record, commit, discard, report) when the host publishes it; scosdk/datacore.hpp (DataCore, DataCorePatch, DataCoreInstance); the SDK zip ships sco_datacore.h. Pack reasons for operations without a line (patches built in code) name the operation number. Tests: tests/test_datacore_service.cpp (a simulated launch sequence: load, commit after it, the next launch applying t...
Read more