scs-sdk 0.1.1

Typed Rust wrapper for the SCS Software Telemetry and Input SDKs
Documentation
  • Coverage
  • 76.33%
    374 out of 490 items documented5 out of 63 items with examples
  • Size
  • Source code size: 305.96 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 6.11 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 3s Average build duration of successful builds.
  • all releases: 5s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • AptS-1547/scs-sdk-crates
    2 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • AptS-1547

scs-sdk

中文 | English

scs-sdk is the safe, typed, no_std interpretation of scs-sdk-sys for the public telemetry and input interfaces in SCS SDK 1.14 interface. It turns the header-shaped ABI into typed Rust values, descriptors, catalogs, version domains, and callback-scoped SDK operations without taking ownership of plugin lifecycle or product state.

Telemetry and Input version domains and call capabilities remain independent.

This is an independent community crate and is not affiliated with or endorsed by SCS Software.

Layer responsibility

This layer owns:

  • audited decoding from raw SCS values into typed Rust representations;
  • strongly typed Telemetry API and per-game telemetry schema versions;
  • channel, configuration, gameplay, event, and attribute descriptors;
  • borrowed callback views whose lifetime cannot exceed the callback data;
  • scoped registration, unregistration, and logging calls back into SCS; and
  • input-device declarations, input indices/values/flags, init-only device registration, and callback-scoped input logging; and
  • complete enumerable catalogs with official capability history.

It deliberately does not own exported loader symbols, process-global runtime state, callback-context allocation, registration transactions, panic containment, or a product's telemetry state. Those mechanisms belong in scs-sdk-plugin or the application.

The crate remains no_std and does not add std or alloc merely for owned strings or collections. A higher layer copies foreign data when it must outlive the direct callback scope.

API and version model

TelemetryApi is the single audited entry point for adapting SCS initialization structures. Its exact supported list is:

TelemetryApiVersion::V1_00
TelemetryApiVersion::V1_01

Unknown raw versions remain representable for diagnostics, but are not silently reinterpreted as the newest known layout. TelemetryApiVersion describes the plugin ABI negotiated with the loader; GameSchemaVersion describes one game’s telemetry descriptor schema. They are separate strong types and must not be confused with an SDK archive suffix or a public game patch version.

InputApi separately accepts only InputApiVersion::V1_00. InputGameVersion is distinct from both telemetry version types. InputInitCall alone can register a device, while InputCall and InputSession keep later callbacks and shutdown scoped to direct SCS calls.

Key scoped types include:

  • TelemetryApi<'a>: validated initialization data and the selected ABI adapter;
  • TelemetrySession: callback registration and logging functions captured from the validated API;
  • SdkCall<'scope>: a non-escaping call capability available only while SCS is directly invoking the plugin on the game main thread; and
  • ScopedLogger<'scope>: bounded temporary C-string construction for one permitted SDK call scope.

SdkCall is deliberately non-storable, non-Send, and non-Sync. The safe API does not suggest that SDK calls may be retained or moved to a worker thread. Every official non-success result maps to a distinct SdkError variant instead of losing information in a generic failure.

Typed values and callback views

ValueRef<'a> checks the raw SCS value tag before reading the corresponding C union member. Unknown or mismatched tags produce None; inactive union members are never inspected. Borrowed strings and named values remain tied to the foreign callback lifetime.

Rust-owned geometry types—FVector, DVector, Euler, FPlacement, and DPlacement—copy only meaningful fields. They do not copy ABI padding which SCS is not required to initialize.

InputAxisValue models the normalized float domain used by game input axes. Its constructor preserves every finite value from -1.0 through 1.0, including negative zero, and rejects NaN, infinities, and finite out-of-range values. InputValue::Float carries this strong type rather than an arbitrary f32, so safe application code cannot send a value which the game interprets as an invalid neutral input.

NamedValues<'a> implements the SDK sentinel iteration contract for configuration and gameplay payloads. It terminates at the foreign sentinel and validates every entry independently rather than scanning arbitrary memory.

Descriptors, catalogs, and indices

Typed descriptors preserve the expected value representation:

use scs_sdk::{Attribute, Channel};

Channel<T> and Attribute<T> are used for decoding and registration, while AnyChannel and AnyAttribute retain names, value types, indexing metadata, and availability for enumeration and diagnostics.

Three index domains remain deliberately distinct:

Type Meaning
SdkIndex Explicit SCS array slot attached to an indexed value.
TrailerIndex Numbered trailer namespace such as trailer.0.
TrailerConfigurationId Callback identity distinguishing legacy trailer from numbered trailer configurations.

Application APIs should not replace these domains with an ambiguous bare integer.

The complete typed telemetry inventory is:

Surface Count
Channels 107
Configuration IDs 6
Configuration attributes 60
Configuration-to-attribute associations 71
Gameplay events 6
Gameplay attributes 15
Gameplay-to-attribute associations 21

Documented enum-like strings also have closed known-value catalogs:

Catalog Known values
configuration::ShifterType 4
configuration::JobMarket 5
gameplay::FineOffence 14

Each closed catalog exposes ALL, COUNT, as_str, FromStr, and per-value schema availability. A failed known-value parse does not destroy the original text: generic string access remains available so future additive SDK values can still be logged and preserved.

Capability history

Every built-in channel, configuration descriptor, gameplay descriptor, and association carries GameSchemaAvailability with independently researched ETS2 and ATS minima. These values come from official historical SDK headers and their changelog comments—not from the SDK archive number or Telemetry API.

Representation-level and event-level API history stays separate. For example, signed 64-bit values and gameplay events require Telemetry API 1.01, while individual descriptors may also require a later game schema.

The plugin framework combines this metadata with detected GameInfo before it asks SCS to register a capability.

Raw escape hatch

The underlying ABI crate is deliberately available as:

pub use scs_sdk_sys as sys;

This exists for wrapper and runtime work, not as the normal application path. Ordinary product plugins should use the safe descriptors and the scs-sdk-plugin::sdk re-export instead of importing sys types.

Validation

Run from the repository root:

cargo fmt --all -- --check
cargo test --locked -p scs-sdk
cargo clippy --locked -p scs-sdk --all-targets -- -D warnings
RUSTDOCFLAGS=-Dwarnings cargo doc --locked -p scs-sdk --no-deps
cargo +nightly-2026-04-12 miri test --locked -p scs-sdk

Public API, descriptor, registration, version, or value changes must also prove that the framework still exposes the wrapper without leaking raw details:

cargo test --locked -p scs-sdk-plugin
scripts/check-plugin-boundary.sh

License

Workspace-authored Rust code is available under either Apache License 2.0 or MIT, at your option.

Typed descriptors, constants, identifiers, catalogs, schema-history metadata, and related documentation derived from SDK 1.0 through 1.14 retain both original SCS Software notices: LICENSE-SCS-SDK-2013 for SDK 1.0-1.5 and LICENSE-SCS-SDK-2016 for SDK 1.6-1.14. The official SDK archive remains third-party material and is not relicensed under the workspace license.