Skip to content

Commit 2b97657

Browse files
committed
Implement basic support for FEPM (ISX-1842)
- Rework InputSystem's Init functions to handle optional domain reloads - Bypass InitializeInPlayer() "Reset" and "Restore" functions if DRs disabled Only the first step to getting this working, but enables FEPM support for golden path scenarios.
1 parent cfd6eec commit 2b97657

File tree

2 files changed

+56
-27
lines changed

2 files changed

+56
-27
lines changed

Packages/com.unity.inputsystem/InputSystem/InputSystem.cs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,19 @@ namespace UnityEngine.InputSystem
8080
#if UNITY_EDITOR
8181
[InitializeOnLoad]
8282
#endif
83-
8483
public static partial class InputSystem
8584
{
85+
static InputSystem()
86+
{
87+
GlobalInitialize(true);
88+
}
89+
90+
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
91+
private static void RuntimeInitialize()
92+
{
93+
GlobalInitialize(false);
94+
}
95+
8696
#region Layouts
8797

8898
/// <summary>
@@ -3102,7 +3112,7 @@ public static InputActionAsset actions
31023112
return;
31033113

31043114
var valueIsNotNull = value != null;
3105-
#if UNITY_EDITOR
3115+
#if UNITY_EDITOR
31063116
// Do not allow assigning non-persistent assets (pure in-memory objects)
31073117
if (valueIsNotNull && !EditorUtility.IsPersistent(value))
31083118
throw new ArgumentException($"Assigning a non-persistent {nameof(InputActionAsset)} to this property is not allowed. The assigned asset need to be persisted on disc inside the /Assets folder.");
@@ -3117,7 +3127,7 @@ public static InputActionAsset actions
31173127

31183128
// Note that we do not enable/disable any actions until play-mode
31193129
}
3120-
}
3130+
}
31213131

