logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class PlayerInputCreator

    Generates (or updates) the PlayerInput aggregate's asset chain: a UnityPlayerInputSettingsDefinition and, in Multiplayer, the three settings assets it can reference — Serenity.InputGateway.Infrastructure.Settings.UnityPlayerInputRoutingSettings, Serenity.InputGateway.Infrastructure.Settings.UnityPlayerInputJoinGateSettings, and Serenity.InputGateway.Infrastructure.Settings.UnityPlayerInputDeviceFilterSettings. This is the most complex creator in the project (four inter-referencing assets); a dedicated wizard window over this engine ships separately.

    Resolution is by-Id-in-folder for all four types, mirroring Serenity.GameMode.Installation.Editor.Builder.GameModeSettingsCreator: nothing at runtime resolves any of these four assets by Id — UnitySerenityInstaller assigns the UnityPlayerInputSettingsDefinition directly on the composition root, and the Definition in turn either carries a direct routing reference or the installer falls back to an Addressables-label lookup (see below) — so more than one instance of any of the four types can legitimately exist per project (e.g. per build configuration), exactly like Logging's profiles.

    The routing fallback is NOT null-tolerant end to end — verified by reading both call sites. UnityPlayerInputInstaller.InstallInputRoutingSettingsFromDefinition uses the Definition's own routing field when assigned; otherwise it calls UnityAssetUtils.LoadAllFromAnyBlocking<UnityPlayerInputRoutingSettings> over the PLAYER_INPUT label and takes the first match. If THAT also finds nothing, the resolved routing stays null, and Install() unconditionally calls InstallUiInputRouter → UnityPlayerInputUiInputRouterFactory.Create → UiInputRouterFactoryInput.EnsureValid(), which throws ArgumentNullException when RoutingSettings is null — a hard boot crash, not a graceful degrade. This is why every asset this creator produces is retagged with PLAYER_INPUT (not just for inventory consistency, unlike GameMode's settings — here the label is load-bearing for the fallback), and why SinglePlayer — which deliberately leaves the Definition's routing reference untouched — validates (warns, never blocks) whether a labeled Serenity.InputGateway.Infrastructure.Settings.UnityPlayerInputRoutingSettings already exists anywhere the fallback could find it. By contrast, InstallJoinBehavior and UnityPrimaryInputGate.IsDeviceAllowedForPrimary both null-check routing and degrade gracefully (join disabled, any device allowed as primary) — only the UI router path is a hard crash.

    Player Prefab is authored as a UnityEngine.GameObject, not the strongly-typed UnityEngine.InputSystem.PlayerInput field the Definition actually stores. A designer drags a prefab asset; this engine resolves its UnityEngine.InputSystem.PlayerInput component (mirroring UnityPlayerInputInstaller.InstallJoinBehavior's own GetComponent<PlayerInput>() check) and warns — never blocks, matching the installer's own severity — when the prefab has none.

    onPrimaryJoinTask is a plain reference, not authored. It is a UnityReflectionCallTaskDefinition — a generic reflection-call task asset with its own authoring surface entirely out of scope here; this engine only assigns whatever reference is handed to it (or preserves the existing one on update), the same way it treats InputAsset.

    A wizard window collecting input and rendering results ships in a separate change; every asset mutation lives here.

    Inheritance
    object
    PlayerInputCreator
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    Namespace: Serenity.InputGateway.Installation.Editor.Builder
    Assembly: Serenity.UnityPlayerInput.Installation.Editor.dll
    Syntax
    public static class PlayerInputCreator

    Fields

    DefaultOutputFolder

    Folder a brand-new asset chain is created under when the caller names none.

    Declaration
    public const string DefaultOutputFolder = "Assets/Game/Media/PlayerInput"
    Field Value
    Type Description
    string

    Methods

    Create(Input)

    Validates the request, resolves whichever assets already exist by Id to seed a scratch draft from each — so a field this run does not touch survives exactly as the real asset already had it, not a blank template default — applies the flat DTO's fields onto those drafts, then commits them through CreateFromDrafts(UnityPlayerInputSettingsDefinition, UnityPlayerInputRoutingSettings, UnityPlayerInputJoinGateSettings, UnityPlayerInputDeviceFilterSettings, CreationMode, string, string, string, string, string, bool), the single write path shared with CreatePlayerInputWindow's own long-lived per-asset drafts. Kept for headless/test/recipe callers that only have this flat PlayerInputCreator.Input shape — the window itself seeds and edits its own drafts directly and calls CreateFromDrafts(UnityPlayerInputSettingsDefinition, UnityPlayerInputRoutingSettings, UnityPlayerInputJoinGateSettings, UnityPlayerInputDeviceFilterSettings, CreationMode, string, string, string, string, string, bool) without ever going through this DTO.

    Declaration
    public static PlayerInputCreator.Result Create(PlayerInputCreator.Input input)
    Parameters
    Type Name Description
    PlayerInputCreator.Input input
    Returns
    Type Description
    PlayerInputCreator.Result

    CreateFromDrafts(UnityPlayerInputSettingsDefinition, UnityPlayerInputRoutingSettings, UnityPlayerInputJoinGateSettings, UnityPlayerInputDeviceFilterSettings, CreationMode, string, string, string, string, string, bool)

    The single write path: in Multiplayer, resolves-or-creates the Device Filter and Join Gate bottom-up, then Routing (wiring both onto routingDraft before committing it), then always resolves-or-creates the Definition (wiring Routing onto definitionDraft only in Multiplayer mode) — each commit going through ResolveAndCommit<TSettings>(TSettings, string, string, string, SerenityAssetCreationTransaction), so serialization decides what gets written onto each real asset, not a hand-maintained field list. On any failure every mutation across every touched asset is rolled back: created assets/folders are deleted, their Addressables entries removed, and any already-existing asset that was being edited has its pre-call field values restored. The four CALLER-OWNED draft parameters are protected the same way: each is captured via Serenity.Global.Infrastructure.Editor.SerenityExistingAssetRestore before this method writes an Id trim or a cross-reference onto it, and restored to that captured state on failure — so a caller's long-lived draft (the wizard window's own bound scratch instance) never keeps a reference to an asset the rollback just deleted.

    Declaration
    public static PlayerInputCreator.Result CreateFromDrafts(UnityPlayerInputSettingsDefinition definitionDraft, UnityPlayerInputRoutingSettings routingDraft, UnityPlayerInputJoinGateSettings joinGateDraft, UnityPlayerInputDeviceFilterSettings deviceFilterDraft, PlayerInputCreator.CreationMode mode, string outputFolderPath, string definitionId, string routingId, string joinGateId, string deviceFilterId, bool registerAsAddressables)
    Parameters
    Type Name Description
    UnityPlayerInputSettingsDefinition definitionDraft

    Every field to write onto the Definition. Required.

    UnityPlayerInputRoutingSettings routingDraft

    Every field to write onto Routing — required in Multiplayer mode, ignored in SinglePlayer mode (the Definition's own routing reference is left exactly as the draft already carries it in that mode).

    UnityPlayerInputJoinGateSettings joinGateDraft

    Every field to write onto the Join Gate — Multiplayer mode only.

    UnityPlayerInputDeviceFilterSettings deviceFilterDraft

    Every field to write onto the Device Filter — Multiplayer mode only.

    PlayerInputCreator.CreationMode mode
    string outputFolderPath
    string definitionId
    string routingId
    string joinGateId
    string deviceFilterId
    bool registerAsAddressables
    Returns
    Type Description
    PlayerInputCreator.Result

    Validate(Input)

    Validates the request: a non-empty Id, a well-formed output folder, every timing throw UnityPlayerInputInstaller.ValidateSettings would raise, a required Input Asset (the installer throws when it is null), the UI Action Map name resolving against it (an error), the Navigate/Submit/Cancel action names resolving within that map (warnings), the Player Prefab carrying a UnityEngine.InputSystem.PlayerInput component when assigned (a warning, mirroring the installer's own severity), and the same resolve-or-edit duplicate-Id/unlink warnings Create(Input) would act on — including, in SinglePlayer, whether the installer's Routing label fallback has anything to find at all. The full rule set lives in Serenity.InputGateway.Installation.Editor.Builder.PlayerInputCreatorValidator, extracted under the file-size ratchet — this stays the one public entry point every caller uses.

    Declaration
    public static SerenityCreationValidationResult Validate(PlayerInputCreator.Input input)
    Parameters
    Type Name Description
    PlayerInputCreator.Input input
    Returns
    Type Description
    SerenityCreationValidationResult
    In this article
    © 2026 Serenity. All Rights Reserved