Native client settings layers
| Layer | Owner and lifetime | Important boundary |
|---|---|---|
| Account preferences | Per-login userPrefs plus a separate memory-only
session map. | A change event does not prove a disk flush. |
| Integer settings cache | Server-backed symbolic sections mapped to numeric keys. | Sync completion is a request boundary; check isSynced(). |
| Packed server sections | Logical fields packed into shared integer bit ranges. | Pass validated field values through the manager; it is not a range validator, and staging is not acknowledgement. |
| Options and transient stores | Runtime preview, staged apply, confirmation, revert, and domain-specific commit. | Preview, save, confirmation, rejection, and clearing are separate transaction stages. |
The packed-settings manager clears a
field's declared mask, then ORs int(value) << offset into the stored integer.
It does not mask that incoming value to the field width or clamp it to the option's range.
Preserving neighboring fields therefore requires valid field-domain input; integer conversion
alone is not validation.
The concrete PostMortemModeSetting
option offers four choices for its two-bit field. In a direct packing control, supplying
four instead of zero through three set the neighboring bit while the target field decoded as
zero. A one-bit field likewise does not coerce arbitrary integers to Boolean values. Validate
direct mod inputs against the concrete option's supported choices before staging them.
These source and adapted-method controls cover low-bit packing with inert cache/dictionary helpers. They do not show that stock UI submits invalid values or that real client/server settings were changed; integer-sign branches, installed bytecode and native application were not exercised.
Choose a layer from required ownership and lifetime, not API convenience. The native player preference manager is also distinct from realm and feature configuration exposed by lobby context.
Keyboard option defaults and setters use different key values
KeyboardSetting exposes Scaleform values through its ordinary getter, packed controls and packed default. Its getDefaultValue and the keyboard container's current/default mapping dictionaries instead return raw engine keys. Convert a raw default before passing it as UI input. In the normal mapping, setSystemValue(None) installs KEY_NONE, while numeric Scaleform zero selects the left mouse button. The plain-key lookup can also fall back to a default when a command has only a chord; it does not enumerate every binding.
The individual setter changes Python mapping state. The keyboard container then applies children, fires onMappingChanged(values), and calls CommandMapping.save to persist eligible bindings and submit the mapping to native input. The event itself does not publish that mapping. A listener exception can interrupt the container before save, after Python state changed. A completed outer settings pass therefore does not prove every keyboard change was published or persisted. These source rules do not establish hardware behavior or restart restoration.
Settings readiness and transactions
Core construction and onSettingsReady do not prove server-cache readiness. Account
GUI and avatar transitions later run the ordered cache refresh and runtime apply. Replay mode can
suppress server mutation, and disconnect rolls back previews before services clear.
- Do not overlap integer-cache refreshes without a higher-level serializer.
- Keep preview and commit ownership together, including rejection, revert, transient-store clearing, and disconnect cleanup.
- Bulk option application catches failures per setting and can partially succeed.
- Recheck numeric mappings, packed fields, option composition, and decompiled inconsistencies for every target client build.
Settings overrides use one shared baseline
SettingsCore.setOverrideSettings captures one service-wide baseline. A second override logs and returns while that slot is occupied, including when the stored baseline is empty. The API supplies no owner token or nested stack. Restoration reapplies the captured values, so intervening live changes can be overwritten. Do not treat this service as independent temporary overrides for unrelated owners.
The selected storage gates filter normal applyStorages and clearStorages; they do not block ordinary live option application, and forced storage application bypasses the apply gate. Once the baseline is captured, a storage lookup or apply exception can leave the slot occupied. Unset clears storage gates before restoring values and releases the baseline only after restoration returns. Those paths are not an atomic restore or a persistence acknowledgement.
Coordinate one owner and an explicit restoration boundary when using this internal API. The inspected base policy controller demonstrates a consumer path, not evidence that concrete stock policies overlap. These are source and recording-fixture contracts; no preferences, graphics, active policies or client runtime were exercised.
Optional settings-menu integration
A settings menu is a presentation and persistence adapter, not the owner of runtime truth.
Keep safe defaults and a local fallback so the mod still loads when the optional menu package
is absent. Current client source exposes both gui.aslainMenu and the compatible
gui.modsSettingsApi name, but their reported versions and optional methods differ;
inspect the package shipped with the target client.
- Use one stable, globally unique linkage and one stable
varNamefor each persisted control. - Ask for compatible saved settings first. If none exist, register the template, then sanitize the values returned by registration.
- Reject callbacks for another linkage and validate every stored, committed, live, or programmatically supplied value.
- Treat dropdown values as presentation indexes. Convert them to stable semantic values before using them in another data contract.
- Use the menu's committed callback for durable changes. Live-change callbacks are provisional and should drive only reversible previews until Apply or OK commits them.
Release metadata is separate from settings migration
Supply modAuthor and modVersion in templates that support them, including
alternative layouts. Use the module's __version__ value without adding a prefix.
These presentation fields do not reset settings; do not raise settingsVersion
merely for an author or release-version change.
Feature-detect newer helpers and handle a rejected new keyword narrowly. The existence of a function does not prove that its current signature accepts a recently added keyword. Retain exact callback identities for any registration that supports explicit unregistration, and do not create a second Mods List entry merely to expose settings for a feature that owns no separate window.