31223132
/// <summary>
31233133
/// Event that is triggered if the instance assigned to property <see cref="actions"/> changes.
@@ -3129,7 +3139,7 @@ public static InputActionAsset actions
31293139
/// <seealso cref="actions"/>
31303140
/// <seealso cref="InputActionAsset"/>
31313141
public static event Action onActionsChange
3132-
{
3142+
{
31333143
add => s_Manager.onActionsChange += value;
31343144
remove => s_Manager.onActionsChange -= value;
31353145
}
@@ -3487,30 +3497,42 @@ private static bool ShouldEnableRemoting()
34873497

34883498
// The rest here is internal stuff to manage singletons, survive domain reloads,
34893499
// and to support the reset ability for tests.
3490-
static InputSystem()
3500+
3501+
private static bool IsDomainReloadDisabledForPlayMode()
34913502
{
3492-
#if UNITY_EDITOR
3493-
InitializeInEditor();
3494-
#else
3495-
InitializeInPlayer();
3503+
#if UNITY_EDITOR && !ENABLE_CORECLR
3504+
if (!EditorSettings.enterPlayModeOptionsEnabled || (EditorSettings.enterPlayModeOptions & EnterPlayModeOptions.DisableDomainReload) == 0)
3505+
return false;
34963506
#endif
3507+
return true;
34973508
}
34983509

3499-
////FIXME: Unity is not calling this method if it's inside an #if block that is not
3500-
//// visible to the editor; that shouldn't be the case
3501-
[RuntimeInitializeOnLoadMethod(loadType: RuntimeInitializeLoadType.SubsystemRegistration)]
3502-
private static void RunInitializeInPlayer()
3510+
private static void GlobalInitialize(bool calledFromCtor)
3511+
{
3512+
// This method is called twice: once from the static ctor and again from RuntimeInitialize().
3513+
// We handle the calls differently for the Editor and Player.
3514+
3515+
#if UNITY_EDITOR
3516+
// If Domain Reloads are enabled, InputSystem is initialized via the ctor and we can ignore
3517+
// the second call from "Runtime", otherwise (DRs are disabled) the ctor isn't fired, so we
3518+
// must initialize via the Runtime call.
3519+
3520+
if (calledFromCtor || IsDomainReloadDisabledForPlayMode())
35033521
{
3504-
// We're using this method just to make sure the class constructor is called
3505-
// so we don't need any code in here. When the engine calls this method, the
3506-
// class constructor will be run if it hasn't been run already.
3522+
InitializeInEditor(calledFromCtor);
3523+
}
3524+
#else
3525+
// In the Player, simply initialize InputSystem from the ctor and then execute the initial update
3526+
// from the second call. This saves us from needing another RuntimeInitializeOnLoad attribute.
35073527

3508-
// IL2CPP has a bug that causes the class constructor to not be run when
3509-
// the RuntimeInitializeOnLoadMethod is invoked. So we need an explicit check
3510-
// here until that is fixed (case 1014293).
3511-
#if !UNITY_EDITOR
3512-
if (s_Manager == null)
3528+
if (calledFromCtor)
3529+
{
35133530
InitializeInPlayer();
3531+
}
3532+
else
3533+
{
3534+
RunInitialUpdate();
3535+
}
35143536
#endif
35153537
}
35163538

@@ -3524,18 +3546,24 @@ internal static void EnsureInitialized()
35243546
#if UNITY_EDITOR
35253547
internal static InputSystemObject s_SystemObject;
35263548

3527-
internal static void InitializeInEditor(IInputRuntime runtime = null)
3549+
internal static void InitializeInEditor(bool calledFromCtor, IInputRuntime runtime = null)
35283550
{
35293551
Profiler.BeginSample("InputSystem.InitializeInEditor");
35303552

3553+
// This is only necessary after a Domain Reload but otherwise can be skipped.
3554+
bool globalReset = calledFromCtor || !IsDomainReloadDisabledForPlayMode();
3555+
3556+
if (globalReset)
35313557
Reset(runtime: runtime);
35323558

35333559
var existingSystemObjects = Resources.FindObjectsOfTypeAll<InputSystemObject>();
35343560
if (existingSystemObjects != null && existingSystemObjects.Length > 0)
35353561
{
3562+
if (globalReset)
3563+
{
35363564
////FIXME: does not preserve action map state
35373565

3538-
// We're coming back out of a domain reload. We're restoring part of the
3566+
// If we're coming back out of a domain reload. We're restoring part of the
35393567
// InputManager state here but we're still waiting from layout registrations
35403568
// that happen during domain initialization.
35413569

@@ -3559,6 +3587,7 @@ internal static void InitializeInEditor(IInputRuntime runtime = null)
35593587
// Get rid of saved state.
35603588
s_SystemObject.systemState = new State();
35613589
}
3590+
}
35623591
else
35633592
{
35643593
s_SystemObject = ScriptableObject.CreateInstance<InputSystemObject>();
@@ -3761,7 +3790,6 @@ private static void InitializeInPlayer(IInputRuntime runtime = null, InputSettin
37613790

37623791
#endif // UNITY_EDITOR
37633792

3764-
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
37653793
private static void RunInitialUpdate()
37663794
{
37673795
// Request an initial Update so that user methods such as Start and Awake
@@ -3898,9 +3926,9 @@ private static void Reset(bool enableRemoting = false, IInputRuntime runtime = n
38983926

38993927
// This is the point where we initialise project-wide actions for the Editor, Editor Tests and Player Tests.
39003928
// Note this is too early for editor ! actions is not setup yet.
3901-
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
3929+
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
39023930
EnableActions();
3903-
#endif
3931+
#endif
39043932

39053933
Profiler.EndSample();
39063934
}

Packages/com.unity.inputsystem/Tests/TestFixture/InputTestFixture.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,10 +905,11 @@ internal void SimulateDomainReload()
905905
// This quite invasively goes into InputSystem internals. Unfortunately, we
906906
// have no proper way of simulating domain reloads ATM. So we directly call various
907907
// internal methods here in a sequence similar to what we'd get during a domain reload.
908+
// Since we're faking it, pass 'true' for calledFromCtor param.
908909

909910
InputSystem.s_SystemObject.OnBeforeSerialize();
910911
InputSystem.s_SystemObject = null;
911-
InputSystem.InitializeInEditor(runtime);
912+
InputSystem.InitializeInEditor(true, runtime);
912913
}
913914

914915
#endif

0 commit comments

Comments
 (0)